本文来自火山引擎公众号,原文发布于2021-09-06。

近日,字节跳动旗下的企业级技术服务平台火山引擎正式对外发布「ByteHouse」,作为 ClickHouse 企业版,解决开源技术上手难 & 试错成本高的痛点,同时提供商业产品和技术支持服务。

作为国内规模最大的 ClickHouse 用户,目前字节跳动内部的 ClickHouse 节点总数超过 1 万 5 千个,管理总数据量超过 600PB,最大的集群规模在 2400 余个节点。综合来说,字节跳动广泛的业务增长分析很多都建立在 ClickHouse 为基础的查询引擎上。在打造 ClickHouse 企业版「ByteHouse」的路程中,我们经过了多年的探索与沉淀,今天和大家分享字节跳动过去使用 ClickHouse 的两个典型应用与优化案例。

推荐系统实时指标

在字节跳动内部“AB实验”应用非常广泛,特别是在验证推荐算法和功能优化的效果方面。最初,公司内部专门的 AB 实验平台已经提供了 T+1 的离线实验指标,而推荐系统需要更快地观察算法模型、或者某个功能的上线效果,因此需要一份能够实时反馈的数据作为补充:

  • 能同时查询聚合指标和明细数据;

  • 能支持多达几百列的维度和指标,且场景灵活变化,会不断增加;

  • 可以高效地按ID过滤数据;

  • 需要支持一些机器学习和统计相关的指标计算(比如 AUC)。

︱技术选型

字节内部有很多分析引擎,ClickHouse、 Druid、 Elastic Search、 Kylin等,通过分析用户需求后选择了ClickHouse:

  • 能更快地观察算法模型,没有预计算所导致的高数据时延;

  • ClickHouse 既适合聚合查询,配合跳数索引后,对于明细点查性能也不错;

  • 字节自研的ClickHouse 支持 Map 类型,支持动态变更的维度和指标,更加符合需求;

  • BitSet 的过滤 Bloom Filter 是比较好的解决方案,ClickHouse 原生就有 BF 的支持;

  • 字节自研的 ClickHouse 引擎已经通过UDF 实现了相关的能力,而且有比较好的扩展性。

每个产品都有自己合适的场景,但是对于当前场景的需求评估下,ClickHouse 更加合适。

︱方案评估

方案对比

确认技术选型后,在如何实现部分,也有两种方式:

最终方案 & 效果

由于外部写入并不可控和技术栈上的原因,我们最终采用了 Kafka Engine 的方案,也就是 ClickHouse 内置消费者去消费 Kafka。整体的架构如图:

  • 数据由推荐系统直接产生,写入 Kafka——为了弥补缺少 Flink 的 ETL 能力,推荐系统做了相应配合,修改 Kafka Topic 的消息格式直接适配 ClickHouse 表的 schema;

  • 敏捷 BI 平台也适配了一下实时的场景,可以支持交互式的查询分析;

  • 如果实时数据有问题,也可以从 Hive 把数据导入至 ClickHouse 中,除此之外,业务方还会将 1% 抽样的离线数据导入过来做一些简单验证,1% 抽样的数据一般会保存更久的时间。

除了技术选型和实现方案,我们在支持推荐系统的实时数据时遇到过不少问题,其中最大的问题随着推荐系统产生的数据量越来越大,单个节点的消费能力也要求越来越大,主要碰到如下问题:

︱问题一:写入吞吐量不足

挑战:在有大量辅助跳数索引的场景下,索引的构建严重影响写入吞吐量。

解决方案:异步构建索引。

社区版本的实现里的具体逻辑如下:

  • 解析输入数据生成内存中数据结构的 Block;

  • 然后切分 Block,并按照表的 schema 构建 columns 数据文件;

  • 最后扫描根据 skip index schema 去构建 skip index 文件。三个步骤完成之后才会算 Part 文件构建完毕。

在需要保证构建完 columns 数据之后用户即可正常查询的前提下,ByteHouse 同步完成前面两步,第三步把构建好的 part  放入到一个异步索引构建队列中,由后台线程构建索引文件。

效果:在改成异步后,整体的写入吞吐量大概能提升 20%。

︱问题二:Kafka 消费能力不足

挑战:社区版本的 Kafka 表,内部默认只会有一个消费者,这样会比较浪费资源并且性能达不到性能要求。

尝试优化过程:

  • 尝试通过增大消费者的个数来增大消费能力,但社区的实现是由一个线程去管理多个的消费者,多个消费者消费到的数据最后仅能由一个输出线程完成数据构建,所以这里没能完全利用上多线程和磁盘的潜力;

  • 尝试通过创建多张 Kafka Table 和 Materialized View 写入同一张表,但是对于运维会比较麻烦。

解决方案:支持多线程消费。

前面提到的优化手段都不尽如人意,最后决定改造 Kafka Engine 在其内部支持多个消费线程,简单来说就是每一个线程它持有一个消费者,然后每一个消费者负责各自的数据解析、数据写入,这样的话就相当于一张表内部同时执行多个的 INSERT Query。

效果:通过多线程实现多消费者同时消费写入表,写入性能达到接近于线性的提升。

︱问题三:出现故障无法保证数据完整性

挑战:在主备模式下,如果数据同时两个节点都写入,一旦一个节点出现故障,新启的节点恢复过程中容易出现各种问题,包括性能下降,无法保证分片,最严重可能导致查询结果不正确。

解决方案:确保主备模式下只会写入一个主备其中一个节点。

为了避免两个节点消费这个数据,改进版的 Kafka Engine 参考了 ReplicatedMergeTree 基于 ZooKeeper 的选主逻辑。对于每一对副本的一对消费者,会尝试在 ZooKeeper 上完成选主逻辑,确保选举成为主节点的消费者才能消费,另一个节点则会处于一个待机状态。

有了这样的单节点消费机制, 系统会检测 ReplicatedMergeTree 表数据是否完整,如果数据不完整则代表不能正常服务,此时消费者会主动出让 Leader,让副本节点上成为消费者,也就是新写入的数据并不会写入到缺少数据的节点,对于查询而言,由于查询路由机制的原因也不会把 Query 路由到缺少数据的节点上,所以一直能查询到最新的数据。

效果:改进 Kafka engine 确保主备模式下只有一个节点能消费数据,即使出现节点故障在新节点恢复过程中同样保障了解决了数据完整性的问题。

标题广告投放实时数据

第二个典型案例关于广告的投放数据,一般是运营人员需要查看广告投放的实时效果。由于业务的特点,当天产生的数据往往会涉及到多天的数据。这套系统原来基于 Druid 实现的,Druid 在这个场景会有一些难点:

选择了 ClickHouse 之后能解决 Druid 不足的地方,但还是有部分问题需要解决。

︱问题一:Buffer Engine 无法和 ReplicatedMergeTree 一起使用

问题 & 挑战:社区提供了 Buffer Engine 为了解决单次写入生成过多 parts 的问题, 但是不太能配合 ReplicatedMergeTree 一起工作, 写入不同 Replica 的 Buffer 仅缓存了各自节点上新写入的数据, 导致查询会出现不一致的情况。

解决方案:

改进了 Buffer Engine 做了如下的调整和优化:

  • 我们选择将 Kafka/Buffer/MergeTree 三张表结合起来,提供的接口更加易用;

  • 把 Buffer 内置到 Kafka engine 内部, 作为 Kafka engine 的选项可以开启/关闭,使用更方便;

  • Buffer table 内部类似 pipeline 模式处理多个 Block;

  • 支持了 ReplicatedMergeTree 情况下的查询。

首先确保一对副本仅有一个节点在消费,所以一对副本的两个 Buffer 表,只有一个节点有数据。如果查询发送到了没有消费的副本,会额外构建一个特殊的查询逻辑,从另一个副本的 Buffer 表里读取数据。

效果:增强 Buffer Engine,解决了Buffer Engine 和 ReplicatedMergeTree 同时使用下查询一致性的问题。

︱问题二:出现宕机后可能会出现数据丢失后者重复消费的情况

挑战:ClickHouse 缺少事务支持。一批次写入只写入部分 part 后出现宕机,因为没有事务保障重启后可能出现丢失或者重复消费的情况。

解决方案

参考了 Druid 的 KIS 方案自己管理 Kafka Offset,实现单批次消费/写入的原子语义:实现上选择将 Offset 和 Parts 数据绑定在一起,增强了消费的稳定性。每次消费时,会默认创建一个事务,由事务负责把 Part 数据和 Offset 一同写入磁盘中,如果出现失败,事务会一起回滚 Offset 和写入的 part 然后重新消费。

效果:确保了每次插入数据的原子性,增强了数据消费的稳定性。

小结

实时数据分析是 ClickHouse 的优势场景,结合字节跳动实时数据场景的特点,我们对 ClickHouse 进行了优化和改造,并将这些能力沉淀到了 ByteHouse 上。ByteHouse 基于自研技术优势和超大规模的使用经验,为企业大数据团队带来新的选择和支持,以应对复杂多变的业务需求,高速增长的数据场景。未来,ByteHouse将不断以字节和外部最佳实践输出行业用户,帮助企业更好地构建交互式大数据分析平台,并更广泛的与 ClickHouse 研发者社群共享经验,共同推动 ClickHouse 社区的发展。

从 ClickHouse 到 ByteHouse:实时数据分析场景下的优化实践的更多相关文章

  1. HttpClient在高并发场景下的优化实战

    在项目中使用HttpClient可能是很普遍,尤其在当下微服务大火形势下,如果服务之间是http调用就少不了跟http客户端找交道.由于项目用户规模不同以及应用场景不同,很多时候可能不需要特别处理也. ...

  2. Insert 语句对 nologging 与 logging表 在不同场景下的优化

    前言 前段时间报表数据库上有条insert sql语句,插入的大量数据,执行非常慢,需要对其进行分析优化. 分析步骤是在:ARCHIVE与NOARCHIVE模式下进行. 测试场景: 分别对表的常规插入 ...

  3. 活动报名:以「数」制「疫」,解密 Tapdata 在张家港市卫健委数字化防疫场景下的最佳实践

        疫情两年有余,全国抗疫攻防战步履不停.在"动态清零"总方针的指导下,国内疫情防控工作渐趋规范化.常态化.健康码.行程卡.疫情地图.电子哨兵.核酸码.场所码--各类精准防疫手 ...

  4. clickhouse在风控-风险洞察领域的探索与实践

    一.风险洞察平台介绍 以Clickhouse+Flink实时计算+智能算法为核心架构搭建的风险洞察平台, 建立了全面的.多层次的.立体的风险业务监控体系,已支撑欺诈风险.信用风险.企业风险.小微风险. ...

  5. 亿级流量场景下,大型架构设计实现【2】---storm篇

    承接之前的博:亿级流量场景下,大型缓存架构设计实现 续写本博客: ****************** start: 接下来,我们是要讲解商品详情页缓存架构,缓存预热和解决方案,缓存预热可能导致整个系 ...

  6. Lyft 基于 Flink 的大规模准实时数据分析平台(附FFA大会视频)

    摘要:如何基于 Flink 搭建大规模准实时数据分析平台?在 Flink Forward Asia 2019 上,来自 Lyft 公司实时数据平台的徐赢博士和计算数据平台的高立博士分享了 Lyft 基 ...

  7. 金融任务实例实时、离线跑批Apache DolphinScheduler在新网银行的三大场景与五大优化

    在新网银行,每天都有大量的任务实例产生,其中实时任务占据多数.为了更好地处理任务实例,新网银行在综合考虑之后,选择使用 Apache DolphinScheduler 来完成这项挑战.如今,新网银行多 ...

  8. 不同场景下 MySQL 的迁移方案

    一 目录 一 目录 二 为什么要迁移 三 MySQL 迁移方案概览 四 MySQL 迁移实战 4.1 场景一 一主一从结构迁移从库 4.2 场景二 一主一从结构迁移指定库 4.3 场景三 一主一从结构 ...

  9. 亿级流量场景下,大型缓存架构设计实现【1】---redis篇

    *****************开篇介绍**************** -------------------------------------------------------------- ...

随机推荐

  1. 安装pytorch的细节记录

    1.根据教程安装pytorch的时候发现太慢了,无法容忍,根据https://blog.csdn.net/zzq060143/article/details/88042075z在Ancona Prom ...

  2. 常用Java API:Calendar日期类

    摘要 在蓝桥杯中有关于日期计算的问题,正好java中的Date类和Calendar类提供了对日期处理的一些方法.Date类大部分方法已经废弃了,所以本文将详细介绍Calendar类. Calendar ...

  3. DDD领域驱动设计-设计规范-Ⅵ

    不以规矩,不能成方圆.                                                                     -战国·邹·孟轲<孟子·离娄章句上 ...

  4. 数字孪生 3D 科技馆的科学传播新模式

    前言 科技馆是一种参与型体验型的博物馆,以传播科学知识.培养公众的科学创新技术为宗旨,并以其生动的展现方式得到公众的广泛欢迎.一直以来,我国科技馆的发展受到各种因素的制约和影响,发展缓慢.如今在我国经 ...

  5. 安装与卸载JDK8

    前言:学习Java的第一步需要先配置好JDK环境,而JDK8是目前使用最广泛的JDK版本.本文讲解了如何下载安装和卸载JDK8.以下环境为Windows10 下载JDK安装包 Oracle官网 所有J ...

  6. docker创建本地主机实例Virtualbox 驱动出错

    宿主机系统:Centos7 64位 创建主机实例Virtualbox 命令:docker-machine create -d virtualbox test 连接centos工具:Finalshell ...

  7. RDD的详解、创建及其操作

    RDD的详解 RDD:弹性分布式数据集,是Spark中最基本的数据抽象,用来表示分布式集合,支持分布式操作! RDD的创建 RDD中的数据可以来源于2个地方:本地集合或外部数据源 RDD操作 分类 转 ...

  8. 查看Git提交的代码统计

    1,提交Top5: git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5 2,某用户提交的代码统计 git log ...

  9. Kafka面试题总结

    1.Kafka 都有哪些特点? 高吞吐量.低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partit ...

  10. [前端随笔][Vue] 多级菜单实现思路——组件嵌套

    说在前面 本篇记录学习了vue-element-admin中的多级菜单的实现 [传送门] @vue/cli 4.2.2:vuex:scss:组件嵌套 正文 创建项目 npm create 项目名 // ...