The Dataflow Model 阅读笔记

2023/05/16

Tags: Algorithm Paper

Dataflow 计算模型

Dataflow 的核心计算模型非常简单,它只有两个概念,一个叫做 ParDo,就是并行处理的意思;另一个叫做 GroupByKey,也就是按照 Key 进行分组。

ParDo

ParDo 用来进行通用的并行化处理。每个输入元素(这个元素本身有可能是一个有限的集合)都会使用一个 UDF 进行处理(在Dataflow中叫做DoFn),输出是0或多个输出元素。这个例子是把键的前缀进行展开,然后把值复制到展开后的键构成新的键值对并输出。

dataflow-pardo

GroupByKey

GroupByKey 用来按 Key 把元素重新分组。

dataflow-group-by-key

ParDo 操作因为是对每个输入的元素进行处理,因此很自然地就可以适用于无边界的数据。而 GroupByKey 操作,在把数据发送到下游进行汇总前,需要收集到指定的键对应的所有数据。如果输入源是无边界的,那么我们不知道何时才能收集到所有的数据。所以通常的解决方案是对数据使用窗口操作。

窗口

时间语义

窗口通常基于时间,时间对于窗口来说是必不可少的,在流式计算中,有 processing-time 和 event-time 两种时间语义,具体参考: 时间语义

窗口分类

窗口分配与合并

Dataflow 模型里,需要的不只是 GroupByKey,实际在统计数据的时候,往往需要的是 GroupByKeyAndWindow。统计一个不考虑任何时间窗口的数据,往往是没有意义的; Dataflow 模型提出:

  1. 从模型简化的角度上,把所有的窗口策略都当做非对齐窗口,而底层实现来负责把对齐窗口作为一个特例进行优化。
  2. 窗口操作可以被分隔为两个互相相关的操作:
    • set<Window> AssignWindows(T datum) 即窗口分配操作。这个操作把元素分配到 0 或多个窗口中去。
    • set<window> MergeWindows(Set<Window> windows) 即窗口合并操作,这个操作在汇总时合并窗口。 而在实际的逻辑实现层面,Dataflow 最重要的两个函数,也就是 AssignWindows 函数和 MergeWindows 函数。

窗口分配

每一个原始的事件,在业务处理函数之前,其实都是(key, value, event_time)这样一个三元组。而 AssignWindows 要做的,就是把这个三元组,根据我们的处理逻辑,变成(key, value, event_time, window)这样的四元组。

需要注意的是,在窗口分配过程中,滑动窗口中存在区间重合的情况,那么在为事件分配窗口的过程中,按照上文四元组的定义,可能一个事件会变成多个事件;

dataflow-window-assign

窗口合并

dataflow-assign-merge-window

Dataflow 里,通过 AssignWindows+MergeWindows 的组合,来进行相应的数据统计。我们还是以前面会话窗口中的案例:客户 30 分钟没有互动就算作超时。

因为要根据同一个用户的行为进行分析,所以 Key 是用户 ID 。那么对应的 Value 里,可以记录消息发送方,以及对应的消息内容。而 event_time,则是实际消息发送的时间。对于每一个事件,我们进行 AssignWindows 的时候,都是把对应的时间窗口,设置成 [eventt​ime,eventt​ime+30)。也就是事件发生之后的 30 分钟超时时间之内,都是这个事件对应会话的时间窗口。而在同一个 Key 的多个事件,我们可以把这些窗口合并。对于会话窗口,如果两个事件的窗口之间有重合部分,我们就可以把它们合并成一个更大的时间窗口。而如果不同事件之间的窗口没有重合,那么这两个事件就还是两个各自独立的时间窗口。

例如同一个用户下,有三个事件,发生的时间分别是 13:0213:1413:57。那么分配窗口的时候,三个窗口会是 [13:02,13:32)[13:14,13:44) 以及 [13:57,14:27)。前两个时间窗口是有重叠部分的,但是第三个时间窗口并没有重叠,对应的窗口会合并成 [13:02,13:44) 以及 [13:57,14:27) 这样两个时间窗口。

窗口的分配和合并功能,就使得 Dataflow 可以处理乱序数据。相同的数据以不同的顺序到达我们的计算节点,计算的结果仍然是相同的。并且在这个过程里,我们可以把上一次计算完的结果作为状态持久化下来,然后每一个新进入的事件,都按照 AssignWindowsMergeWindows 的方式不断对数据进行化简。

触发器和增量处理

基于 watermark 处理迟到数据必然会面临以下两个问题:

  1. watermark 之后的事件如何处理?
  2. 为了数据准确性而设置过长的 watermark ,会导致没有迟到数据也会等待过长时间,从而失去时效性。

在 Dataflow 中给出如下思路:

基于 lambda 架构的思想,尽快给出一个计算结果,然后在后续的事件处理过程中,去不断修正计算结果,在 Dataflow 中体现为 触发器(Trigger) 机制;

触发器除了定义数据何时计算,还可以定义触发之后的输出策略:

参考