赞
踩
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
原文大佬的这篇Doris+Flink构建实时数仓的实战文章整体写的很深入,这里直接摘抄下来用作学习和知识沉淀。
本篇文章介绍如何基于Doris和Flink快速构建一个极速易用的实时数仓,包括数据同步、数据集成、数仓分层、数据更新、性能提升等方面的具体应用方案。
先介绍一下传统的数据架构如何设计的、又存在哪些痛点问题。下图为传统的数据架构,如果从数据流的角度分析传统的数据处理架构,会发现从源端采集到的业务数据和日志数据,主要分为实时和离线两条链路:
从技术架构的角度对传统数据技术栈进行分析,会发现为了迎合不同场景的需求,往往会采用多种技术栈,例如对于 OLAP 场景的多维分析,一般使⽤ Doris 或 Kylin、 Druid。除此之外,为应对半结构化数据的分析需求,例如日志分析与检索场景,通常会使⽤ ES 进行分析;面对高并发点查询的 Data Serving 场景会使⽤ HBase等。其中涉及到的数据组件有数十种,高昂的使用成本和组件间兼容、维护及扩展带来的繁重压力成为企业必须要面临的问题。
从上述介绍即可知道,传统的数据架构存在几个核心的痛点问题:
在此背景下,需要构建⼀个“极速、易用、统一、实时”的数据架构来解决这些痛点:
采取Doris和Flink 来构建极速易用的实时数仓,具体架构如下图所示。多种数据源的数据经过flink cdc 集成或flink job加工件处理后,入库到Doris或者Hive等湖仓中,最终基于Doris提供统一的查询服务。
在数据同步上,通过Flink CDC将RDS的数据实时同步到Doris。通过Routine Load将kafka等消息系统的数据实时同步到Doris,在数仓分层上,ODS层通常选择明细模型构建,DWD层可以通过SQL调度任务,对ODS数据抽取并获取,DWS和ADS层则可以通过物化视图和Rollup进行构建。在数据湖上, Doris ⽀持为 Hive、Iceberg 、Hudi 以及Delta Lake(todo)提供联邦分析和湖仓加速的能⼒。在数据应用上,Apache Doris 既可以承载批量数据加工处理的需求,也可以承载高吞吐的 Ad-hoc(数据探索) 和高并发点查询等多种应⽤场景。
在全量数据和增量的同步上,采取了Flink CDC来实现。其原理非常简答,Flink CDC实现了基于Snapshot的全量数据同步,基于 BinLog的实时增量数据同步。全量数据同步和增量数据同步可以自动切换,因此在数据迁移过程中,只需要配置好同步的表即可。当Flink任务启动时,优先进行历史表的数据同步,同步完成后自动切换成实时同步。
如何保证数据一致性是大家重点关注的问题之一,那么在新架构是如何实现的呢?
数据⼀致性⼀般分为“最多⼀次” 、“⾄少⼀次”和“精确⼀次”三种模型。
- 最多⼀次(At-Most-Once):发送⽅仅发送消息,不期待任何回复。在这种模型中,数据的⽣产和消费过程中可能出现数据丢失的问题。
- ⾄少⼀次(At-Least-Once):发送⽅不断重试,直到对⽅收到为⽌。在这个模型中,⽣产和消费过程都可能出现数据重复。
- 精确⼀次(Exactly-Once):能够保证消息只被严格发送⼀次,并且只被严格处理⼀次。这种数据模型能够严格保证数据⽣产和消费过程中的准确⼀致性。
Flink CDC通过Flink Checkpoint 机制结合Doris两阶段提交可以实现端到端的Exactly Once语义,具体过程分为四步:
综上可知,利用 Flink CDC结合Doris 两阶段事务提交保证了数据写入一致性。需要注意的是,在该过程中可能遇到一个问题:如果事务预提交成功、但 Flink Checkpoint 失败了该怎么办?针对该问题,Doris 内部支持对写⼊数据进⾏回滚(Rollback),从⽽保证数据最终的⼀致性。
随着业务的发展,部分用户可能存在RDS Schema的变更需求。当RDS表结构发生变更时,用户期望Flink CDC不但能够将数据变化同步到Doris,也希望将 RDS 表结构的变更同步到 Doris,⽤户则无需担⼼ RDS 表结构和 Doris 表结构不⼀致的问题。
Apache Doris 1.2.0 已经实现了 Light Schema Change 功能,可满⾜ DDL 同步需求,快速⽀持 Schema 的变更。
Light Schema Change的实现原理相对简单,对数据表的加减列操作,不再需要同步更改数据文件,仅需要再FE中更新元数据即可,从而实现毫秒级的Schema Change 操作。由于 Light Schema Change 只修改了 FE的元数据,并没有同步给 BE。因此会产⽣ BE 和 FE Schema 不⼀致的问题。为了解决这种问题,我们对 BE 的写出流程进⾏了修改,具体包含三个⽅⾯。
(1)数据写入:FE会将 Schema 持久化到元数据中,当 FE 发起导⼊任务时,会把最新的 Schema 一起发给 Doris BE,BE 根据最新的Schema对数据进⾏写⼊,并与 RowSet 进⾏绑定。将该 Schema 持久化到 RowSet 的元数据中,实现了数据的各⾃解析,解决了写⼊过程中 Schema 不⼀致的问题。
**(2)数据读取:**FE ⽣成查询计划时,会把最新的 Schema 附在其中⼀起发送给 BE,BE 拿到最新的 Schema 后对数据进⾏读取,解决读取过程中 Schema 发⽣不⼀致的问题。
**(3)数据 Compaction:**当数据进⾏ Compaction 时,我们选取需要进⾏ Compaction 的 RowSet中最新的Schema作为之后RowSet 对应的 Schema,以此解决不同 Schema 上 RowSet 的合并问题
经过对 Light Schema Change 写出流程的优化后, 单个 Schema Chang 从 310 毫秒降低到了 7 毫秒,整体性能有近百倍的提升,彻底的解决了海量数据的 Schema Change 变化难的问题。
有了 上述Light Schema Change 的保证,Flink CDC 能够同时⽀持DML 和DDL 的数据同步。那么是如何实现的呢?
(1)开启 DDL 变更配置:在 Flink CDC 的 MySQL Source 侧开启同步 MySQL DDL 的变更配置,在 Doris 侧识别 DDL 的数据变更,并对其进⾏解析。
(2)识别及校验:当 Doris Sink 发现 DDL 语句后,Doris Sink 会对表结构进⾏验证,验证其是否⽀持 Light Schema Change。
(3)发起 Schema Change :当表结构验证通过后,Doris Sink 发起 Schema Change 请求到 Doris,从⽽完成此次 Schema Change 的变化。
解决了数据同步过程中源数据⼀致性的保证、全量数据和增量数据的同步以及 DDL 数据的变更后,一个完整的数据同步⽅案就基本形成了。
除了上文中所提及的基于 Flink CDC 进行数据增量/全量同步外,我们还可以基于 Flink Job 和 Doris 来构建多种不同的数据集成方式:
Doris针对不同场景,提供了不同的数据模型,分别为明细模型、聚合模型、主键模型。
在某些多维分析场景下,数据既没有主键,也没有聚合需求,Duplicate 数据模型可以满足这类需求。明细模型主要用于需要保留原始数据的场景,如日志分析,用户行为分析等场景。明细模型适合任意维度的 Ad-hoc 查询(即席查询)。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有 Key 列)。
在企业实际业务中有很多需要对数据进行统计和汇总操作的场景,如需要分析网站和 APP 访问流量、统计用户的访问总时长、访问总次数,或者像厂商需要为广告主提供广告点击的总流量、展示总量、消费统计等指标。在这些不需要召回明细数据的场景,通常可以使用聚合模型,比如上图中需要根据门店 ID 和时间对每个门店的销售额实时进行统计。
在某些场景下用户对数据更新和数据全局唯一性有去重的需求,通常使用UNIQUE KEY 模型。在 UNIQUE 模型中,会根据表中的主键进⾏Upsert 操作:对于已有的主键做 Update 操作,更新 value 列,没有的主键做 Insert 操作,比如图中我们以订单id为唯一主键,对订单上的其他数据(时间和状态)进行更新。
由于数据量级普遍较大,如果直接查询数仓中的原始数据,需要访问的表数量和底层文件的数量都较多,不同层级对数据或指标做不同粒度的抽象,通过复用数据模型来简化数据管理压力,利用血缘关系来定位数据链路的异常,同时进一步提升数据分析的效率,在Doris 中可以通过以下多种思路来构建数据仓库分层:
通过INSERT INTO SELECT 可以将原始表的数据进行处理和过滤并写入到目标表中,这种SQL抽取数据的行为 一把是以微批形式进行(例如15分钟一次的ETL计算任务),通常发生在从ODS到dwd层数据的抽取过程中,因此需要借助外部的调度工具例如Dolphinscheduler等来对ETL SQL进行调度。
物化视图本质是一个预先计算的过程,可以在Base表上,创建不同的物化视图或Rollup来对Base表进行聚合计算。通常在明细层到汇总层(例如dwd层到dws层或 dws层到ads层)的汇聚过程中,可以使用物化视图,以此实现指标的高度聚合。同时物化视图的计算是实时进行的,因此站在计算的角度,也可以将物化视图理解为一个单表上的实时计算过程。
Doris 2.0将实现多表物化视图这一功能,可以将带有 Join 的查询结果固化以供用户直接查询,支持定时自动或手动触发的方式进行全量更新查询结果。基于多表物化视图这一功能的实现,可以做更复杂的数据流处理,比如数据源侧有 TableA、TableB、TableC,在多表物化视图的情况下,用户就可以将 TableA 和 TableB 的数据进行实时Join 计算后物化到 MV1 中。在这个角度上来看,多表物化视图更像一个多流数据实时 Join 的过程。
在实时数仓构建的过程中,还需面临高并发写入和实时更新的挑战,如何在亿级数据中快速找到需要更新的数据,并对其进行更新,⼀直都是大数据领域不断追寻的答案。
在Doris中通过Unique Key 模型来满足数据更新的需求,同时通过MVCC多版本并发机制来实现数据的读写隔离。当新数据写入时,如果不存在相同key的数据则会直接写入,如果有相同key的数据则增加版本,此时数据将多个版本的形式存在。后台会启动异步的Compaction进程对历史版本的数据进行清理,当用户在查询时,Doris会将最新版本对应的数据返回给用户,这种设计解决了海量数据的更新问题。
在Doris中提供了Merge-on-Read和Merge-on-Write两种数据更新模式。
在此我们以订单数据的写入为例介绍 Merge-on-Read 的数据写入与查询流程,三条订单数据均以 Append 的形式写⼊ Doris 表中:
Merge-on-Read的特点是写入速度比较快,但是在数据读取过程中由于需要进行多路归并排序,存在着大量非必要的CPU计算资源消耗和IO开销。
在1.2.0 版本中,Doris在原有的Unique Key数据模型上增加了 Merge-on-Write的数据更新模式。Merge-on-Write兼顾了写入和查询性能,在写入过程中引入了Delete Bitmap数据结构,使用Delete Bitmap标记Rowset中某一行是否被删除,为了保持Unique Key原有的语义,Delete Bitmap也支持多版本。另外使用了兼顾性能和存储空间的 Row Bitmap,将Bitmap中的MemTable一起存储在BE中,每个Segment会对应⼀个 Bitmap。
写入流程:
当查询到 Key 对应的 RowSet 后,便会覆盖 RowSet Key 对应的 Bitmap,接着在 Publish 阶段更新 Bitmap,从而保证批量点查 Key 和更新 Bitmap 期间不会有新的可见 RowSet,以保证 Bitmap 在更新过程中数据的正确性。除此之外,如果某个 Segment 没有被修改,则不会有对应版本的 Bitmap 记录。
查询流程:
Merge-on-Write该模式不需要在读取的时候通过归并排序来对主键进行去重,这对于高频写入的场景而言,大大减少了查询执行时的额外消耗。此外还能够支持谓词下推,并能够很好利用Doris丰富的索引,在数据IO层面就能够进行充分的数据裁剪,大大减少数据的读取量和计算量,因此在很多场景的查询中都有非常明显的性能提升。在真实场景的测试中,通过 Merge-on-Write可以在保证数万QPS的高频Upsert 操作的同时,可以实现性能 3-10 倍的提升。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
中…(img-WEGrDdFH-1715240270114)]
[外链图片转存中…(img-nCuJs5CY-1715240270115)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。