漫画趣解Flink实时数仓~
共 5822字,需浏览 12分钟
· 2022-07-27
我是Flink,最近我抑郁了~
1 引子(搬橡果)
过冬了,我和小伙伴灰灰开始屯年货。
今年劳动了大半年,我们收获了整整一车的橡果。众所周知,我们小松鼠们都喜欢把这些心爱的橡果放到储藏室。
于是今天起了个大早,开始搬运这些橡果。
![](https://filescdn.proginn.com/4bb356c491f1b3d2eb002a15b2dcbf9f/8ac955b79b17e847fce2888a053b7eba.webp)
不一会,灰灰突然对我说想要吃一颗昨天摘的灰色小橡果。
![](https://filescdn.proginn.com/0ddc3cf99acb460ca89cd09ec4c8e221/086ce3a42b7bdb2d12a3f98a57a8c35f.webp)
我望了望眼前堆积如山的年货,苦恼的摸了摸脑袋:等我搬到了那颗再给你。
![](https://filescdn.proginn.com/d6a30a75fdbfc73408e53646c299351d/87eebe0bbb4187641ebc3c7f8c0248db.webp)
灰灰很不开心,嘴里嘟囔着:为啥昨天不能一摘下来我们就搬呢?
我解释道: 我们每年都是攒够一车才一起搬的呀?
![](https://filescdn.proginn.com/36447abf8b6551b139e16c020ea1cf90/a100707bc796036a6688d6435402e71e.webp)
看着一边气鼓鼓的灰灰,我放缓了搬运的速度~
抬头望着高高的橡果堆叹了口气。一边搬运,一边翻找他要的那颗小橡果。。。
![](https://filescdn.proginn.com/ebb477071ac034a5bdf824a4aecb4166/70dd7907a972af2c0c21154267da9a7d.webp)
今天怕是搬不完了~
2 慢 OR 快?
总结下,在故事中我们遇到了几个小烦恼:
每次都是攒了整车橡果才开始搬运,无法 及时
拿到想要的灰色小橡果就算我 实时
搬运。之后再要其他小橡果,我还是不能快速找到
,完全记不住之前拿过哪些?放到了哪里?
关键词:速度慢、体量大、及时性差、 快速查找、可回溯。。
借由这个小故事,回归到本文主题。
这些关键词也是企业实时数仓建设
中常遇到的一些难点和诉求。
2.1 企业实时数仓建设诉求
大多数企业面临数据源多、结构复杂的问题,为了更好的管理数据和赋能价值,常常会在集团、部门内进行数仓建设。
其中一般初期的数仓开发流程大致如下:
获取数据源,进行数据清洗、扩维、加工,最终输出业务指标 根据不同业务,重复进行上述流程开发,即 烟囱式
开发。
![](https://filescdn.proginn.com/5f601fa5bb7bed5d19d4db64f88fa780/f95811cb82ec966a4c167569cb187472.webp)
可想而知,随着业务需求的不断增多,这种烟囱式
的开发模式会暴露很多问题:
代码耦合度高 重复开发 资源成本高 监控难
为此大量企业的数据团队开始着手数仓规划,对数据进行分层。
![](https://filescdn.proginn.com/ff1563fc4eaa01fc6532dba81c8adad1/5e51e9c257976145c726971f30958700.webp)
数据规整为层级存储,每层独立加工。整体遵循由下向上建设思想,最大化数据赋能。
数据源: 分为 日志数据
和业务数据
两大类,包括结构化和非结构化数据。数仓类型:根据及时性分为 离线
数仓和实时
数仓技术栈: 采集(Sqoop、Flume、CDC) 存储(Hive、Hbase、Mysql、Kafka、数据湖) 加工(Hive、Spark、Flink) OLAP查询(Kylin、Clickhous、ES、Dorisdb)等。
2.2 稳定的离线数仓
业务场景
要求每天出一个当日用户访问PV、UV流量报表,结果输出到业务数据库
早期规划中,在数据实时性要求不高的前提下,基本一开始都会选择建设离线数仓。
![](https://filescdn.proginn.com/c93aea9669aa9ab0cd9d46b66403ff66/10780c8e505bb77c084ee761335c9e36.webp)
1) 技术实现
使用Hive作为数据存储、计算技术栈 编写数据同步脚本,抽取数据到Hive的ODS层中 在Hive中完成dwd清洗加工、维度建模和dws汇总、主题建模 依赖调度工具(dophinScheduler)自动 T+1调度 olap引擎查询分析、报表展示
2) 优缺点
配合调度工具,能够自动化实现T+1的数据采集、加工等全流程处理。技术栈 简单
易操作Hive存储性能高、适合交互式查询 计算速度受Hive自身限制,可能因参数和数据分布等差异造成不同程度的数据 延迟
3) 改良
既然我们知道了Hive的运算速度比较慢,但是又不想放弃其高效的存储和查询功能。
那我们试试换一种计算引擎: Spark。
![](https://filescdn.proginn.com/a0183efc00a743e5b353147ebac13a70/44735a957a6c7b546726e4f8b1885f96.webp)
整体流程不变,主要是在ods->dwd->dws层的数据加工由Spark负责。效果是显而易见的,比Hive计算快了不少。
注意Spark是内存级计算引擎,需要合理规划内存大小,防止出现OOM(内存泄露)。
目前两种离线数仓均完美的实现了业务需求。领导第二天一看报表统计,结果皆大欢喜~
现在考虑换一种场景:不想等到第二天才能看到结果,要求实时展示指标,此时需要建设实时数仓。
3 冗余 OR 可回溯 ?
业务场景
实时统计每秒用户访问PV、UV流量报表,结果输出到业务数据库,并支持历史数据回看
既然要求达到实时效果,首先考虑优化加工计算过程。因此需要替换Spark,使用Flink计算引擎。
在技术实现方面,业内常用的实时数仓架构分为两种:Lambda
架构和Kappa
架构。
3.1 Lambda架构
顾名思义,Lambda架构保留实时、离线两条处理流程,即最终会同时构建实时数仓和离线数仓。
![](https://filescdn.proginn.com/e8570f3ff9e600a31bb44020dda1b995/102a3827e6d6ab112d0aefd1072df425.webp)
1) 技术实现
使用Flink和Kafka、Hive为主要技术栈 实时技术流程。通过实时采集程序同步数据到Kafka消息队列 Flink实时读取Kafka数据,回写到 kafka ods
贴源层topicFlink实时读取Kafka的ods层数据,进行实时清洗和加工,结果写入到 kafka dwd
明细层topic同样的步骤,Flink读取dwd层数据写入到 kafka dws
汇总层topic离线技术流程和前面章节一致 实时olap引擎查询分析、报表展示
2) 优缺点
两套技术流程,全面保障实时性和历史数据完整性 同时维护两套技术架构,维护成本高,技术难度大 相同数据源处理两次且存储两次,产生大量数据冗余和操作重复 容易产生数据不一致问题
3) 改良
针对相同数据源被处理两次
这个点,对上面的Lambda架构进行改良。
![](https://filescdn.proginn.com/091d8c33f0a4caab140f22ffbb021a85/4ee41707cbbc927dc474f985a4d4e352.webp)
通过将实时技术流的每一层计算结果定时刷新到离线数仓中,数据源读取唯一。大幅减少了数据的重复计算,加快了程序运行时间。
总结: 数据存储、计算冗余;历史数据可追溯
3.2 Kappa架构
为了解决上述模式下数据的冗余存储和计算的问题,同时降低技术架构复杂度,这里介绍另外一种模式: Kappa架构。
![](https://filescdn.proginn.com/1628f74bbeea66af699720f1ec19599b/4b0368f02b539c6a8776f75d55681559.webp)
1) 技术实现
使用Flink和Kafka为主要技术栈 实时技术流和Lambda架构保持一致 不再进行离线数仓构建 实时olap引擎查询分析、报表展示
2) 优缺点
单一实时数仓,强实时性,程序性能高 维护成本和技术栈复杂度远远低于Lambda架构 源头数据仅作为实时数据流被计算、存储,数据仅被处理一次。 数据回溯难。依赖Kafka存储,历史数据会丢失 olap查询难。Kafka需要引入其他对接工具实现olap查询,Kafka天生不适合olap分析。
总结: 数据存储计算仅一次;历史数据回溯难
总体而言,第一种Lambda架构虽然有诸多缺点,但是具备程序稳健性和数据完整性,因此在企业中用的会比较多。
相反Kappa架构用的比较少。因为Kappa架构仅使用Kafka作为存储组件,需要同时满足数据完整性和实时读写,这明显很难做到。
Kappa架构的实时数仓道路将何去何从?
4 数据湖&实时数仓
我们明白,Kafka的定位是消息队列,可作为热点数据的缓存介质,对于数据查询和存储其实并不适合。
如果能够找到一个替代Kafka的实时数据库就好了。。
预期要求
1)能够支持数据回溯和数据更新
2)实现数据批流读写,支持实时接入
4.1 数据湖技术
近些年,随着数据湖技术的兴起,仿佛看到了一丝希望。
![](https://filescdn.proginn.com/dd5298b1be0c382dfad810e5d222b1d4/4f9ebb430be81f7ffbb510a4b1208621.webp)
目前市场上最流行的数据湖为三种: Delta、Apache Hudi和Apache Iceberg。
其中Delta和Apache Hudi
对于多数计算引擎的支持度不够,特别是Delta完全是由Spark衍生而来,不支持Flink。
其中的Iceberg,Flink是完全实现了对接机制。看看其具备的功能:
基于 快照
的读写分离
和回溯流批统一
的写入和读取非强制绑定计算引擎 支持 ACID
语义支持表、分区的 变更
特性
4.2 kappa架构升级
因此考虑对Kappa架构进行升级,使用Flink + Iceberg(Hudi)技术架构,可以解决Kappa架构中的一些问题。
![](https://filescdn.proginn.com/35216c9ba7910eed841672dde3f470b6/b19e4a0331306dcdc513d4ae7728da63.webp)
存储介质由Kafka换成Iceberg(Hudi),其余技术栈保持不变 Flink读取源头Kafka数据,结果存储到Iceberg ods层 继续执行后续的ods->dwd->dws层计算、结果存储 Iceberg(Hudi)支持流批一体查询,过程中支持olap查询 实时olap引擎查询分析、报表展示
目前Flink社区关于Iceberg(Hudi)的建设已经逐渐成熟,其中很多大厂开始基于Flink + Iceberg(Hudi)打造企业级实时数仓。
更多实时数仓问题,可以咨询我的wx: youlong525.
5 电商零售实时数仓实战
纸上得来终觉浅,这里简单介绍一下老兵之前做过的实时数仓案例。
使用的技术栈可能有点老,主要探讨下建设思路。
5.1 技术架构
![](https://filescdn.proginn.com/c700badc3f4d8570f6be8c541ab5f4d2/61886325e1737b740bd0ee8b0413cb38.webp)
系统整体采用Flink + Spark + Kafka为主要技术栈,由底向上构建电商零售实时数仓,最终提供统一的数据服务。
1)底层使用Flink CDC
技术实时抽取源数据,包括业务系统
和第三方埋点
数据(客户中心、营销中心、销售中心)。
// data格式
{
"data": [
{
"id": "13",
"order_id": "6BB4837EB74E4568DDA7DC67ED2CA2AD9",
"order_code": "order_x001",
"price": "135.00"
}
]
}
// flink cdc (示例)
CREATE TABLE order_detail_table (
id BIGINT,
order_id STRING,
order_code STRING,
price DECIMAL(10, 2)
) WITH (
'connector' = 'kafka',
'topic' = 'order_binlog',
'properties.bootstrap.servers' = 'localhost:9092',
'properties.group.id' = 'group001',
'canal-json.ignore-parse-errors'='true'
);
2)数据源经过计算引擎和决策引擎转换,构建实时明细
、实时轻度汇总
、实时高度汇总
模型,即对应数仓分层: DWD、DWS、ADS层。
初步规划技术栈为Spark Streaming + Kafka。后期因实时性要求,改为Flink + Kafka,满足秒级响应。
![](https://filescdn.proginn.com/ffb8facfcc2f7946da6b4f214ac7418b/2d7300a4cac89363285ae2a48294940e.webp)
3)构建完实时数仓模型后,数据转存至存储介质
。包括ES、Redis、Mysql、Kafka等,并最终向外提供API共享服务访问。
// 存储介质API服务
val esServices = new EsHandler[BaseHandler](dataFlows)
val kafkaServices = new KafkaHandler[BaseHandler](dataFlows)
val redisServices = new RedisHandler[BaseHandler](dataFlows)
val jdbcServices = new JDBCHandler[BaseHandler](dataFlows)
esServices.handle(args)
kafkaServices.handle(args)
redisServices.handle(args)
jdbcServices.handle(args)
4)最终向外提供API服务,为企业的智能推荐
、会员画像
、数据挖掘
、营销大屏
等应用服务提供数据支撑。
5.2 数据流程
![](https://filescdn.proginn.com/2cae1e04788a23812f3ccc8b2ff5bf64/8b09488007d7d7981f2601050b2d39d6.webp)
整体从上而下,数据经过采集
-> 数仓明细加工
、汇总
-> 应用
步骤,提供实时数仓服务。
这里列举用户分析的数据流程和技术路线:
采集用户行为数据,统计用户曝光点击信息,构建用户画像。
![](https://filescdn.proginn.com/c75438cc0c0dfa886f42c45f83e6a6c9/673e8f66932ff9f08758602e1aed1e8d.webp)
6 实时数仓的优化与总结
1)实时数仓到底是Lambda架构还是Kappa架构好?
这个没有标准答案。这里给个建议:一般中小型
项目或需要保证历史数据
的完整性,建议使用Lambda架构构建,提供离线流程保障。目前Kappa架构用的不多,受场景和实时技术栈因素影响。
2)数据丢失怎么办?
如果是数据源丢失,可以重新消费
(offset位置);如果是Flink窗口数据延迟:可手动调大延迟时间
,延缓窗口关闭;或者使用侧输出流
保存延迟数据,再合并处理;也可以延迟数据写入存储介质
,后续统一处理。
3)实时计算中数据重复怎么办?
内存去重:数据量不大建议使用flink的 state
结构或者借助bitmap
结构稍微大点可以用 布隆过滤器
或hyperlog(借助工具)外部介质(redis或hbase)设计好 key
实现自动去重,存在存储成本
4)如何进行多条实时流JOIN
Flink内部提供JOIN算子操作,包括JOIN、window JOIN、Interval Join和connect等算子,详情请查看我的Flink双流JOIN文章。
5)实时任务和离线任务怎么调度
给YARN任务打上标签,将离线和实时分开,提交作业时指定Lable;同时调整Yarn的调度参数,合理分配多container执行。
--END--
非常欢迎大家加我个人微信,有关大数据的问题我们在群内一起讨论
长按上方扫码二维码,加我微信,拉你进群