来源:Apache Flink
摘要:本文整理自曹操出行实时计算负责人林震基于 Hologres+Flink 的曹操出行实时数仓建设的分享,内容主要分为以下六部分:
1. 曹操出行业务背景介绍
01
曹操出行业务背景介绍
曹操出行创立于 2015 年 5 月 21 日,是吉利控股集团布局“新能源汽车共享生态”的战略性投资业务,以“科技重塑绿色共享出行”为使命,将全球领先的互联网、车联网、自动驾驶技术以及新能源科技创新应用于共享出行领域,以“用心服务国民出行”为品牌主张,致力于打造服务口碑最好的出行品牌。
作为一家互联网出行平台,曹操主要提供了网约车、顺风车和专车等出行服务。其中,打车是其核心业务之一。整体业务过程大致如下: 首先,用户在我们的平台上下单,然后曹操平台会给司机进行订单的派发,司机接到订单后,会进行履约服务。结束一次订单服务后,乘客会在平台上进行支付。

02
曹操出行业务痛点分析

上图是一个传统 lambda 架构,在这个架构中主要会分做实时数据流和离线数据流。在实时链路中,业务数据是存放在 RDS 中,并通过 Binlog 以 Canal 同步的方式进入 Kafka ,同时应用的日志数据也会通过实时采集的方式进入到 Kafka 。数据准备工作完成后,在 Kafka 中构建实时数据仓库。整个实时数仓基于数仓分层理念进行构建的,主要包括原始数据层(ODS)、数据明细层(DWD)、数据汇总层(DWS)和应用数据层(ADS)。这些层次通过 Flink Streaming SQL 进行串联,实现数据的流转和处理。
在离线链路中,数据主要是通过 DataX 定时同步任务将 RDS 中的数据同步到 HDFS 。同时应用的日志会通过定时任务同步到 HDFS ,整个离线数仓以 Spark Sql 定时调度任务去逐层执行。数据在离线数仓中会以不同的数据域去组织满足不同粒度的数据计算,最终数据会通过 Flink Sink 以及离线同步工具写到不同的数据应用组件中。同时,为了保证某些应用场景中数据的一致性,可能需要对离线和实时两条链路的数据进行合并处理和加工。

基于曹操出行数据生产成本和研发诉求,针对传统 lambda 架构中可以看到一些问题:
为了适配不同应用场景,我们在架构中使用了非常丰富的数据组件。
研发成本非常高,不仅在实时链路中进行研发和处理,而且还需额外研发一套离线的数据链路。
运维效率较低,由于整个实时数仓是构建在 Kafka 上的,因此在数据探查以及进行数据订正就会变得非常困难。
资源成本较大,主要体现在几方面:组件多,需要专门安排人员进行运维和管理;一些需要精准一致性的场景需求,需在两个数据链路中做数据的同步和合并计算;在某些计算场景中,需要 Flink 维护大状态进行处理,也造成额外性能问题和资源的浪费。
另外从公司开发者使用的角度,我们对实时数仓提出了以下几点诉求:
统一的组件来满足不同数据应用场景。
复杂的实时数据链路中保障高效的数据订正。
能克服在 Flink 中一些大状态下的技术难点。
03
Hologres+Flink 构建企业级实时数仓
曹操出行作为 Hologres 的深度用户,在前期调研与测试阶段,我们对 Hologres 的相关能力做了比较详细的分析,主要有以下优势:
具备 OLAP 分析能力
具备高并发点查能力
具备半结构化日志分析能力
具备基于 PostGIS 的扩展能力,支持空间地理信息信息数据的分析与使用,对于曹操出行的业务属性来说非常重要。
契合数仓分层结构理念(可以像离线数仓一样去构建分层体系,数据实时流动,实时存储)
Flink Streaming 生态高度融合 (Flink CDC 组件集成,Flink Catalog 集成)
统一的 Ad-hoc 能力,能以外表加载离线数仓中数据进行湖仓加速和联邦分析
全链路低时延
多流 Join 场景很好的提供数据打宽的能力,支持主键模型和行级,局部字段更新的能力
Count Distinct 大状态精确去重场景的支持


在 Hologres 中 Binlog 也是一种物理表,其跟原表的主要区别是内置的几种自身结构,包含自身递增序列,数据修改类型以及数据修改时间,Binlog 本质上也是分 shard 进行存储,所以也为一种分布式表,并且在 WAL 之前生成,因此在数据上可以与原表保证强一致性。
其次 Hologres Binlog 修改类型也还原了 Flink 中四种 RowKind 类型。在数据更新过程中会产生两条更新记录(update_before,update_after),并且保证了更新记录是一个连续的存储。右边展示中,写入一个数据一个pk1,然后再写入一个 pk2 数据,pk2 的数据再做一次更新,那么在 Binlog 中它会产生4条数据结果。
4. Hologres 数据模型介绍

04
曹操出行实时数仓实践



接下来是我们对聚合场景的优化,针对许多预聚合计算场景,我们将其统一收敛到 Rollup 计算模型中,主要解决以下问题:
在 Flink 聚合场景中经常会出现状态兼容性的问题
整个数据的复用性非常差,研发人员收到新的需求,例如新的指标或者新增维度粒度时,为了不影响生产数据的稳定性,新增需求需要构建新任务,导致任务管理混乱。
因此曹操出行主要进行了两点优化:
构建 MapSumAgg 算子,MapSum 主要通过对 SumAgg 算子做了重新设计,使之能够支持 Map 内部结构的求和逻辑
对 Grouping Sets 进行动态配置化,这样 Grouping Sets 动态增加维度粒度,使整个任务在不重启的情况下也能自动去做自适应
结合这两点,把已有的指标放入 map 结构中进行封装,这样在不改变原有的算子状态,也可以得到很好的处理。在下游中可以针对不同维度组合,指标集合做好选择,然后由同步工具做实时的数据路由,为下游提供服务。

对于第二个聚合场景的优化,是对精确去重场景的拆分。在前面例子中,我们把 Count Distinct 的精确去重做了剥离,主要解决两个问题:
维度爆炸问题。在 Flink 的回撤机制下使用精确去重时,需要存储全量状态。然而,在 Cube 场景中,这种状态的爆炸式增长对于 Flink 的可扩展性是一个挑战。
查询灵活性问题。解决思路是通过 Hologres 去构建细粒度的 RoaringBitmap 存储方案。
具体流程如下:首先, 在 Hologres 中构建自身序列的 UID 维表,然后在主表中通过反差逻辑将 UID 的自身序列反查出来。接下来,在 Flink 中进行 Group by 操作,并进行聚合计算,得出 RoaringBitmap 的结果。最后,将结果写入 Hologres 的 DWS 层,形成轻度汇总表用于 UV 计算。这种方案既能解决应用端在灵活维度查询时的高效性需求,又能解决 Flink 中维度爆炸的问题。


元数据血缘的改造主要解决了以下问题:
Schema 的演进提供了一个更便利的管控
解决实时链路发布流程中的依赖链问题。
对任务元数据信息进行有效的管理
曹操出行主要进行以下措施来实现上述目标:
Flink Catalog 集成,在元数据中去整合 Hologres 的 Catalog,也支持 Kafka Topic 表中自定义 Catalog,支持多版本 schema 和任务数据的多版本,提供更灵活的数据处理能力。
Kafka Source 和 Kafka Sink 的改造。结合整合整个上线发布的流程,对于数据的版本信息,是通过 Kafka Sink 对 Header 进行记录,Kafka Source 对 header 的版本信息进行过滤,从而把数据版本引入到整个上下游的链路,提供上下游数据灵活的迭代。这种做法的好处是,在整个链路中可以感知到下游数据的使用情况,帮助用户快速定位是否还有任务依赖于某个版本的数据,图片主要是展示一个开发流程中元数据的集成。


7.数据订正能力建设

05
曹操出行业务成果分析

对比原有 Lamada 架构,Hologres + Flink 整体架构更加清晰,使用数据组件大大减少
整体技术复杂难度降低,原先为了解决数据一致性问题,数据需要在不同的异构存储和异构链路中来回传输和计算,整个技术复杂度较高
整个开发模式变得简单易用,大大缩短人力周期
数据实时模型分层非常清晰,整体下游复用性以及使用门槛大幅度降低
由于数据存储在 Hologres 之上,因此数据探查更加便捷,数据订正难易程度大幅度减少。
组件维护成本减少
数据的离线存储和实时存储,从双份存储降低到一份存储,以及降低了数据在异构存储之间的同步与计算成本
解决在 Flink 中各类计算场景中大状态的资源成本,减少了计算开销并提升了处理性能。
06
未来展望

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70027827/viewspace-3004152/ ,如需转载,请注明出处,否则将追究法律责任。