本文主要通过Google Cloud DataFlow Paper的内容与Apache Flink DataStream中的实现进行了基于Time、Window和Trigger的比较。
众所周知,Apache Flink最早来源于[Stratosphere]项目,DataFlow则来源于MillWheel项目,且DataFlow的实现是基于FlumeJava和MillWheel。Flink的实现也是借鉴自Millwheel,因此,在流处理的实现上,两者的实现引擎可以说都来自MillWheel,进而有很多相似之处,尽管Apache Flink在概念上有些也是基于DataFlow的论文。
1、流处理简介
流处理在分布式系统中面临的难题包括:大量的数据、无界、乱序、以及全局性(基于分布式)的处理。
何为正确性?完全的正确性在流处理中不可能实现,只有在批处理中才会有completely正确性。因此,DataFlow的设计准则的第一条就是“从来不依赖任何的完整性的概念”。
下图展示DataFlow的设计准则:
Flink的设计目标包括对于大量数据处理提供低延迟、能够处理乱序、有状态(全局性状态)的无界的数据流。
2、如何在正确性、延迟以及成本之间进行平衡?
DataFlow和Flink中都有Time、watermark、Window和Trigger的概念。
(1)Time的2种方式:
1、Event Time
2、processing Time
除此之外,Flink中还实现了一种新的时间概念:Ingestion Time。即event进入Flink时打上的时间戳,也就是其Ingestion time可以作为其watermark的时间。这对于event本身没有提供时间字段的例子很有帮助。
关于watermark,之前的文章中也有提到。理想情况下,事件的event time等于processing time,然后现实不可能是这样的。因此,理想水位线与现实水位线之间的差值,DataFlow中给出了这个值的定义:Skew。
。
(2)window内部实现的2种方式:
1、Set<Window> AssignWindows(T datum)
2、Set<Window> MergeWindows(Set<Window> windows)
即根据数据,确定其所属的window;同时,对于session window而言,也存在着window merge到一起的情况。
Flink与DataFlow中都有相同的Window的概念。
我们通过一个例子说明window的assign和merge。
(1)Window Assignment
例如,有2条数据(k,v1,12:00)以及(k,v2,12:01),通过operator:“AssignWindows(
Sliding(2m,1m))”将每条数据划分到相应的窗口中,由于是sliding窗口,因此每条数据被划分到2个不同的窗口中。
(2)Window Merging
在DataFlow中,ession window的处理是window merge机制产生的动机,因此,这里使用了session window的例子,关于session window,可以参考我之前的文章。
这个例子中,设置的session gap是30分钟,且用到了几个operator:
1、AssignWindows(Sessions(30m)): 根据每条数据的timestamp,划分其窗口范围
2、DropTimestamps: 将每条数据的timestamp列去掉,只剩下(k,v,window range)
3、GroupByKey: 根据key,聚合数据成为一个(value,window)组
4、MergeWindows(Sessions(30m)): 根据指定的窗口策略(sessions(30m)),将同一个key中有重合的窗口进行merge。例如k1中,v1和v4的窗口有重合,因此,扩展v1和v4所在的窗口范围到[13:02,13:50),即v1和v4所在窗口范围的并集。
5、GroupAlsoByWindow: 对于同一个key,按照窗口分组,将相同窗口的value聚合到一起。
6、ExpandToElements: 扩展元素,这里最终输出(key,value List,window_end_time,window),即把窗口结束的时间作为每条数据的时间戳。
从最后的结果看,DataFlow中的session window和Flink中的session window基本一致。
(3)Trigger触发器
在流处理中,实现基于Event Time、提供非对齐(窗口大小不固定,典型的就是session window)的窗口,本身就是一种提升。
我们先看看DataFlow中如何处理Trigger。
到目前为止,我们提到了Event Time与Window的机制与实现,那么我们还面临2个问题:
1、对于tuple以及基于processing time的窗口的支持
2、何时触发窗口?
对于问题1,一会我们会在具体的例子中展示;问题2,对于现实世界中基于event time处理可能遇到的乱序的情况,我们需要一种信号来告诉我们什么时候开始窗口的计算。
说到这里,可能大家已经想到,乱序问题的处理的就依赖watermark就好了。然而, watermark本身也存在2个短板:
1、太快
2、太慢
这怎么解释呢?
太快就是watermark产生(emit)后,仍然存在一些late的数据到来。因为在分布式数据处理中,我们永远不知道late elemen