统计结果实时更新问题
在年初的实时数仓调研过程中,我遇到一个统计结果实时更新的问题,即当业务数据的更新操作通过binlog实时同步到flink后,如何对统计结果做同步更新。
简单的统计如sum、count,还可以基于flink实时统计的结果状态进行更新,比如数据从10更新为20,sum对之前的统计结果+10即可。但稍复杂些的计算,比如avg就无法基于历史结果去实时更新了,因为avg的结果更新是基于历史全量明细数据的,flink作为一个通过状态保存中间计算结果的引擎,逻辑上看是无法独立完成这种任务的。
由于我们是To B的公司,数仓的大部分数据都来自于业务而非前端埋点日志,要做实时数仓,这种对数据的更新操作是必须要解决的。
美团外卖实时数仓建设实践
在看美团的技术博客时,发现了一篇对实时数仓建设的实践文章,对上述问题给出了一些解决方案。
整篇文章有两张关键的图。一张是对数据类型做了划分,并提出了两种不同的处理思路,另一张是实际应用的例子。
数据类型和应用场景(来自博客)

日志类的数据会采用实时的处理方式,采用滑动窗口去做统计值,相当于每次计算不会依赖于全量数据,而最多只依赖于之前的计算结果。由于日志类数据不会有更新,也就没有上述问题。
业务类数据需要更新,会出现两个问题:
- 更新是以binlog的形式传入的,如何让对应的历史数据实时更新
- 当明细数据实时更新了,统计结果怎么更新
博客里采用的是微批处理的方式,实现的延迟效果不是实时,而是准实时。在技术实现上,博客里采用doris作为存储和计算的基础,而不是flink。
第一个问题通过doris能够很好地解决,doris有unique模型,可以用这个模型来自动地更新数据。
在第二个问题出现之前,其实还有一个技术上的问题,就是因为采用了doris作为明细数据的落地存储,相当于doris就是实时流的sink了,下游没办法再接收到这个流。我们在调研时考虑过用OLAP做实时数仓,当时的方案里,ODS层更新后数仓各层的级联更新依赖于物化视图等方式,但这种方式可能会给OLAP造成非常大的负担。
从第二张图里可以看出,整个方案变成了微批处理,每分钟调度一次汇总任务,相当于外部驱动数仓各层的更新,用离线数仓的方式来做准实时数仓。但我目测依然会对OLAP有很大的压力,需要严格约束上层统计任务的执行时长。
当实时数仓变成微批处理的准实时数仓时,第二个问题就不是难事了,每次重新统计即可。这也得益于底层采用的是OLAP,能够存储历史明细数据,同时又有计算能力。
应用示例(来自博客)

为什么是OLAP
如果要总结这个方案可行的原因,我认为采用了具备存储和计算两种功能的实时OLAP系统,并将实时变为准实时,是一个关键。虽然这种方案降低了时效性,但相比T+1的离线数仓,这种方案已经能够满足大多数场景对时效性的需求了。
进一步考虑,flink为什么不能做类似的方案?如果flink仅仅基于中间结果来计算,逻辑上确实是无法做到的,因为像avg这种统计的更新是要基于历史全量明细的;所以历史全量明细是一定要存的,而如果给flink提供这些数据的存储系统,是否能做到呢?这就要求flink能够像OLAP那样基于明细数据做快速的全量统计,跟flink原本基于中间结果的状态更新操作是完全不一样的,相当于要求flink做实时olap的事情。
目前flink很难做类似的事情,更别说把时效性从准实时提高到实时了。要想做到业务数据统计结果的实时更新,我们可能需要一种能够在明细数据上做高速统计的计算系统,由于这个要求跟flink基于状态做实时更新的设计有所偏差,个人认为这个系统更可能在OLAP中出现。OLAP要想承担这个重任,可能会在高速统计、预计算、物化视图、实时数据写入等方面做更多的优化。