clickhouse 优化实践,万级别QPS数据毫秒写入和亿级别数据秒级返回 | 京东云技术团队
1、背景
魔笛活动平台目前在采集每个活动的用户行为数据并进行查询,解决线上问题定位慢,响应不及时的问题,提升客诉的解决效率。目前每天采集的数据量5000万+,一个月的数据总量15亿+,总数据量40亿+,随着接入的活动越来越多,采集上报的数据量也会越来越大。目前采用ClickHouse来存储数据,可以在秒级别内处理数十亿条数据,能够达到50MB-200MB/s的写入吞吐能力,按照每行100Byte估算,大约相当于50W-200W条/s的写入速度。这里关于ClickHouse就不再赘述,感兴趣的可以看上篇文章。这里是我在实际使用过程中,发现了一些写入和查询的相关问题,并进行了相应的优化。
2、写入优化
2.1 历史方案
为了更好的收集活动数据,自己开发了一款埋点sdk用于收集各业务的活动埋点数据,埋点数据统一异步发送MQ,然后活动平台消费MQ数据,经过一定处理后通过MybatisPlus方式批量写入clickhouse,每次批量写入5000条。

2.2 出现的问题
当消费MQ的TPS超过3000的时候,出现了以下问题:
1. 出现报错:写入量大的时候会报这个错误:too many parts。

2. 单次写入条数少:我明明配置的每次批量写入5000条,但是每次基本都是一条一条写入。

3. 性能很差:单次写入最大耗时居然有250000毫秒,平均也超过50000毫秒!

2.3 出现问题的原因
(1)单次写入条数少原因:MybatisPlus的savebatch单次最大写入SQL是4M,按照单条活动的数据大小,最大单次也就写1000条数据,再多就会一次一次写入。所以虽然配置的是每次写入5000,但是实际看是每次写入一条或者几条。
(2)too many parts错误:clickhouse操作数据的最小操作单元是block,每次写入都会按照zookeeper记录的唯一自增的blockId,按照PartitionId_blockId_blockId_0生成data parts,也就是小文件,然后后台会有merge线程,不定时(分钟级别)的将多个小文件进行合并,生成PartitionId_MinBlockNum_MaxBlockBum_Level的文件,未达到data parts最小rows或者大小限制前,会持续merge,每次merge的耗时大概5分钟左右。由于merge线程池是固定的,默认32,所以如果插入过于频繁,merge压力过大,处理不了,就会出现too many parts的报错。例如并发数为 200,这样一批写入到 ClickHouse 中就会产生 200 个文件,几批下来如果 ClickHouse 内部线程没来及合并相同分区,就会抛异常。而 ClickHouse 默认一次合并超过 300 个文件就会报错。
(3)性能差的原因:因为写clickhouse底层都是使用httpclient的方式写入的,所以对于clickhouse来说单条频繁写入效率很低。

2.4 改造方案
(1)写入clickhouse的并发数调小,批处理的数据size间隔调大,比如之前200并发调整到50并发,从之前一批1条数据调整到10000条数据,clickhouse官网建议每批次写入100000+条(要视flink TM 内存大小调整,防止批量过大出现oom)。从而减少clickhouse文件的个数,避免超过parts_to_throw_insert默认值。一般最好一秒钟写入一次clickhouse。
(2)将由MybatisPlus的savebatch批量写入改为其他方式写入。采用clickhouse原生的jdbc写入或者flink摄入,flink我这边自定义了sink 用于摄入clickhouse,达到一定批次或者执行checkpoint时就写入一次。
(3)为了保证批量,我这边采用实时双buffer缓冲队列方式写入,这个队列可以是本地缓存队列,也可以是redis缓存队列。根据时间窗口期和固定写入阈值(针对波动大的可以按照二次指数平滑函数去确定阈值)进行写入与否的判断。设置一个读队列,一个写队列,并设置一个开关,一个阈值,一个定时器,当数据来时,默认放入写队列中,当队列中数据的数量大于阈值,将开关关闭,将写队列数据放到读队列中,从读队列拿出数据批量写入clickhouse,将开关打开,清空队列中数据。如果队列中数据在一定时间内,比如10秒,一直没有达到阈值,也关闭开关,写队列数据放到读队列中,从读队列拿出数据批量写入clickhouse,将开关打开,清空队列中数据。

2.5 效果
MQ消费的TPS最高是2万+,也就是每秒写入的条数最高超过了俩万,在此情况下,保证了每秒只写入clickhouse一次,写入性能也稳定在50毫秒左右,写入性能相比较于之前方案提升了5000倍,吞吐量相较于之前也提升了几十倍。


3、查询优化
3.1 历史方案
索引:一级索引是时间,二级索引是id,因为大部分是根据时间来查询,id作为排序。
字段值:写入时候将字段值默认为空。
查询:查询时候查询所有列的数据,再线性查询每条数据的活动信息、奖励信息等。
3.2 出现的问题
目前生产环境有40亿+数据,耗时很长,达到了30秒,非常非常慢。
3.3 出现问题的原因
尝试通过SQL执行计划来确定一个sql 的查询瓶颈。目前查看sql 执行计划有两种方法:
方法一(20.6之前版本):clickhouse-client -u xxxx --password xxxxxx --send_logs_level=trace <<< 'your query sql' > /dev/null;
方法二(20.6与20.6之后版本):explain SQL。
方法一是指定clickhouse 执行日志级别为trace,这样可以打印出来sql 各个阶段执行的日志,通过日志型来分析SQL执行情况,能够详细的了解到SQL执行情况。方法二有点像mysql那样,但这个只能打印部分SQL执行情况,不够详细。所以我们最终使用了方法一。
通过分析发现这几方面原因:
(1)查询缓慢的都是固定维度查询的,例如:用户pin、活动id等。分析了查询sql 的执行计划,主键索引和分区都没有用到。没有用到主键索引是导致查询慢的主要原因。至于为什么,这个要从clickhouse的底层存储结构说了,这里不详细说明,想了解的可以去看看我上篇文章。
(2)因为ClickHouse对于空值,在底层存储是用了单独的文件存储。相对于没有空值的情况,存在空值会稍微影响查询性能。
(3)没有分区查询,跟hive一样,表分区后,底层也会有相关的分区目录,筛选的时候添加分区过滤,提升查询性能。
3.4 改造方案
3.5 效果
40亿+的数据量,由之前13-20秒提升为800-1200毫秒返回,约提升15-20倍。
4、思考
如果后续数据量超过百亿,达到几百亿甚至千亿级别的数据量,性能还会不会这么好呢?这时候可以考虑分表策略,将用户pin进行hash,例如分十张表存储数据,将每张表数据控制在50-100亿级别。在数据写入这块,使用分表了策略后还需要自定义分表摄入的策略。
作者:京东科技 苗元
来源:京东云开发者社区 转载请注明来源
clickhouse 优化实践,万级别QPS数据毫秒写入和亿级别数据秒级返回 | 京东云技术团队的更多相关文章
- 字节跳动基于ClickHouse优化实践之“多表关联查询”
更多技术交流.求职机会.试用福利,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 相信大家都对大名鼎鼎的ClickHouse有一定的了解了,它强大的数据分析性能让人印象深刻.但在字节大量 ...
- 技术干货:实时视频直播首屏耗时400ms内的优化实践
本文由“逆流的鱼yuiop”原创分享于“何俊林”公众号,感谢作者的无私分享. 1.引言 直播行业的竞争越来越激烈,进过2018年这波洗牌后,已经度过了蛮荒暴力期,剩下的都是在不断追求体验.最近正好在做 ...
- 让Elasticsearch飞起来!——性能优化实践干货
原文:让Elasticsearch飞起来!--性能优化实践干货 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog ...
- 融云技术分享:融云安卓端IM产品的网络链路保活技术实践
本文来自融云技术团队原创分享,原文发布于“ 融云全球互联网通信云”公众号,原题<IM 即时通讯之链路保活>,即时通讯网收录时有部分改动. 1.引言 众所周知,IM 即时通讯是一项对即时性要 ...
- 京东云开发者|京东云RDS数据迁移常见场景攻略
云时代已经来临,云上很多场景下都需要数据的迁移.备份和流转,各大云厂商也大都提供了自己的迁移工具.本文主要介绍京东云数据库为解决用户数据迁移的常见场景所提供的解决方案. 场景一:数据迁移上云 数据迁移 ...
- 虎牙在全球 DNS 秒级生效上的实践 集群内通过 raft 协议同步数据,毫秒级别完成同步。
https://mp.weixin.qq.com/s/9bEiE4QFBpukAfNOYhmusw 虎牙在全球 DNS 秒级生效上的实践 原创: 周健&李志鹏 阿里巴巴中间件 今天
- 【DataMagic】如何在万亿级别规模的数据量上使用Spark
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文首发在云+社区,未经许可,不得转载. 作者:张国鹏 | 腾讯 运营开发工程师 一.前言 Spark作为大数据计算引擎,凭借其快速.稳定. ...
- 从 ClickHouse 到 ByteHouse:实时数据分析场景下的优化实践
本文来自火山引擎公众号,原文发布于2021-09-06. 近日,字节跳动旗下的企业级技术服务平台火山引擎正式对外发布「ByteHouse」,作为 ClickHouse 企业版,解决开源技术上手难 &a ...
- Redis各种数据结构性能数据对比和性能优化实践
很对不起大家,又是一篇乱序的文章,但是满满的干货,来源于实践,相信大家会有所收获.里面穿插一些感悟和生活故事,可以忽略不看.不过听大家普遍的反馈说这是其中最喜欢看的部分,好吧,就当学习之后轻松一下. ...
- 如何在万亿级别规模的数据量上使用Spark
一.前言 Spark作为大数据计算引擎,凭借其快速.稳定.简易等特点,快速的占领了大数据计算的领域.本文主要为作者在搭建使用计算平台的过程中,对于Spark的理解,希望能给读者一些学习的思路.文章内容 ...
随机推荐
- 数据库的两个好帮手:pagehack和pg_xlogdump
摘要:pagehack和pg_xlogdump可以帮助我们在数据库故障定位中,解析各种文件的页面头和xlog日志. 随着技术的演进,数据也发生了巨大的变化,数据规模越来愈大.数据种类呈现多样性,数据处 ...
- 不信谣不传谣,亲自动手验证ModelBox推理是否真的“高性能”
摘要:"高性能推理"是ModelBox宣传的主要特性之一,不信谣不传谣的我决定通过原生API和ModelBox实现相同案例进行对比,看一下ModelBox推理是否真的"高 ...
- 常遇到读多写少,教你用ReadWriteLock实现一个通用的缓存中心
摘要:本文我们就来说说使用ReadWriteLock如何实现一个通用的缓存中心. 本文分享自华为云社区<[高并发]原来ReadWriteLock也能开发高性能缓存,看完我也能和面试官好好聊聊了! ...
- 揭秘华为云GaussDB(for Influx):最佳实践之数据建模
摘要:本期将从GaussDB(for Influx)数据模型谈起,分享GaussDB(for Influx)数据建模的最佳方法,避免一些使用过程中的常见问题. 本文分享自华为云社区<华为云Gau ...
- 火山引擎DataTester分享:A/B实验中常见的8个错误
火山引擎DataTester是科学可信的A/B测试与智能优化平台,源自字节跳动长期沉淀,能够深度耦合推荐.广告.搜索.UI.产品功能等多种行业场景需求,为业务增长.转化.产品迭代,运营提效等各环节提供 ...
- 发布会回放|Gradio 4.0 正式发布!
Gradio 的目标是使机器学习模型的演示更容易定制和访问,以满足不同用户的需求.在 4.0 正式版的发布活动上,Hugging Face 的 Gradio 团队介绍了自己为了提高机器学习模型的可访问 ...
- 使用Expression代替反射读取IDataReader或IDataRecord给实体类赋值
ExpressionMapper代码 using System; using System.Collections.Concurrent; using System.Collections.Gener ...
- SpringBoot Serverless 实战 | 监控调试
SpringBoot 是基于 Java Spring 框架的套件,它预装了 Spring 的一系列组件,让开发者只需要很少的配置就可以创建独立运行的应用程序.在云原生的世界,有大量的平台可以运行 Sp ...
- 三、mycat实验数据
系列导航 一.Mycat实战---为什么要用mycat 二.Mycat安装 三.mycat实验数据 四.mycat垂直分库 五.mycat水平分库 六.mycat全局自增 七.mycat-ER分片 最 ...
- 1 Englishi 词根
1 ab 离去,相反, 不 (负能量的) abnormal abuse 2 anti 反对,相反 antiwar antiaging antiforeign antinoise 3 co-/col ...