第3章 实时数仓项目
3.1 为什么做这个项目
随着公司不断业务不断发展,产品需求和内部决策对于数据实时性要求越来越迫切,传统离线数仓T+1模式已经不能满足,所以需要实时数仓的能力来赋能。
3.2 项目架构
3.3 框架版本选型
和离线保持一致。
3.4 服务器选型
和离线保持一致。
3.5 集群规模
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
nn | nn | dn | dn | dn | dn | dn | dn | dn | dn |
rm | rm | nm | nm | nm | nm | nm | nm | nm | nm |
zk | zk | zk | |||||||
Kafka | Kafka | Kafka | |||||||
Flume | Flume | Flume | |||||||
Hive | Hive | ||||||||
MySQL | |||||||||
Spark | Spark | ||||||||
DS | DS | Datax | maxwell | ||||||
Hbase | Hbase | Hbase | |||||||
Flink | Flink | ||||||||
CK | CK |
3.6 项目建模
1)数据调研
(1)先和Java人员要表,表中最好有字段的描述或者有表和字段的说明文档。(项目经理帮助协调) =》 快速熟悉表中业务。梳理清楚业务线,找到事实表和维度表。
(2)和业务人员聊 =》 验证你猜测的是否正确
(3)和产品经理聊
需求:派生指标、衍生指标
派生指标 = 原子指标(业务过程 + 度量值 + 聚合逻辑) + 统计周期 + 统计粒度 + 业务限定
需求中的业务过程必须和实际的后台业务能对应上。
2)明确数据域
(1)用户域:登录、注册
(2)流量域:启动、页面、动作、故障、曝光
(3)交易域:加购、下单、支付、物流
(4)工具域:领取优惠卷、使用优惠卷下单、使用优惠卷支付
(5)互动域:点赞、评论、收藏
3)构建业务矩阵
用户、商品、活动、时间、地区、优惠卷
(1)用户域:
登录、注册
(2)流量域: √
启动、页面、动作、故障、曝光
(3)交易域:
加购、下单、支付、物流
(4)工具域:
领取优惠卷、使用优惠卷下单、使用优惠卷支付
(5)互动域:
点赞、评论、收藏
4)建模 至下而上
(1)ODS层
①存Kafka: topic_log\topic_db ,保持数据原貌不做处理
(2)DWD层 事实表
①事务型事实表
找原子操作
a)选择业务过程
选择感兴趣的业务过程。 产品经理提出的指标中需要的。
b)声明粒度
粒度:一行信息代表什么含义。可以是一次下单、一周下单、一个月下单。
如果是一个月的下单,就没有办法统计一次下单情况。保持最小粒度。
只要你自己不做聚合操作就可以。
c)确定维度
确定感兴趣的维度。 产品经理提出的指标中需要的。
例如:用户、商品、活动、时间、地区、优惠卷
d)确定事实
确定事实表的度量值。 可以累加的值,例如,个数、件数、次数、金额。
e)维度退化
通过Lookupjoin 将字典表中字段退化到明细表中
(3)DIM层 维度表
①维度数据存储Hbase,同时不做维度整合
5)指标体系建设 至上而下
(1)ADS层
需求、日活、新增、留存、转化率、GMV
(2)DWS层 聚合层
需求:派生指标、衍生指标
派生指标 = 原子指标(业务过程 + 度量值 + 聚合逻辑) + 统计周期 + 统计粒度 + 业务限定
例如,统计,每天各个省份手机品牌交易总额
交易总额 (下单 + 金额 + sum ) + 每天 + 省份 + 手机品牌
找公共的:业务过程 + 统计周期 + 统计粒度 建宽表
3.7 数据量
1)ODS层:
(1)用户行为数据(100g => 1亿条;1g => 100万条)
曝光(60g or 600万条)、页面(20g)、动作(10g)、故障 + 启动(10g)
(2)业务数据(1-2g => 100万-200万条)
登录(20万)、注册(100-1000);
加购(每天增量20万、全量100万)、下单(10万)、支付(9万)、物流(9万)、取消下单(500)、退款(500);
领取优惠卷(5万)、使用优惠卷下单(4万)、使用优惠卷支付(3万);
点赞(1000)、评论(1000)、收藏(1000);
用户(活跃用户100万、新增1000、总用户1千万)、商品SPU(1-2万)、商品SKU(10-20万)、活动(1000)、时间(忽略)、地区(忽略)
2)DWD层 + DIM层:
和ODS层几乎一致;
3)DWS层
轻度聚合后,20g-50g。
4)ADS层
10-50m之间,可以忽略不计。
3.8 项目中遇到哪些问题?
1)业务数据采集框架选择(FlinkCDC,Maxwell,Canal)
2)Dwd层新老访客修复、Dws层用户回流状态过大,选择状态后端不合理导致OOM
3)状态后端选择RocksDB导致链路延迟过高
4)Dws层读取外部数据库维度数据网络延迟过高导致反压
5)数据倾斜导致的反压
6)Flink SQL未设置TTL导致的OOM
7)改变程序拓扑结构,通过Savepoint恢复程序未指定算子Uid导致的报错
8)Kafka分区动态增加,Flink键控不到新分区数据导致数据丢失
9)某个Kafka分区没有数据,导致Flink下游水位线无法抬升,窗口无法关闭计算
10)Kafka的问题(挂了、丢了、重复了、积压了、乱序了、如何提高吞吐量)
11)Hbase的rowkey设计不合理导致的数据热点问题
12)Redis做旁路缓存,与Hbase的数据一致性问题
13)Flink写Clickhouse的精准一次性问题
14)Clickhouse的优化问题
3.9 实时---业务
3.9.1 数据采集到ODS层
1)前端埋点的行为数据为什么又采集一份?
时效性
Kafka保存3天,磁盘够:原来1T,现在2T,没压力
2)为什么选择Kafka?
实时写、实时读
=》 消息队列适合,其他数据库受不了
3)为什么用Maxwell?历史数据同步怎么保证一致性?
FlinkCDC在20年7月才发布
Canal与Maxwell区别:
Maxwell支持同步历史数据
Maxwell支持断点还原(存在元数据库)
数据格式更轻量
保证至少一次,不丢
4)Kafka保存多久?如果需要以前的数据怎么办?
跟离线项目保持一致:3天
我们的项目不需要,如果需要的话可以去数据库或Hive现查,ClickHouse也有历史的宽表数据。
3.9.2 ODS层
(1)存储原始数据
2个topic :
埋点的行为数据 ods_base_log
业务数据 ods_base_db
(2)业务数据的有序性: maxwell配置,指定生产者分区的key为 table
3.9.3 DWD+DIM层
1)存储位置,为什么维度表存HBase?
事实表存Kafka、维度表存HBase
基于热存储加载维表的Join方案:
随机查
长远考虑
适合实时读写
2)埋点行为数据分流
(1)修复新老访客(选择性):以前是前端试别新老访客,不够准确
(2)分流:侧输出流
分了3个topic: 启动、页面、曝光
(3)用户跳出、独立访客统计
3)业务数据处理
(1)动态分流:FlinkSQL读取topic_base_db数据,过滤出每张明细表写回kafka
(2)订单预处理表设计:双流join,使用leftjoin
(3)字典表维度退化
4)维度数据写入Hbase
(1)为了避免维度数据发生变化而重启任务,在mysql存一张配置表来动态配置。
动态实现:通过广播状态
=》 读取一张配置表 ===》 维护这张配置表
source来源 sink写到哪 操作类型 字段 主键 扩展
=》实时获取配置表的变化 ==》CDC工具
=》 FlinkCDC
=》 使用了sql的方式,去同步这张配置表
=》sql的数据格式比较方便
(2)怎么写HBase:借助phoenix
没有做维度退化
维表数据量小、变化频率慢
(3)Hbase的rowkey怎么设计的?有没有数据热点问题?
最大的维表:用户维表
=》百万日活,2000万注册用户为例,1条平均1k:2000万*1k=约20G
使用Phoenix创建的盐表,避免数据热点问题
3.9.4 DWS层
1)为什么选择ClickHouse
(1)适合大宽表、数据量多、聚合统计分析 =》 快
(2)宽表已经不再需要Join,很合适
2)关联维度数据
(1)维度关联方案:预加载、读取外部数据库、双流Join、LookupJoin
(2)项目中读取Hbase中维度数据
(3)优化1:异步IO
异步查询实际上是把维表的查询操作托管给单独的线程池完成,这样不会因为某一个查询造成阻塞,单个并行可以连续发送多个请求,提高并发效率。
这种方式特别针对涉及网络IO的操作,减少因为请求等待带来的消耗。
Flink在1.2中引入了Async I/O,在异步模式下,将IO操作异步化,单个并行可以连续发送多个请求,哪个请求先返回就先处理,从而在连续的请求间不需要阻塞式等待,大大提高了流处理效率。
Async I/O 是阿里巴巴贡献给社区的一个呼声非常高的特性,解决与外部系统交互时网络延迟成为了系统瓶颈的问题。
(4)优化2:旁路缓存
旁路缓存模式是一种非常常见的按需分配缓存的模式。如图,任何请求优先访问缓存,缓存命中,直接获得数据返回请求。如果未命中则,查询数据库,同时把结果写入缓存以备后续请求使用。
(5)怎么保证缓存一致性
方案1:当我们获取到维表更新的数据,也就是拿到维度表操作类型为update时:
更新Hbase的同时,删除redis里对应的之前缓存的数据
Redis设置了过期时间:24小时
方案2:双写
3)轻度聚合
(1)DWS层要应对很多实时查询,如果是完全的明细那么查询的压力是非常大的。将更多的实时数据以主题的方式组合起来便于管理,同时也能减少维度查询的次数。
(2)开一个小窗口,5s的滚动窗口
(3)同时减轻了写ClickHouse的压力,减少后续聚合的时间
(4)几张表? 表名、字段
访客、商品、地区、关键词
3.9.5 ADS层
1)实现方案
为可视化大屏服务,提供一个数据接口用来查询ClickHouse中的数据。
2)怎么保证ClickHouse的一致性?
ReplacingMergeTree只能保证最终一致性,查询时的sql语法加上去重逻辑
3)Flink任务如何监控
Flink和ClickHouse都使用了Prometheus + Grafana