Spark & Flink

流式处理的一些概念 二:水印、触发器、积累模式(翻译)

2018-12-19  本文已影响0人  Alex90

继续上一篇的内容,研究下面的三个概念:

原文中首先回顾上一篇的几个概念,结合一些事例(Dataflow Java SDK 的伪代码)帮助理解他们。下面正式讲解本章节内容:

水印(watermarks)

水印是事件时间域中输入完整性的时间概念。换句话说,它们是系统对于事件流中正在处理的记录的事件时间的进度测量和完整性判断。回想一下之前提到的事件时间和处理时间之间的偏差,对于大多数真实世界的分布式数据处理系统,它是一个不断变化的时间函数。

代表现实的红线本质上是水印,它捕获了随着处理时间推进的事件时间完整性的进展。从概念上讲,可以将水印看作一个函数 F(P)->E,接受处理时间的一个点,并返回事件时间的一个点(更准确地说,函数的输入实际上是正在观察水印的流水线中点上游的所有东西的当前状态:输入源、缓冲数据、正在处理的数据等;但在概念上,将其看作从处理时间到事件时间的映射更简单)。事件时间点E是系统认为已经观察到事件时间小于E的所有输入的点。换句话说,这是一个断言,没有更多的事件时间少于E的数据将再次出现。水印有两种类型:

现在,为了更好地理解水印所起的作用以及它们的一些缺点,让我们看一下流引擎的两个示例,其中流引擎仅使用水印来确定何时实现输出。左边的示例使用完美的水印,右边的示例使用启发式水印。

在这两种情况下,当水印通过窗口的末端时,窗口实现输出。这两种算法的主要区别在于,在右侧的水印计算中使用的启发式算法没有考虑9的值,这极大地改变了水印的形状。这个例子突出了水印的两个缺点:

仅仅依赖完整性概念的系统不能同时获得低延迟和正确性。解决这些问题是触发器发挥作用的地方。

触发器(Trigger)

触发器声明窗口的输出在处理时间域中应该什么时间发生(尽管触发器本身可以基于其他时间域发生的事情做出那些决定,比如事件时域中的水印)。窗口的每个特定输出称为窗口的窗格(pane of the window)。

信号触发的例子包括:

除了基于具体信号触发的简单触发器之外,还有允许创建更复杂的触发逻辑的复合触发器。复合触发器包括:

我们可以使用触发器考虑解决水印太慢或太快的问题。在这两种情况下,我们本质上都希望为指定窗口提供某种规则的、物化的更新,在水印超出窗口末尾之前或之后(除了更新之外,我们将在通过窗口末尾的水印的阈值处接收)。所以,我们需要一些重复触发器。然后问题就变成了:我们要重复什么?

在速度太慢的情况下(提供过早的推测性结果),我们可以假定,对于任何给定的窗口,都会有稳定数量的传入数据。因为我们知道(通过定义什么处于窗口的早期阶段),观察到的窗口输入到目前为止是不完整的。因此,当处理时间提前的情况,进行周期性地触发(例如,每分钟一次)可能是明智的,因为触发器触发的数量并不取决于窗口实际观察到的数据量;最坏的情况是,我们只是得到了周期性触发器触发的稳定流。

在速度太快的情况下(由于启发式水印,为响应延迟数据而提供最新的结果),让我们假设水印是基于相对准确的启发式(通常是相当安全的假设)。在这种情况下,我们不希望经常看到延迟的数据,如果快速修改结果会很好。在观察元素计数1之后触发将给我们的结果提供快速更新(即,在任何时候我们看到延迟数据时立即更新),考虑到预期的延迟数据不频繁,不太可能压垮系统。

对于提前水印的数据的执行每分钟触发一次,对于延迟水印的数据执行每统计到一个立即触发,得到的结果如图:

这个版本与只使用水印的版本对比,有两个明显的改进:

触发器有效地规范化了完美水印和启发式水印之间的输出模式,这两个版本的输出看起来非常相似。

此时剩余的最大的差异是窗口生命周期界限。在完美的水印情况下,一旦水印已经过了窗口的末尾,就再也看不到窗口的数据了,因此以在那个时候删除窗口的所有状态。在启发式水印情况下,仍然需要保持窗口的状态一段时间,以解决延迟数据。但是到目前为止,还没有任何好的方法来知道每个窗口需要保持多长时间的状态。

允许的延迟,垃圾回收(allowed lateness - garbage collection)

在长期存活、无序的流处理系统中,垃圾回收是很重要的一个部分。在启发式水印示例中,每个窗口的持久状态在逗留在整个生命周期中,这是很必要的,因为这允许迟到的数据到达时能够得到适当地处理。但实际上,在处理无界数据源时,为给定的窗口无限期地保持状态是不现实的,最终将用完磁盘空间。

因此,任何现实世界的无序处理系统,都需要提供某种方法来限制其处理的窗口的生命周期。一种方法是在系统内允许的延迟上设置一个界限(设置一个数据最大的延迟)。任何之后到达的数据都会被丢弃。一旦确定了单个数据的延迟时间,你也可以准确的知道窗口的状态必须保持多久:直到水印超过窗口末尾的延迟时间。除此之外,还给系统提供了在界限之外观测到数据之后立即删除的自由,这意味着系统不会浪费资源处理没有人关心的数据。

在之前的基础上,添加一分钟的延迟时间范围,pipeline 的执行类似于下图,允许延迟的影响:

1 2

关于 lateness horizons 的两个附注:

累积(accumulation)

当触发器用于随着时间推移,为单个窗口生成多个窗格(panes of window)时,我们面临着一个问题:“结果的细化如何关联?”。实际上存在三种不同的累积模式:

参考之前图示中第二个窗口 [12:02,12:04) 的三个窗格,下表显示了三种累积模式中每个窗格的值是什么样子的:

Discarding Accumulating Accumulating & Retracting
Pane 1: [7] 7 7 7
Pane 2: [3, 4] 7 14 14, -7
Pane 3: [8] 8 22 22, -14
Last Value Observed 8 22 22
Total Sum 22 51 22

在之前的基础上增加,丢弃模式的伪代码,pipeline 效果图如下,丢弃版本中的窗格没有重叠。因此,每个输出都独立于其他输出

而累计和收缩的模式如下,窗口是重叠的,retractions 用红色表示,该颜色与重叠的蓝色窗格结合在一起。

横向比较三种模式:

可以想象,按顺序呈现的模式(丢弃、累积、累积和收缩)在存储和计算成本方面依次更加昂贵。累积模式提供了沿着正确性、延迟和成本轴进行权衡的另一个维度。

原文:https://www.oreilly.com/ideas/the-world-beyond-batch-streaming-102

上一篇下一篇

猜你喜欢

热点阅读