The world beyond batch: Streaming 101(第二节)

The world beyond batch: Streaming 101(第二节)

数据处理模式

现在我们可以开始讲一些有界和无界数据处理的重要模式了:批量和流式,这里我把微批归类为流式,因为二者的区别不是很重要。

有界数据

处理有界数据很简单,大家都很熟悉。在下图中,左边是一个数据集,使用一些数据处理引擎对它进行处理(典型的是批量处理,尽管一个设计良好的流式引擎也可以胜任),例如 MapReduce,右边则是处理后的结果:

enter image description here

图2:使用一个典型的批量引擎处理有界数据。左边的有限的无组织的数据通过数据处理引擎的处理,生成了右边对应的结构化的数据。

有界数据处理整体来说是很简单的,更让我们感兴趣的是如何处理无界数据。现在让我们看看不同的处理无界数据的典型方法,首先会分析使用传统的批量引擎的方法,然后分析像流式或者微批引擎这种为无界数据设计的系统。

无界数据 – 批量

尽管批量引擎在大家的观念中并不是为无界数据处理设计的,但是从它诞生开始就被用来处理无界数据了。大家都能想到,只要我们把无界数据划分成有界数据的集合,就可以采用批量处理。

固定窗口

使用批量引擎处理无界数据最常见的方法是将输入数据切分到固定大小的窗口中,然后将每个窗口作为独立的有界数据进行处理。特别是像日志这种输入源,事件可以被写进目录和文件的层次结构中,它们对应的窗口被编码进这些目录文件的名字中,这种问题乍一看好像很简单,因为为了将数据划分到合适的 event time 窗口中,你已经执行了基于时间的 shuffle 操作。

然而实际上大部分系统需要处理完整性问题:如果一些事件由于网络问题延迟到达怎么办?如果事件是从全球收集的,并且需要在处理前必须被发送到一个公共位置怎么办?如果事件是来自移动设备的怎么办?这意味着可能需要一些特别的处理方法(例如延迟处理直到确定所有事件都已到达,或者只要有数据晚到就重新处理某个窗口的整个数据集)。

enter image description here

图3:通过固定窗口使用典型的批量引擎处理无界数据。一个无界数据是有限的固定窗口的有界数据的集合,通过连续执行的批量引擎进行处理。

会话

当你使用像会话这种更精细的窗口策略,通过批量引擎处理无界数据时,会遇到更多的问题。会话一般是按活跃间隔划分的(例如针对某个特定的用户)。当使用典型的批量引擎计算会话时,经常会出现一个会话跨越多个分片,如下图红色标记部分。通过增加分片大小可以减少跨越多个分片的概率,但是会增加延迟。另一个方法是增加额外的逻辑来处理这种情况,代价是增加逻辑复杂度。

enter image description here

图4:通过固定窗口使用典型的批量引擎处理无界数据。一个无界数据是有限的固定窗口的有界数据的集合,然后被细分成动态的会话窗口,通过连续执行的批量引擎进行处理。

这两种方法都不够完美,更好的方法是使用流式来处理会话,我们下面会讲。

无界数据 – 流式

与大部分基于批量的无界数据处理方法不同,流式系统就是为无界数据而设计的。正如上面所说,对于分布式输入源,它产生的数据不只是无界的,还具有如下特性:

  • 按 event times 无序,如果你想按发生的时间顺序来分析数据,就需要基于时间进行 shuffle 处理。
  • event time skew 不确定,意味着你不能假设在 X+Y 时总是能看到大部分 event time 为 X 的数据。

有一些处理具有这些特性的数据的方法。我大致将它们分为4类:

  • 时间无关
  • 近似法
  • 基于 processing time 的时间窗口
  • 基于 event time 的时间窗口

我们对每一种方法进行分析。

时间无关

时间无关处理被用于不关心时间的场景中,也就是说所有的逻辑都是数据驱动的。由于这些场景的所有事情都是由到达的数据决定的,所以不需要流式引擎支持除了基本数据传递之外的特殊功能。目前所有的流式系统都能支持这种与时间无关的使用场景。批量系统也非常适合对无界数据进行这种时间无关的处理,只需要将无界数据划分成任意长度的有界数据序列并分别独立处理即可。我们将会举几个例子说明。

过滤

一个非常基本的时间无关处理的例子就是过滤。假设你在处理 Web 流量日志,想要过滤出来自某个特定主域的流量。你会查看每条到达的日志是否属于那个主域,如果不是则丢弃。由于这件事在任何时刻都只依赖单条日志,而数据源是无界的、无序的、以及 event time skew 是不确定的都没有影响。

enter image description here

图5:过滤无界数据。从左向右的流动的包含不同类型的数据被过滤成只包含一种类型的数据。

Inner-joins

另外一个时间无关的例子是 inner-join。当拼接两个无界数据源时,如果你只关心拼接的结果,则处理逻辑不需要考虑时间的因素。一旦看到来自某个数据源的一个值,只需要把它缓存起来;当来自另一个数据源的第二个值到达时,则发送拼接结果即可。

enter image description here

图6:对无界数据执行 inner join 操作。当来自两个数据源的匹配的元素都到达时则产生拼接结果。

如果切换成 outer join 则会引入数据完备性问题:一旦看到了拼接的一边,如何知道另一边是否到达了呢?说实话,我们没法得知,因此我们只能引入某种超时机制,这必然会引入时间因素。时间因素本质上就是时间窗口的形式,后面会更详尽的介绍。

近似法

enter image description here

图7:对无界数据计算近似值。数据经过一个复杂算法的处理,在另一边生成与想要的结果近似的输出数据。

第二大类方法就是近似算法,例如approximate Top-Nstreaming K-means 等等。它们以无界数据作为输入,并提供与你所希望获得的结果类似的输出数据。近似算法的优点是它们开销很低并且天生就是为处理无界数据而设计的。而缺点是它们的算法通常是很复杂的(这使得想出新的算法是很困难的),并且近似特性限制了它们的应用。

值得注意的是:这些算法在设计上通常都有一些时间因素。由于这些算法会随着元素的到达而处理它们,时间因素通常都是基于 processing-time 的。这对于提供了某类可控错误边界的算法是尤为重要的。

近似算法本身是个很令人着迷的主题,但是因为它们实质上是时间无关处理的另一种例子(除了算法本身的时间特征),使用起来是很简单的,所以就不再细说了。

上一篇:The world beyond batch: Streaming 101(第一节)

下一篇:The world beyond batch: Streaming 101(第三节)

发表评论

电子邮件地址不会被公开。 必填项已用*标注