基于 EMR OLAP 的开源实时数仓解决方案之 Flink + ClickHouse 事务实现

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
简介: 本文介绍了如何支持 Flink 到 ClickHouse 的 Exactly-Once 写入来保证整个实时数仓数据准确性的现有机制及实现方案。

EMR-OLAP 团队主要负责开源大数据 OLAP 引擎的研发,例如 ClickHouse,Starrocks,Trino 等。通过 EMR 产品向阿里云用户提供一站式的大数据 OLAP 解决方案。本文介绍了如何支持 Flink 到 ClickHouse 的 Exactly-Once 写入来保证整个实时数仓数据准确性的现有机制及实现方案。主要内容包括:

  1. 背景
  2. 机制梳理
  3. 技术方案
  4. 测试结果
  5. 未来规划

一、背景

Flink 和 ClickHouse 分别是实时流式计算和 OLAP 领域的翘楚,很多互联网、广告、游戏等客户都将两者联合使用于构建用户画像、实时 BI 报表、应用监控指标查询、监控等业务,形成了实时数仓解决方案 (如图-1)。这些业务对数据的准确性要求都十分严格,所以实时数仓整个链路需要保证端到端的 Exactly-Once。

通常来说 Flink 的上游是可以重复读取或者消费的 pull-based 持久化存储 (例如 Kafka),要实现 Source 端的 Exactly-Once 只需要回溯 Source 端的读取进度即可。Sink 端的 Exactly-Once 则比较复杂,因为 Sink 是 push-based 的,需要依赖目标输出系统的事务保证,但社区 ClickHouse 对事务并不支持,所以针对此情况阿里云 EMR ClickHouse 与 Flink 团队一起深度研发,支持了 Flink 到 ClickHouse 的 Exactly-Once 写入来保证整个实时数仓数据的准确性。本文将分别介绍下现有机制以及实现方案。

img

图-1 实时数仓架构

二、机制梳理

2.1 ClickHouse 写入机制

ClickHouse 是一个 MPP 架构的列式 OLAP 系统 (如图-2),各个节点是对等的,通过 Zookeeper 协同数据,可以通过并发对各个节点写本地表的方式进行大批量的数据导入。

ClickHouse 的 data part 是数据存储的最小单元,ClickHouse 接收到的数据 Block 在写入时,会按照 partition 粒度进行拆分,形成一个或多个 data part。data part 在写入磁盘后,会通过后台merge线程不断的合并,将小块的 data part 合并成大块的 data part,以此降低存储和读取的开销。

在向本地表写入数据时,ClickHouse 首先会写入一个临时的 data part,这个临时 data part 的数据对客户端不可见,之后会直接进行 rename 操作,使这个临时 data part 成为正式 data part,此时数据对客户端可见。几乎所有的临时 data part 都会快速地成功被 rename 成正式 data part,没有被 rename 成功的临时 data part 最终将被 ClickHouse 清理策略从磁盘上删除。

通过上述分析,可以看出 ClickHouse 的数据写入有一个从临时 data part 转为正式 data part 的机制,加以修改可以符合两阶段提交协议,这是实现分布式系统中事务提交一致性的重要协议。

img

图-2 Flink 作业写入 ClickHouse

注:多个 Flink Task 可以写入同一个 shard 或 replica

2.2 Flink 写机制

​ Flink 作为一个分布式处理引擎,提供了基于事务的 Sink 机制,该机制可以保障写入的 Exactly-Once,相应的数据接收方需要提供遵守 XA 规范的 JDBC 。由于完整的 XA 规范相当复杂,因此,我们先对 Flink 的处理机制进行梳理,结合 ClickHouse 的实际情况,确定需要实现的接口范围。

​ 为了实现分布式写入时的事务提交统一,Flink 借助了 checkpoint 机制。该机制能够周期性地将各个 Operator 中的状态生成快照并进行持久化存储。在 checkpoint 机制中,有一个 Coordinator 角色,用来协调所有 Operator 的行为。从 Operator 的角度来看,一次 checkpoint 有三个阶段,初始化-->生成快照-->完成/废弃 checkpoint。从 Coordinator 的角度来看,需要定时触发 checkpoint,以及在所有 Operator 完成快照后,触发 complete 通知。(参考附录 [1] )

​ 接下来介绍 Flink 中的 Operator 是如何借助事务和 checkpoint 机制来保障 Exactly-Once,Operator 的完整执行需要经过 initial、writeData、snapshot、commit 和 close 阶段。

initial 阶段:

  • 从快照中取出上次任务执行时持久化的 xid 记录。快照中主要存储两种 xid,一组是未完成 snapshot 阶段的 xid,一组是已经完成了 snapshot 的 xid。
  • 接下来对上次未完成 snapshot 的 xid 进行 rollback 操作;对上次已经完成了 snapshot 但 commit 未成功的 xid 进行 commit 重试操作。
  • 若上述操作失败,则任务初始化失败,任务中止,进入 close 阶段;若上述操作成功,则继续。
  • 创建一个新的唯一的 xid,作为本次事务 ID,将其记录到快照中。
  • 使用新生成的 xid,调用 JDBC 提供的 start() 接口。

writeData 阶段:

  • 事务开启后,进入写数据的阶段,Operator 的大部分时间都会处于这个阶段。在与 ClickHouse 的交互中,此阶段为调用 JDBC 提供的 preparedStatement 的 addBatch() 和 executeBatch() 接口,每次写数据时都会在报文中携带当前 xid。
  • 在写数据阶段,首先将数据写到 Operator 内存中,向 ClickHouse 提交内存中的批量数据有三种触发方式:内存中的数据条数达到 batchsize 的阈值;后台定时线程每隔一段时间触发自动 flush;在 snapshot 阶段调用end() 和 prepare() 接口之前会调用 flush 清空缓存。

snapshot 阶段:

  • 当前事务会调用 end() 和 prepare() 接口,等待 commit,并更新快照中的状态。
  • 接下来,会开启一个新的事务,作为本 Task 的下一次 xid,将新事务记录到快照中,并调用 JDBC 提供的start() 接口开启新事务。
  • 将快照持久化存储。

complete 阶段:

在所有 Operator 的 snapshot 阶段全部正常完成后,Coordinator 会通知所有 Operator 对已经成功的checkpoint 进行 complete 操作,在与 ClickHouse 的交互中,此阶段为 Operator 调用 JDBC 提供的 commit() 接口对事务进行提交。

close阶段:

  • 若当前事务尚未进行到 snapshot 阶段,则对当前事务进行 rollback 操作。
  • 关闭所有资源。

从上述流程可以总结出,Flink 通过 checkpoint 和事务机制,将上游数据按 checkpoint 周期分割成批,保障每一批数据在全部写入完成后,再由 Coordinator 通知所有 Operator 共同完成 commit 操作。当有 Operator 写入失败时,将会退回到上次成功的 checkpoint 的状态,并根据快照记录的 xid 对这一批 checkpoint 的所有 xid 进行 rollback 操作。在有 commit 操作失败时,将会重试 commit 操作,仍然失败将会交由人工介入处理。

三、技术方案

3.1 整体方案

根据 Flink 和 ClickHouse 的写入机制,可以描绘出一个Flink 到 ClickHouse 的事务写入的时序图 (如图-3)。由于写的是 ClickHouse 的本地表,并且事务的统一提交由 Coordinator 保障,因此 ClickHouse 无需实现 XA 规范中标准的分布式事务,只需实现两阶段提交协议中的少数关键接口,其他接口在 JDBC 侧进行缺省即可。

img

图-3 Flink 到 ClickHouse 事务写入的时序图

3.2 ClickHouse-Server

3.2.1 状态机

为了实现 ClickHouse 的事务,我们首先定义一下所要实现的事务允许的几种操作:

  • Begin:开启一个事务。
  • Write Data:在一个事务内写数据。
  • Commit:提交一个事务。
  • Rollback:回滚一个未提交的事务。

事务状态

  • Unknown:事务未开启,此时执行任何操作都是非法的。
  • Initialized:事务已开启,此时允许所有操作。
  • Committing:事务正在被提交,不再允许 Begin/Write Data 两种操作。
  • Committed:事务已经被提交,不再允许任何操作。
  • Aborting:事务正在被回滚,不再允许任何操作。
  • Aborted:事务已经被回滚,不再允许任何操作。

完整的状态机如下图所示:

img

图-4 ClickHouse Server 支持事务的状态机

图中所有操作均是幂等的。其中,Committing 到 Committed 和 Aborting 到 Aborted 是不需要执行任何操作的,在开始执行 Commit 或 Rollback 时,事务的状态即转成 Committing 或 Aborting;在执行完 Commit 或 Rollback 之后,事务的状态会被设置成 Committed 或 Aborted。

3.2.2 事务处理

Client 通过 HTTP Restful API 访问 ClickHouse Server,Client 与 ClickHouse Server 间一次完整事务的交互过程如图-5 所示:

img

图-5 Clickhouse 事务处理的时序图

正常流程:

  • Client 向 ClickHouse 集群任意一个 ClickHouse Server 发送 Begin Transaction 请求,并携带由 Client 生成的全局唯一的 Transaction ID。ClickHouse Server 收到 Begin Transaction 请求时,会向 Zookeeper 注册该Transaction ID (包括创建 Transaction ID 及子 Znode 节点),并初始化该 Transaction 的状态为 Initialized
  • Client 接收到 Begin Transaction 成功响应时,可以开始写入数据。当 ClickHouse Server 收到来自 Client 发送的数据时,会生成临时 data part,但不会将其转为正式 data part,ClickHouse Server 会将写入的临时 data part 信息,以 JSON 的形式,记录到 Zookeeper 上该 Transaction 的信息中。
  • Client 完成数据的写入后,会向 ClickHouse Server 发送 Commit Transaction 请求。 ClickHouse Server 在收到 Commit Transaction 请求后,根据 ZooKeeper 上对应的Transaction的 data part 信息,将 ClickHouse Server 本地临时 data part 数据转为正式的 data part 数据,并更新Transaction 状态为Committed。Rollback 的过程与 Commit 类似。

异常处理:

  • 如果创建 Transaction ID 过程中发现 Zookeeper 中已经存在相同 Transaction ID,根据 Zookeeper 中记录的 Transaction 状态进行处理:如果状态是 Unknown 则继续进行处理;如果状态是 Initialized 则直接返回;否则会抛异常。
  • 目前实现的事务还不支持分布式事务,只支持单机事务,所以 Client 只能往记录该 Transaction ID 的 ClickHouse Server 节点写数据,如果 ClickHouse Server 接收到到非该节点事务的数据,ClickHouse Server 会直接返回错误信息。
  • 与写入数据不同,如果 Commit 阶段 Client 向未记录该 Transaction ID 的 ClickHouse Server 发送了 Commit Transaction 请求,ClickHouse Server 不会返回错误信息,而是返回记录该 Transaction ID 的 ClickHouse Server 地址给 Client,让 Client 端重定向到正确的 ClickHouse Server。Rollback 的过程与 Commit 类似。

3.3 ClickHouse-JDBC

根据 XA 规范,完整的分布式事务机制需要实现大量的标准接口 (参考附录 [2] )。在本设计中,实际上只需要实现少量关键接口,因此,采用了基于组合的适配器模式,向 Flink 提供基于标准 XA 接口的 XAResource 实现,同时对 ClickHouse Server 屏蔽了不需要支持的接口。

对于 XADataSource 的实现,采用了基于继承的适配器模式,并针对 Exactly-Once 的特性,修改了部分默认配置,如发送失败的重试次数等参数。

另外,在生产环境中,通常不会通过分布式表,而是通过 SLB 进行数据写入时的负载均衡。在 Exactly-Once 场景中,Flink 侧的 Task 需要保持针对某一 ClickHouse Server 节点的连接,因此不能使用 SLB 的方式进行负载均衡。针对这一问题,我们借鉴了 BalanceClickHouseDataSource 的思路,通过在 URL 中配置多个IP,并在 properties 配置中将 write_mode 设置为 Random ,可以使 XADataSource 在保障 Exactly-Once 的同时,具有负载均衡的能力。

3.4 Flink-Connector-ClickHouse

Flink 作为一个流式数据处理引擎,支持向多种数据接收端写入的能力,每种接收端都需要实现特定的Connector。针对 Exactly-Once,ClickHouse Connector 增加了对于 XADataSource 的选项配置,根据客户端的配置提供 Exactly-Once 功能。

四、测试结果

4.1 ClickHouse 事务性能测试

  • 写入 ClickHouse 单批次数据量和总批次相同,Client端并发写线程不同性能比较。

    由图-6 可以看出,无论 ClickHouse 是否开启事务, ClickHouse 的吞吐量都与 Client 端并发写的线程数成正比。开启事务时,ClickHouse 中临时 data part 不会立刻被转为正式 data part,所以在事务完成前大量临时 data part 不会参与 ClickHouse merge 过程,降低磁盘 IO 对写性能的影响,所以开启事务写性能较未开启事务写性能更好;但事务内包含的批次变多,临时 data part 在磁盘上的增多导致了合并时 CPU 的压力增大,从而影响了写入的性能,开启事务的写性能也会降低。

    img

    图-6 ClickHouse 写入性能压测 (一)

  • 写入 ClickHouse 总批次 和 Client 端并发写线程相同,单批次写入 ClickHouse 数据量不同性能比较。

    由图-7 可以看出,无论 ClickHouse 是否开启事务, ClickHouse 的吞吐量都与单批次数据量大小成正比。开启事务时,每批次数据越小,ClickHouse 的吞吐量受事务是否开启的影响就越大,这是因为每批次写入的时间在事务处理的占比较小,事务会对此产生一定的影响,因此,一次事务包含的批次数量越多,越能够减少事务对写入性能的影响;当事务包含批次的增大,事务处理时间在写入中的占比逐渐降低,ClickHouse merge 产生的影响越来越大,从而影响了写入的性能,开启事务较不开启事务写性能更好。

    img

    图-7 ClickHouse写入性能压测 (二)

总体来说,开启事务对写入性能几乎没有影响,这个结论是符合我们预期的。

4.2 Flink 写入 ClickHouse 性能比较

对于相同数据量和不同 checkpoint 周期,Flink 写入 ClickHouse 总耗时如图-8 所示。可以看出,checkpoint 周期对于不开启 Exactly-Once 的任务耗时没有影响。对于开启 Exactly-Once 的任务,在 5s 到 60s 的范围内,耗时呈现一个先降低后增长的趋势。原因是在 checkpoint 周期较短时,开启 Exactly-Once 的 Operator 与 Clickhouse 之间有关事务的交互过于频繁;在 checkpoint 周期较长时,开启 Exactly-Once 的 Operator 需要等待 checkpoint 周期结束才能提交最后一次事务,使数据可见。在本测试中,checkpoint 周期数据仅作为一个参考,生产环境中,需要根据机器规格和数据写入速度进行调整。

总体来说,Flink 写入 Clickhouse 时开启 Exactly-Once 特性,性能会稍有影响,这个结论是符合我们预期的。

img

图-8 Flink 写入 ClickHouse 测试

五、未来规划

该版本 EMR ClickHouse 实现的事务还不是很完善,只支持单机事务,不支持分布式事务。分布式系统一般都是通过 Meta Server 来做统一元数据管理来支持分布式事务机制。当前我们也正在规划设计 ClickHouse MetaServer 来支持分布式事务,同时可以移除 ClickHouse 对 ZooKeeper 的依赖。

附录

[1] https://flink.apache.org/2020/10/15/from-aligned-to-unaligned-checkpoints-part-1.html

[2] https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf


Flink Forward Asia 2021 重磅开启,全球 40+ 多行业一线厂商,80+ 干货议题,带来专属于开发者的技术盛宴。

https://flink-forward.org.cn/

另有首届 Flink Forward Asia Hackathon 正式启动,20W 奖金等你来!

https://www.aliyun.com/page-source//tianchi/promotion/FlinkForwardAsiaHackathon

img


更多 Flink 相关技术问题,可扫码加入社区钉钉交流群
第一时间获取最新技术文章和社区动态,请关注公众号~

image.png

活动推荐

阿里云基于 Apache Flink 构建的企业级产品-实时计算Flink版现开启活动:
99 元试用 实时计算Flink版(包年包月、10CU)即有机会获得 Flink 独家定制卫衣;另包 3 个月及以上还有 85 折优惠!
了解活动详情:https://www.aliyun.com/product/bigdata/sc

image.png

相关实践学习
基于Hologres+Flink搭建GitHub实时数据大屏
通过使用Flink、Hologres构建实时数仓,并通过Hologres对接BI分析工具(以DataV为例),实现海量数据实时分析.
实时计算 Flink 实战课程
如何使用实时计算 Flink 搞定数据处理难题?实时计算 Flink 极客训练营产品、技术专家齐上阵,从开源 Flink功能介绍到实时计算 Flink 优势详解,现场实操,5天即可上手! 欢迎开通实时计算 Flink 版: https://cn.aliyun.com/product/bigdata/sc Flink Forward Asia 介绍: Flink Forward 是由 Apache 官方授权,Apache Flink Community China 支持的会议,通过参会不仅可以了解到 Flink 社区的最新动态和发展计划,还可以了解到国内外一线大厂围绕 Flink 生态的生产实践经验,是 Flink 开发者和使用者不可错过的盛会。 去年经过品牌升级后的 Flink Forward Asia 吸引了超过2000人线下参与,一举成为国内最大的 Apache 顶级项目会议。结合2020年的特殊情况,Flink Forward Asia 2020 将在12月26日以线上峰会的形式与大家见面。
相关文章
|
6月前
|
存储 消息中间件 OLAP
基于 Flink+Paimon+Hologres 搭建淘天集团湖仓一体数据链路
本文整理自淘天集团高级数据开发工程师朱奥在Flink Forward Asia 2024的分享,围绕实时数仓优化展开。内容涵盖项目背景、核心策略、解决方案、项目价值及未来计划五部分。通过引入Paimon和Hologres技术,解决当前流批存储不统一、实时数据可见性差等痛点,实现流批一体存储与高效近实时数据加工。项目显著提升了数据时效性和开发运维效率,降低了使用门槛与成本,并规划未来在集团内推广湖仓一体架构,探索更多技术创新场景。
1398 3
基于 Flink+Paimon+Hologres 搭建淘天集团湖仓一体数据链路
|
2月前
|
存储 JSON 数据处理
Flink基于Paimon的实时湖仓解决方案的演进
本文源自Apache CommunityOverCode Asia 2025,阿里云专家苏轩楠分享Flink与Paimon构建实时湖仓的演进实践。深度解析Variant数据类型、Lookup Join优化等关键技术,提升半结构化数据处理效率与系统可扩展性,推动实时湖仓在生产环境的高效落地。
352 0
Flink基于Paimon的实时湖仓解决方案的演进
|
4月前
|
分布式计算 Serverless OLAP
实时数仓Hologres V3.1版本发布,Serverless型实例从零开始构建OLAP系统
Hologres推出Serverless型实例,支持按需计费、无需独享资源,适合新业务探索分析。高性能查询内表及MaxCompute/OSS外表,弹性扩展至512CU,性能媲美主流开源产品。新增Dynamic Table升级、直读架构优化及ChatBI解决方案,助力高效数据分析。
实时数仓Hologres V3.1版本发布,Serverless型实例从零开始构建OLAP系统
|
4月前
|
SQL DataWorks 关系型数据库
DataWorks+Hologres:打造企业级实时数仓与高效OLAP分析平台
本方案基于阿里云DataWorks与实时数仓Hologres,实现数据库RDS数据实时同步至Hologres,并通过Hologres高性能OLAP分析能力,完成一站式实时数据分析。DataWorks提供全链路数据集成与治理,Hologres支持实时写入与极速查询,二者深度融合构建离在线一体化数仓,助力企业加速数字化升级。
|
4月前
|
存储 SQL 分布式计算
MaxCompute x 聚水潭:基于近实时数仓解决方案构建统一增全量一体化数据链路
聚水潭作为中国领先的电商SaaS ERP服务商,致力于为88,400+客户提供全链路数字化解决方案。其核心ERP产品助力企业实现数据驱动的智能决策。为应对业务扩展带来的数据处理挑战,聚水潭采用MaxCompute近实时数仓Delta Table方案,有效提升数据新鲜度和计算效率,提效比例超200%,资源消耗显著降低。未来,聚水潭将进一步优化数据链路,结合MaxQA实现实时分析,赋能商家快速响应市场变化。
221 0
|
8月前
|
存储 缓存 数据挖掘
Flink + Doris 实时湖仓解决方案
本文整理自SelectDB技术副总裁陈明雨在Flink Forward Asia 2024的分享,聚焦Apache Doris与湖仓一体解决方案。内容涵盖三部分:一是介绍Apache Doris,一款高性能实时分析数据库,支持多场景应用;二是基于Doris、Flink和Paimon的湖仓解决方案,解决批流融合与数据一致性挑战;三是Doris社区生态及云原生发展,包括存算分离架构与600多位贡献者的活跃社区。文章深入探讨了Doris在性能、易用性及场景支持上的优势,并展示了其在多维分析、日志分析和湖仓分析中的实际应用案例。
648 17
Flink + Doris 实时湖仓解决方案
|
9月前
|
SQL 消息中间件 Kafka
Flink+Paimon+Hologres,面向未来的一体化实时湖仓平台架构设计
本文介绍了阿里云实时数仓Hologres负责人姜伟华在Flink Forward Asia 2024上的分享,涵盖实时数仓的发展历程、从实时数仓到实时湖仓的演进,以及总结。文章通过三代实时数仓架构的演变,详细解析了Lambda架构、Kafka实时数仓分层+OLAP、Hologres实时数仓分层复用等方案,并探讨了未来从实时数仓到实时湖仓的演进方向。最后,结合实际案例和Demo展示了Hologres + Flink + Paimon在实时湖仓中的应用,帮助用户根据业务需求选择合适的方案。
1370 20
Flink+Paimon+Hologres,面向未来的一体化实时湖仓平台架构设计
|
8月前
|
存储 SQL Java
Flink CDC + Hologres高性能数据同步优化实践
本文整理自阿里云高级技术专家胡一博老师在Flink Forward Asia 2024数据集成(二)专场的分享,主要内容包括:1. Hologres介绍:实时数据仓库,支持毫秒级写入和高QPS查询;2. 写入优化:通过改进缓冲队列、连接池和COPY模式提高吞吐量和降低延迟;3. 消费优化:优化离线场景和分区表的消费逻辑,提升性能和资源利用率;4. 未来展望:进一步简化用户操作,支持更多DDL操作及全增量消费。Hologres 3.0全新升级为一体化实时湖仓平台,提供多项新功能并降低使用成本。
657 1
Flink CDC + Hologres高性能数据同步优化实践
|
9月前
|
存储 关系型数据库 MySQL
Flink基于Paimon的实时湖仓解决方案的演进
本文整理自阿里云智能集团苏轩楠老师在Flink Forward Asia 2024论坛的分享,涵盖流式湖仓架构的背景介绍、技术演进和未来发展规划。背景部分介绍了ODS、DWD、DWS三层数据架构及关键组件Flink与Paimon的作用;技术演进讨论了全量与增量数据处理优化、宽表构建及Compaction操作的改进;发展规划则展望了Range Partition、Materialized Table等新功能的应用前景。通过这些优化,系统不仅简化了复杂度,还提升了实时与离线处理的灵活性和效率。
853 3
Flink基于Paimon的实时湖仓解决方案的演进
|
10月前
|
SQL 监控 关系型数据库
用友畅捷通在Flink上构建实时数仓、挑战与最佳实践
本文整理自用友畅捷通数据架构师王龙强在FFA2024上的分享,介绍了公司在Flink上构建实时数仓的经验。内容涵盖业务背景、数仓建设、当前挑战、最佳实践和未来展望。随着数据量增长,公司面临数据库性能瓶颈及实时数据处理需求,通过引入Flink技术逐步解决了数据同步、链路稳定性和表结构差异等问题,并计划在未来进一步优化链路稳定性、探索湖仓一体架构以及结合AI技术推进数据资源高效利用。
755 25
用友畅捷通在Flink上构建实时数仓、挑战与最佳实践

相关产品

  • 实时计算 Flink版
  • 推荐镜像

    更多
    下一篇
    oss云网关配置