Flink 和 ClickHouse 分别是实时计算和(近实时)OLAP 领域的翘楚,也是近些年非常火爆的开源框架,很多大厂都在将两者结合使用来构建各种用途的实时平台,效果很好。关于两者的优点就不再赘述,本文来简单介绍笔者团队在点击流实时数仓方面的一点实践经验。
所谓点击流(click stream),就是指用户访问网站、App 等 Web 前端时在后端留下的轨迹数据,也是流量分析(traffic analysis)和用户行为分析(user behavior analysis)的基础。点击流数据一般以访问日志和埋点日志的形式存储,其特点是量大、维度丰富。以我们一个中等体量的普通电商平台为例,每天产生约 200GB 左右、数十亿条的原始日志,埋点事件 100+ 个,涉及 50+ 个维度。
按照 Kimball 的维度建模理论,点击流数仓遵循典型的星形模型,简图如下。
点击流实时数仓的分层设计仍然可以借鉴传统数仓的方案,以扁平为上策,尽量减少数据传输中途的延迟。简图如下。
Flink 框架的异步 I/O 机制为用户在流式作业中访问外部存储提供了很大的便利。针对我们的情况,有以下三点需要注意:
可以通过 JDBC(flink-connector-jdbc)方式来直接写入 ClickHouse,但灵活性欠佳。好在 clickhouse-jdbc 项目提供了适配 ClickHouse 集群的 BalancedClickhouseDataSource 组件,我们基于它设计了 Flink-ClickHouse Sink,要点有三:
当前我们仅实现了 DataStream API 风格的 Flink-ClickHouse Sink,随着 Flink 作业 SQL 化的大潮,在未来还计划实现 SQL 风格的 ClickHouse Sink,打磨健壮后会适时回馈给社区。另外,除了随机路由,我们也计划加入轮询和 sharding key hash 等更灵活的路由方式。
还有一点就是,ClickHouse 并不支持事务,所以也不必费心考虑 2PC Sink 等保证 exactly once 语义的操作。如果 Flink 到 ClickHouse 的链路出现问题导致作业重启,作业会直接从最新的位点(即 Kafka 的 latest offset)开始消费,丢失的数据再经由 Hive 进行回填即可。
ClickHouse 集群扩容之后,数据的重平衡(reshard)是一件麻烦事,因为不存在类似 HDFS Balancer 这种开箱即用的工具。一种比较简单粗暴的思路是修改 ClickHouse 配置文件中的 shard weight,使新加入的 shard 多写入数据,直到所有节点近似平衡之后再调整回来。但是这会造成明显的热点问题,并且仅对直接写入分布式表才有效,并不可取。
因此,我们采用了一种比较曲折的方法:将原表重命名,在所有节点上建立与原表 schema 相同的新表,将实时数据写入新表,同时用 clickhouse-copier 工具将历史数据整体迁移到新表上来,再删除原表。当然在迁移期间,被重平衡的表是无法提供服务的,仍然不那么优雅。如果大佬们有更好的方案,欢迎交流。
关于 Flink 和 ClickHouse 等组件的配置、调优、延迟监控、权限管理等知识,笔者在之前的博客中多少讲到过,更多详情请见作者原文链接:
领取专属 10元无门槛券
私享最新 技术干货