沙龙回顾|ClickHouse 在实时场景的应用和优化
此次分享分为三部分内容 , 第一部分通过讲解推荐和广告业务的两个典型案例 , 穿插介绍字节内部相应的改进 。 第二部分会介绍典型案例中未覆盖到的改进和经验 。 第三部分会提出目前的不足和未来的改进计划 。
(文末附ClickHouse沙龙第四场:《ClickHouse在A/B实验和模型训练的使用》报名方式)
沙龙视频ClickHouse在实时场景的应用和优化
讲师:郭映中字节跳动ClickHouse研发工程师
文字沉淀早期实践
数仓同学一般会在HDFS/Hive准备好原始数据;数据就绪后 , 会执行一个基于Spark的ETL服务 , 将数据切成N份再存回HDFS(必要的话也会做一些数据的预处理);再发起INSERTQuery给ClickHouse集群的每一个shard , 将对应的数据文件从HDFS中直接导入到MergeTree表中 , 需要注意的是 , 这里没有把数据写入分布式表(i.e.Distributedtable)中;每个节点上的MergeTree表写入成功之后 , 会由外部事务校验整个集群的数据是否写入成功:如果部分节点导入失败 , 外部的导入服务会将部分写入的数据回滚并重新执行导入任务 , 直到数据完全导入成功 , 才允许上层的分析平台查询数据 。 也就是说 , 当ClickHouse中仅有不完整的数据时 , 外部的查询服务不会查询当天的数据 。
直接写入的风险用户写入ClickHouse一般有两种选择:分布式表(i.e.Distributed) , MergeTree表:
写入分布式表:数据写入分布式表时 , 它会将数据先放入本地磁盘的缓冲区 , 再异步分发给所有节点上的MergeTree表 。 如果数据在同步给MergeTree里面之前这个节点宕机了 , 数据就可能会丢失;此时如果在失败后再重试 , 数据就可能会写重 。 因而 , 直接将数据写入用分布式表时 , 不太好保证数据准确性的和一致性 。
当然这个分布式表还有其他问题 , 一般来说一个ClickHouse集群会配置多个shard , 每个shard都会建立MergeTree表和对应的分布式表 。 如果直接把数据写入分布式表 , 数据就可能会分发给每个shard 。 假设有N个节点 , 每个节点每秒收到一个INSERTQuery , 分发N次之后 , 一共就是每秒生成NxN个part目录 。 集群shard数越多 , 分发产生的小文件也会越多 , 最后会导致你写入到MergeTree的Part的数会特别多 , 最后会拖垮整个文件的系统 。
写入MergeTree表:直接写入MergeTree表可以解决数据分发的问题 , 但是依然抗不住高频写入 , 如果业务方写入频次控制不好 , 仍然有可能导致ClickHouse后台合并的速度跟不上写入的速度 , 最后会使得文件系统压力过大 。
所以一段时间内 , 我们禁止用户用INSERTQuery把数据直接写入到ClickHouse 。
典型案例-推荐系统
研发同学有debug的需求 , 他们不仅需要看聚合指标 , 某些时间还需要查询明细数据 。 推荐系统产生的数据 , 维度和指标多达几百列 , 而且未来可能还会增加 。 每一条数据都命中了若干个实验 , 使用Array存储 , 需要高效地按实验ID过滤数据 。 需要支持一些机器学习和统计相关的指标计算(比如AUC) 。
缺点:需要额外资源、写入频次不好控制、难以处理节点故障、维护成本较高
关键是后面两点:由于缺少事务的支持 , 实时导入数据时难以处理节点故障;ClickHouse组技术栈以C++为主 , 维护Flink潜在的成本比较高 。
目前字节内部的ClickHouse并没有使用社区版本的skipindex , 不过也有类似的辅助索引(e.g.BloomFilterIndex,BitmapIndex) 。 构建part的前两步和社区一致 , 我们构建完columns数据之后用户即可正常查询 , 不过此时的part不能启用索引 。 此时 , 再将刚构建好数据的part放入到一个异步索引构建队列中 , 由后台线程构建索引文件 。 这个改进虽然整体的性能开销没有变化 , 但是由于隐藏了索引构建的时间开销 , 整体的写入吞吐量大概能提升20%
小结一下上面说的主备只有一个节点消费的问题
配置两副本情况下的Kafkaengine , 主备仅有一个节点消费 , 另一个节点待机 。
如果有故障节点 , 则自动切换到正常节点消费;如果有新替换的节点无法正常服务 , 也切换到另一个节点;如果不同机房 , 则由离Kafka更近的节点消费 , 减少带宽消耗;否则 , 由类似ReplicatedMergeTree的ZooKeeperLeader决定 。 典型案例-广告投放实时数据
难点二:业务数据的维度也非常多 , 这种场景下使用Druid预聚合的效率并不高 。
对比Druid和ClickHouse的特点和性能后 , 我们决定将该系统迁移到ClickHouse+自研敏捷BI 。 最后由于维度比较多 , 并没有采用预聚合的方式 , 而是直接消费明细数据 。
因为业务产生的数据由(1)大量的当天数据和(2)少量的历史数据组成 。 历史数据一般涉及在3个月内 , 3个月外的可以过滤掉 , 但是即便是3个月内的数据 , 在按天分区的情况下 , 也会因为单批次生成的parts太多导致写入性能有一定下降 。 所以我们一开始是把消费的block_size调的非常大 , 当然这样也有缺点 , 虽然整个数据吞吐量会变大 , 但是由于数据落盘之前是没法查到数据的 , 会导致整体延时更大 。
(2)把Buffer内置到Kafkaengine内部 , 作为Kafkaengine的选项可以开启/关闭;
(3)最重要的是支持了ReplicatedMergeTree情况下的查询;
(4)Buffertable内部类似pipeline模式处理多个Block 。
【沙龙回顾|ClickHouse 在实时场景的应用和优化】首先是查询粒度 , 如果大家有听第一场分享就大概知道 , 我们目前对物化视图做了一些改进 , 假如查询粒度选了5分钟或10分钟 , 那消费数据时数据会像Druid一样提前对数据预聚合 。 而查询的时候也会做一些查询改写 , 用来达到类似Druid的效果 , 目的是为了覆盖公司内部一些用Druid的场景 。
为简化用户的使用成本 , 用户也不用挨个填写Table的Schema , 而是从Kafka的数据里直接推断出schema 。
(2)之后会尝试实现读写分离 , 将消费数据的节点与查询节点隔离;再基于读写分离做消费节点的动态伸缩 。
(3)分开的消费/写入节点做为专门的写入层 , 后续会引入WAL和Buffer解决高频写入的问题 。 如果有必要的话 , 也会在写入层实现类似分布式表分发数据的功能 。
一旦上面的功能实现成熟 , 会考虑重新开放业务直接使用INSERTQuery写入数据 。
沙龙预告ClickHouse在A/B实验和模型训练的使用
时间:2020年8月28日19:00-20:00
讲师:吴健字节跳动ClickHouse研发工程师
报名链接字节跳动技术沙龙第7期:ClickHouse在A/B实验和模型训练的使用
参与方式:
字节跳动技术沙龙邀请来自字节跳动及业内互联网公司的技术专家 , 分享热门技术话题与一线实践经验 , 内容覆盖架构、大数据、前端、测试、运维、算法、系统等技术领域 。
字节跳动技术沙龙旨在为技术领域人才提供一个开放、自由的交流学习平台 , 帮助技术人学习成长 , 不断进阶 。
推荐阅读
- 火星|“十三五”科技成果回顾——火星探测篇
- 变异毒株|频频出现的新冠变异毒株会使疫苗无效吗?一文回顾这些引起关注的变异毒株
- 高福|高福:疫情仍存爆发风险,做好防护“三大件” |财新时间回顾
- 探测器|成功“刹车”探测器被火星引力捕获,回顾“天问一号”离家的203天
- 火星|成功刹车!一图回顾“天问一号”奔赴火星的200多天
- 乙肝表面抗原|乙肝在研新药REP 2139,401研究回顾,功能性治愈益处
- 月球|科技大国,科技强国—部分科技成果回顾
- 华东理工大学|华东理工大学王辅臣教授:煤气化技术在中国:回顾与展望
- 展览|意大利著名艺术家乔治·莫兰迪回顾展下月来京
- 辱母杀人案|辱母杀人案当事人于欢出狱最新消息:于欢案案情回顾
