Flink 源码阅读笔记(13)- 双流操作的实现
文章目录
在使用 Flink 进行实时数据处理时,一个常用的场景是对两个流的数据进行关联。这篇文章中我们将对双流操作的底层实现机制进行分析。
Window Join and CoGroup
Window Join 操作,顾名思义,是基于时间窗口对两个流进行关联操作。相比于 Join 操作, CoGroup 提供了一个更为通用的方式来处理两个流在相同的窗口内匹配的元素。 Join 复用了 CoGroup 的实现逻辑。它们的使用方式如下:
|
|
从 JoinFunction
和 CogroupFunction
接口的定义中可以大致看出它们的区别:
|
|
可以看出来,JoinFunction
主要关注的是两个流中按照 key 匹配的每一对元素,而 CoGroupFunction
的参数则是两个中 key 相同的所有元素。JoinFunction
的逻辑更类似于 INNER JOIN,而 CoGroupFunction
除了可以实现 INNER JOIN,也可以实现 OUTER JOIN。
Window Join 的是被转换成 CoGroup 进行处理的:
|
|
那么 CoGroup 又是怎么实现两个流的操作的呢?Flink 其实是通过一个变换,将两个流转换成一个流进行处理,转换之后数据流中的每一条消息都有一个标记来记录这个消息是属于左边的流还是右边的流,这样窗口的操作就和单个流的实现一样了。等到窗口被触发的时候,再按照标记将窗口内的元素分为左边的一组和右边的一组,然后交给 CoGroupFunction
进行处理。
|
|
Connected Streams
Window Join 可以方便地对两个数据流进行关联操作。但有些使用场景中,我们需要的并非关联操作,ConnectedStreams
提供了更为通用的双流操作。
ConnectedStreams
配合 CoProcessFunction
或 KeyedCoProcessFunction
使用,KeyedCoProcessFunction
要求连接的两个 stream 都是 KeyedStream
,并且 key 的类型一致。
ConnectedStreams
配合 CoProcessFunction
生成 CoProcessOperator
,在运行时被调度为 TwoInputStreamTask
,从名字也可以看书来,这个 Task 处理的是两个输入。TwoInputStreamTask
在前面关于 Task 的生命周期的文章中已经进行了介绍。我们简单看一下 CoProcessOperator
的实现:
|
|
CoProcessOperator
内部区分了两个流的处理,分别调用 CoProcessFunction.processElement1()
和 userFunction.processElement2()
进行处理。对于 KeyedCoProcessOperator
也是类似的机制。
通过内部的共享状态,可以在双流上实现很多复杂的操作。接下来我们就介绍 Flink 基于 Connected Streams 实现的另一种双流关联操作 - Interval Join。
Interval Join
Window Join 的一个局限是关联的两个数据流必须在同样的时间窗口中。但有些时候,我们希望在一个数据流中的消息到达时,在另一个数据流的一段时间内去查找匹配的元素。更确切地说,如果数据流 b 中消息到达时,我们希望在数据流 a 中匹配的元素的时间范围为 a.timestamp + lowerBound <= b.timestamp <= a.timestamp + upperBound
;同样,对数据流 a 中的消息也是如此。在这种情况,就可以使用 Interval Join。具体的用法如下:
|
|
Interval Join 是基于 ConnectedStreams
实现的:
|
|
在 IntervalJoinOperator
中,使用两个 MapState 分别保存两个数据流到达的消息,MapState 的 key 是消息的时间。当一个数据流有新消息到达时,就会去另一个数据流的状态中查找时间落在匹配范围内的消息,然后进行关联处理。每一条消息会注册一个定时器,在时间越过该消息的有效范围后从状态中清除该消息。
|
|
小结
双流操作是实时计算场景下经常用到的操作。相比于单个数据流上的操作,双流操作要同时考虑到两个数据流中数据的关联性,因而要更为复杂一些。本文简单介绍了在 Flink 中对双流操作的实现机制,包括 Join 操作、CoGroup 操作和 Connected Streams 等。Connected Streams 提供了更为通用的处理两个数据流的方法,特别适用于一个数据流的消息会对另一个数据流的消息处理产生影响的场景,但这通常也要依赖于内部的共享状态。
参考
-EOF-
文章作者 jrthe42
原始链接 https://blog.jrwang.me/2019/flink-source-code-two-stream-join/
上次更新 2019-09-07
许可协议 CC BY-NC-ND 4.0