目前主流的数仓构建思想都是以维度建模为主,以下都是在工作中的一些思考和想法。
flink版本1.2
kappa架构
1.维表延迟问题
主流join动态无时序维表时如何解决因为维表延迟而导致的数据不准问题?
目前来看好像只能通过批处理来修复流数据。如果通过批处理来修复那还能说是kappa架构?
2021-12-23 可以通过监控维表的变更来update结果表修复因延迟导致的数据问题
2022-03-01 streamA left join sideB where B.xxx=xxx 当维表延迟的时候只能通过维表反查主流数据来修复之前错误的结果
2.历史数据的处理以及新增需求后的刷数
这里说的历史数据处理和刷数的需求在kappa架构不是不能实现而且需要考虑到时间长度的问题。当数据量级上去后使用标准的流式架构处理大量的历史数据(ETL)是一个非常耗时的问题。有时一天都完成不了刷数任务。由于刷数任务使用的和正常流式任务相同的代码(除了source不一样),那么就会出现历史数据覆盖最新数据的情况(刷数任务将数据抓到了内存中但是处理的没有正常流式任务快,就会导致数据覆盖的情况),此时必须等刷数任务结束才能重置正常流式任务的offset来修复数据。
3.Kappa架构下ods层
当监听的数据库有物理删除操作时,那么ods也就变成必须要设计的分层了。ods层设计主要是需要解决数据回溯的问题,线上kafka往往不能存储永久的数据。Pulsar目前算是正在解决这个问题的队列。
场景
1.实时计算的数据有明确的时间维度且时间维度较短(如7天内)
计算需求:不同页面每天的uv
只需要依靠kafka本身的数据就可以完成计算并不依赖历史数据。
2.实时计算的数据有明确的时间维度且时间维度长(如30天内)。
计算需求:不同页面近一个月内的uv
kafka不允许存30天的数据,那么单纯靠kafka中的数据是无法计算中结果的。就需要依赖历史数据了。
解决方案参考文章:利用 Flink 实现实时状态复用场景
3.实时计算的数据没有时间维度
计算需求:不同页面从最开始上线到此时的所有的uv
那么此时在使用flink计算的就需要获取此页面下的所有用户然后对数据去重
方案一:
与2里面的方案一一样,在启动时将所有的历史数据都拉取到flink状态中,然后通过flink状态做去重操作。但是缺点更加明显,此时需要拉取所有的历史数据,也就是在dws聚合时需要将dwd的全表拉取到flink中,时间和资源浪费的也更加明显。flink 1.14支持Hybrid Source可以简化此方案的开发流程。
方案二:
方案二与方案一的思路差不多,都是需要将历史数据拉取到flink状态中。但是拉取的时机不一样,方案二的历史数据拉取是在数据进入时判断此分组下的数据是否已经拉取过历史数据,如果没有拉取则查询外置储存,获取所有的历史数据然后进行计算。规避了job启动时的耗时以及不必要的资源耗费。但是代码和SQL相对方案一稍显复杂。
方案三:
将flink作为触发器,计算外置。flink本身不做计算,收到消息后调用OLAP引擎进行dwd层的聚合操作然后获取返回结果在进行对应的处理。相比方案一和方案二,方案三的开发相对简单,不用关心状态和任务的启动耗时。缺点也很明显,完全依赖OLAP引擎的计算能力。OLAP引擎的选择要求也比较高,能支持高并发(flink来一条消息就会触发一次OLAP的计算)、能支持部分join(计算外置、部分join聚合需要支持)、而且当flink因为数据触发时本条触发的数据必须已经存在OLAP引擎中(能支持大量的单条写入而且写入即可读或者当数据写入成功时能发送消息声明数据已经写入,必须存在是为了防止漏算)、最好能支持按照用户组资源隔离(防止慢SQL影响其他任务)。
方案四:
flink SQL left join 维表。将dwd的表从kafka中注册为source同时将dwd的表从OLAP引擎中注册为side,然后利用source left join side。此方案也是为了简化开发和方案二最大的不同就是此方案不会保存flink状态因为每次计算的数据都是从OLAP引擎中拉取的,source 接受到消息然后做 left join操作会将符合条件的所有明细拉入到flink内存中,然后在一条一条的进行计算。优点就是减少了对OLAP引擎的计算依赖。缺点也很明显写放大。flink无法一次性处理所有明细数据,每处理一条数据就会往下游发送一条数据导致写放大。N条明细会有2N条数据往下游发送(group by 操作会有true和false的回撤)。此时只能在聚合完成的下游加window然后选择window中最新的一条true数据往下发送减少写放大的条数。
方案五
方案五和方案三类似,不过方案五是在OLAP引擎中创建物化视图。也就是flink不在负责dws的聚合操作只需要保证dwd的数据能够进入到OLAP引擎中。通过OLAP引擎中的物化视图来实时聚合。OLAP引擎本身最好能保证事务性,否则可能会出现dws和dwd的数据对不上。
方案六
方案六和方案五类似,方案六是在OLAP引擎中做分钟级别的调度来满足实时性。同样flink本身不负责dws的聚合操作只需要保证dwd的数据能够进入到OLAP引擎中。