Hologres + Flink 流式湖仓建设
- [1 Flink + Hologres 特性](#1 Flink + Hologres 特性)
-
- [1.2 实时维表 Lookup](#1.2 实时维表 Lookup)
- [1.3 高性能实时写入与更新](#1.3 高性能实时写入与更新)
- [1.4 多流合并](#1.4 多流合并)
- [1.5 Hologres 作为 Flink 的数据源](#1.5 Hologres 作为 Flink 的数据源)
- [1.6 元数据自动发现与更新](#1.6 元数据自动发现与更新)
- [2 传统实时数仓分层方案](#2 传统实时数仓分层方案)
-
- [2.1传统实时数仓分层方案 1:流式 ETL](#2.1传统实时数仓分层方案 1:流式 ETL)
- [2.2 传统实时数仓分层方案 2:定时调度](#2.2 传统实时数仓分层方案 2:定时调度)
- [2.3 传统实时数仓分层方案 3:物化视图](#2.3 传统实时数仓分层方案 3:物化视图)
- [3 Hologres+Hologres 的 Streaming Warehouse 方案](#3 Hologres+Hologres 的 Streaming Warehouse 方案)
-
- [3.1 hologres特性](#3.1 hologres特性)
-
- [3.1.1 业务场景能力丰富](#3.1.1 业务场景能力丰富)
- [3.1.2 一站式实时开发能力](#3.1.2 一站式实时开发能力)
- [3.1.3 解决的痛点问题](#3.1.3 解决的痛点问题)
- [3.2 Hologres Binlog 支持](#3.2 Hologres Binlog 支持)
- [3.3 Hologres 数据模型介绍](#3.3 Hologres 数据模型介绍)
- [4 Hologres+实时数据湖](#4 Hologres+实时数据湖)
- [4.1 流式湖仓分层建模](#4.1 流式湖仓分层建模)
1 Flink + Hologres 特性
holo在实时数仓领域非常受欢迎,一般搭配flink+hologres来做实时数仓,中间分层用holo,上下游一般依赖于holo的binlog来下发数据
1.2 实时维表 Lookup
Hologres 作为 Flink 的实时维表,相比其他维表具有以下优势:
- 维表百万 RPS 查询。
通过 Hologres 行存表主键点查的能力,支持非常高 RPS 的查询,更容易达到百每秒百万单次查询,我们内部存在一些业务甚至可以到达几千万和上亿次的查询。
-
维表实时可更新。
可以实现更新维表及其中的一部分字段,降低运维难度,提升效率。
-
支持1对N点查(Prefix Scan)。
不仅支持一对一查询,更支持一对多查询。例如我们在保险客户里面,需要根据身份证查询有哪些保单,一个人可能会对应多张保单,这种一对 N 的查询 Hologres 可以非常友好的支持。
-
支持 InsertIfNotExist。
在一般维表进行查询时,查到就返回,查不到就返回空,但通过这个能力,Hologres 可以做到在查询不到数据时插入一则数值,再把插入值返回。这个功能可以用来玩转流量分析场景的精确 UV 查询,通过 RoaringBitmap 画像方案,让千亿级别的画像分析从分钟级缩减到秒级。
1.3 高性能实时写入与更新
Flink 可以高性能实时写入 Hologres,数据写入即可查,右边是我们一年前的实测数据,可以看到在 128CU 的配置下,当写入表无主键,大概每秒钟能写 230 万条;当写入表有主键,主键冲突丢弃新行,每秒写入可达 200 万条;一般来说,表更新需要反查,那会随着数据量增大,更新性能会下降,Hologres 对已经拥有 20 亿条数据的表做更新,也能达到每秒钟 70 万条的更新性能。这种实时写入与更新的性能,非常合适结合 Flink 实现大量的更新和删除。
Hologres 具有很强的更新能力的同时,还支持宽表的局部列更新,在一定程度上替代 Flink 的多流 Join,于此同时,也针对更深的业务场景做了一系列细致的优化,满足业务更深入细致的需求。例如业务的上游数据有时候是乱序的,1 点钟生产数据与 1 点 05 分也会生产数据,我们希望 1 点 05 分生产的数据覆盖之前的数据,因为数据从业务时间上来说,肯定是希望后面的数据覆盖前面。但是因为整个计算链路的不确定性,它会使得有可能 1 点 05 分这个数据先到,1 点钟那个数据后到的,如果直接盲写就会变成把 1 点钟的数据覆盖了 1 点 05 分的数据。但 Hologres 在这种情况下不会做这个覆盖,即使上游乱序了,也能存储到最新的数据,保证上下游数据的一致性。
最后在 Flink 还未发布的 1.19 版本,Hologres 引入了一种称之为叫 Fixed Copy 的写入模式,这个模式相比于现在的写入模式,写入性能会更好,CPU 资源也省出更多。
Hologres 的存储架构基于分布式存储系统,并在其上构建了存储引擎。在底层,Hologres 使用了分布式存储系统来管理数据的存储和分布。在此之上,存储引擎包括一些关键组件,如 Block Cache、Shard ,每个 Shard 中包含了多个 Tablet 和 Write-Ahead Log(WAL)。
市面上主流的数据湖产品通常采用 LSM(Log-Structured Merge)架构。
主流数据主键模型更新模式有 Copy On Write 和 Merge On Read,这两种场景都有各自的问题:
- Copy On Write 具有写放大的问题,数据的延迟会比较高。
- Merge On Read(读时合并)模式在读取数据时需要进行大量的数据合并操作,因此读取性能可能较差。
在 Hologres 中,行存使用 Merge On Read 方式,列存主要基于 Merge On Write。
下面主要介绍下在基于 Merge On Write 这种模式时,一条数据在进入 Hologres 中,它首先到达 WAL Manager(Write-Ahead Log 管理器),同时也会进入到 Memtable(内存表)。在 Memtable 中,主要存储三类数据:数据文件、删除标志文件(例如基于 RoaringBitmap 的文件)和索引文件。当 Memtable 数据积累到一定阶段后,会生成不可变的 Memtable,并通过异步线程定期将其刷新(flush)到 Data File(数据文件)中。通过这种架构,Hologres 能够兼顾行存和列存的优势,并通过适当的数据合并策略来提高性能和存储效率。
1.4 多流合并
除了刚刚维表 Join 以外,在流计算里面另一个痛点就是双流 Join,如果每一路都要保证完整的状态,从理论上来说,它就是一个成本很高的事情。我们这个方案并不是完全替代双流 Join,而是对于例如用户画像场景,有一个明确的 ID,然后希望基于这一个已有的 ID 去关联若干流的数据。在这种场景下,Hologres 就可以很简单的替代掉双流 Join,来实现一个更低成本的这样一个关联。
在画像场景里,我们要描述一个用户的画像或者一个商品的画像,有很多个维度,例如说一个用户,他的浏览习惯是什么,他的履约习惯是什么,他的退货习惯是什么等等,可以从各种维度去看这个客户,然后我们要去给用户画一个画像,判断他到底属于哪一类用户。进行分类的时候,首先我们肯定希望知道这个用户的所有信息,会以用户 ID 作为粒度,把所有用户的信息全部放在一起,然后交给一个分类器去分类,判断这个用户到底属于哪一类,这就是用户画像的一种很经典的用法。
在没有 Hologres 产品加入之前,只能是 Flink 做双流 Join,用 Flink 形成这样一个宽的表,不同的维度有着不同的字段。但加入 Hologres 后,等于在 Hologres 里面建一张宽表,这张表里面它的主键就是用户 ID,然后不同的 Flink 任务去写不同的字段。这并不是指一个任务去写所有整一行,是指每个任务仅仅写各自的几个字段,同一张表有着不同字段,这样的话利用 Hologres 局部更新能力,相当于自动把用户的不同维度数据关联在了一起。
有了以上表现,Hologres 相对其他数仓产品比较有优势的一点是还支持了 Binlog。在这张宽表里面任何一个字段发生变化了以后,我们的 Binlog 里会把整个这一行的数据都给它吐出来,并在 Binlog 里显示出来,Flink 再去对接这个 Binlog,这时就知道这一行的最新情况是什么,可以为这个用户重新去计算画像。
1.5 Hologres 作为 Flink 的数据源
类似于传统数据库 MySQL 中的 Binlog 概念,Binlog 用来记录数据库中表数据的修改记录,比如 Insert/Delete/Update 的操作。在 Hologres 中,表的 Binlog 是一种强 Schema 格式的数据,Binlog 记录的序列号(BigInt),在单 shard 内单调递增,类似于 Kafka 中的 Offset 概念。通过 Flink 消费 Hologres Binlog,可以实现数仓分层间的全链路实时开发,在分层治理的前提下,缩短数据加工端到端延迟,同时提升实时数仓分层的开发效率。如上讲的画像分析场景,可以利用 Hologres 的逐步更新能力,加上 Flink 订阅 Hologres Binlog,可实现一个非常实时的用户画像分析,极大的降低分析成本。同时,当 Hologres 作为 Flink 的源表,Flink 通过流和批的模式都可以把这张表数据读出来。并且还可以自定义它的变化,例如全增量一体化读取,或者存量部分可以只读增量。
1.6 元数据自动发现与更新
Hologres 同时也对接了 Flink 的 catalog,直接可以读取元数据,Flink 的 create table as 和 create database as 这些语法,包括 schema evolution 都可以很好的适配。
2 传统实时数仓分层方案
2.1传统实时数仓分层方案 1:流式 ETL
第一种最经典的数仓分层方案是经过 Flink 加工后交给 Kafka,每加工一层就交给 Kafka,然后通过 Flink 再加工写到下一层 Kafka,写到最后通过 Flink 计算写到一个 KV 引擎对外提供服务,大家有时候不认为这是数仓分层,因为没有看见仓的概念,只存在一层层数仓数据加工。
Flink+Kafka 的方案有个很严重的问题:每一层 Kafka 数据就是给 Flink 用,它几乎不能执行其他事情,当然可以说用 Presto 对接一下 Kafka 的数据源,然后去查询数据是否出错是可以的,但也就存在这点用处。所以一般大家的做法就是在下面再接一个实时数仓,把所有的中间数据再同步一遍到实时数仓里,大家要查询数据分析数据,请用实时数仓,然后 Flink 消费就用 Kafka,这是一个经典架构,也非常成熟。但它的不足之处在于:各种同步数据要存两份,资源消耗很大,整个处理链路也很复杂;中间数据 Kafka 出了问题不便于排查,数据订正都比较麻烦。有时上游想要加上字段,下游需要更改更多的字段,不易响应 schema 动态变化。
2.2 传统实时数仓分层方案 2:定时调度
第二个方法就是用离线的方法:Flink 负责数据的清洗关联,清洗后的明细数据实时写入实时数仓形成 DWD 层,再由高频调度(分钟级别)构建 DWS/ADS 层,实现分钟级增量更新。
这样的好处是方案成熟简单,成本较低。但它的不足之处就是时效性差。因为 Flink 写进的数据是实时的,但是调度任务其实很难做到很高频调度,因为再往下做调度,比方 5 分钟的调度,实现的技术难度就一下子上去了。而数据量大时,5 分钟可能无法跑完数据,只能增量调度,将会更加计算复杂。所以许多用户在实际使用时候往往选择小时级别调度,实时数仓反而退化成了准实时数仓。
2.3 传统实时数仓分层方案 3:物化视图
第三种是物化视图的方案。其实本质上来说是前面两个方案的一个结合,Flink 负责数据的清洗关联,清洗后的明细数据实时写入实时数仓形成 DWD 层。在实时数仓内通过物化视图来加工 DWS 或者 ADS。现在大家各自提供的产品能力,基本都以批量物化方式运行,本质上是将调度任务内置化。Hologres 现在也在做实时的物化,在集团内已经在使用了,后续会开放到公共云,但这种实时物化视图对于技术的挑战还是比较较大的。
对于以上 3 种数仓分仓方案分析后,如果通过 Hologres 将 Kafka 全部替换,并使用行列共存本进行存储,就可以实现了数据在 Flink 和 Hologres 之间的传输。在统一了架构基础上,数仓每一层的数据都可以被查询和修改,并利用 Flink 和 Hologres 的资源强隔离能力,整套系统在生产环境中是高可用的。下面介绍基于 Flink+Hologres 的 Streaming Warehouse 方案详细内容。
3 Hologres+Hologres 的 Streaming Warehouse 方案
我们将全部的 Kafka 换成 Hologres,将 KV 也替换成 Hologres,整个链路中,数据从 Flink 写进来以后就可以直接传入 Hologres 里。行列共存表同时会存两份数据,一份行存,一份列存,他们两份是强一致的,没有任何额外的管理开销,甚至性能有些场景还会提升一点。相比之前 Kafaka 架构,Flink+Hologres 具有以下优势:
-
解决传统中间层 Kafka 数据不易查、不易更新、不易修正的问题,每一层都可查、可修正。
-
中间层数据不仅供 Flink 消费,所有人都可查其数据,甚至同时可以直接对外提供服务,对接 OLAP/ 在线服务等消费。
-
架构统一,减少运维成本,增加业务效率,并且模型统一。
基于 Flink+Hologres 的 Streaming Warehouse 方案,实时数仓 Hologres 主要提供了三大核心能力:
-
Binlog,支持表更新事件的 Binlog 透出能力,通过 Flink 消费 Hologres Binlog,实现数仓层次间全链路实时开发,满足分层治理的前提下,缩短数据加工端到端延迟。
-
行列共存,实现了数据在 Flink 和 Hologres 之间的传输,并使每一层的数据可以被查询和修改。
-
资源强隔离,在多种计算之间资源隔离,实现写入和读取隔离,查询和服务隔离。
3.1 hologres特性
3.1.1 业务场景能力丰富
- 具备 OLAP 分析能力
- 具备高并发点查能力
- 具备半结构化日志分析能力
- 具备基于 PostGIS 的扩展能力,支持空间地理信息信息数据的分析与使用,对于曹操出行的业务属性来说非常重要。
3.1.2 一站式实时开发能力
- 契合数仓分层结构理念(可以像离线数仓一样去构建分层体系,数据实时流动,实时存储)
- Flink Streaming 生态高度融合 (Flink CDC 组件集成,Flink Catalog 集成)
- 统一的 Ad-hoc 能力,能以外表加载离线数仓中数据进行湖仓加速和联邦分析
3.1.3 解决的痛点问题
- 全链路低时延
- 多流 Join 场景很好的提供数据打宽的能力,支持主键模型和行级,局部字段更新的能力
- Count Distinct 大状态精确去重场景的支持
3.2 Hologres Binlog 支持
在 Hologres 中 Binlog 也是一种物理表,其跟原表的主要区别是内置的几种自身结构,包含自身递增序列,数据修改类型以及数据修改时间,Binlog 本质上也是分 shard 进行存储,所以也为一种分布式表,并且在 WAL 之前生成,因此在数据上可以与原表保证强一致性。
其次 Hologres Binlog 修改类型也还原了 Flink 中四种 RowKind 类型。在数据更新过程中会产生两条更新记录(update_before,update_after),并且保证了更新记录是一个连续的存储。右边展示中,写入一个数据一个pk1,然后再写入一个 pk2 数据,pk2 的数据再做一次更新,那么在 Binlog 中它会产生4条数据结果。
3.3 Hologres 数据模型介绍
Hologres 主要分做行存引擎以及列存引擎,同时也支持行列共存场景。
-
在聚合场景中主要是用到列存的引擎,适合 OLAP 场景,复杂查询,统计以及关联等场景。同时也提供了非常丰富的索引,包括有:聚簇索引,位图索引,字典,以及基于时间序列的范围索引。
-
在 KV 场景中主要是用到行存的引擎,主要支持高并发组件查询。包括在 Flink 中做维表反查也是非常适合。
-
在订阅场景中主要是用到行存的引擎,主要在表属性中进行声明,比如说 Binlog 是否开启,Binlog 的 TTL。在订阅方的话,Hologres 支持 CDC 以及非 CDC 的模式。
-
在日志场景中针对聚合场景,主要是支持 JsonB 数据类型。JsonB 数据的写入过程中,Hologres 能够将其自动地平铺成列式的存储结构,同时它可以自动对数据内容做解析,对数据类型做泛化处理,数据格式的对齐,非常适合这种非稀疏场景,因此给聚合场景提供了分析的灵活性。
4 Hologres+实时数据湖
刚才我们主要讲的是实时数仓,也是当前我们客户使用最成熟的架构。随着流式湖仓需求的兴起,当前技术上主要分为两个发展方向。一方面是数据湖的存储,包括 Paimon 这样的新的流式数据湖存储,让数据入湖更加简单和高效。然后在查询分析层面,通过类似 Presto、Hologres 这样高效的查询分析引擎,进行更好的数据查询加速。Hologres 可以直接加速读写存储于 OSS 上的 Hudi、Delta、ORC、Parquet、CSV、SequenceFile 等格式类型的数据。
4.1 流式湖仓分层建模
回到我们刚才的数仓分层,Hologres、Paimon 都具备流式访问能力。如果基于 Hologres+Paimon 实现流式湖仓的分层,数仓各层都可以根据企业的存储成本、业务时效性进行灵活的调整。
-
数据存储 Paimon,Hologres 进行查询加速:提供分钟级时效性+秒级 OLAP 性能
例如针对一些时效性不敏感的 ODS 层数据,数据放在 Paimon 做存储,Hologres 进行查询加速,Hologres 能提供达到分钟级别时效性,相对来说成本更低,而且在和 Paimon 结合的加速查询,我们还在不断持续优化提升性能。
-
数据从 Paimon 写入 Hologres:提供秒级时效性+极致 OLAP 性能
例如针对一些对与查询性能要求比较高的 ADS 层,数据可以直接进入 Hologres,通过和 Flink 结合提供秒级时效性和极致的查询性能,查询时间可能为几十毫秒,这样成本相对更高一点,但是性能会快很多。
可以看到无论是和 Flink 深度集成构建企业级实时数仓,还是与 Paimon 结合在流式湖仓的探索优化,Hologres 在演进过程中始终紧紧围绕实时场景,不断提高实时数仓的性能、可用性、用户体验。未来,Hologres 也会持续通过一站式实时数仓的理念,替换企业纷繁芜杂的数仓架构,让实时数仓更加干净、友好、高效,并帮助企业不断降低成本,加速数字化转型升级。