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

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

时间窗口

剩下的两种无界数据处理的方法都是时间窗口的变种。在介绍它们之前,我应该先明确时间窗口的含义。时间窗口就是将数据源(无界或者有界)沿着时间线划分成有限的数据块进行处理。下图展示了三种不同的时间窗口模式:

enter image description here

图8:窗口模式举例。每种模式都展示了3个不同的 keys,来突出对齐窗口(应用到所有数据的窗口)和未对齐窗口(应用到数据子集的窗口)之间的区别。

  • 固定窗口:固定窗口把时间划分成固定时间长度的段。典型的(如图8所示),固定窗口的段会覆盖整个数据集,这是对齐窗口的一个例子。有些情况下,需要为不同的数据子集(例如按 key)移动窗口,使得随着时间的推移,窗口的完成负载会更均匀,这种情况就是未对齐窗口的例子了。

  • 滑动窗口:固定窗口的一种广义形式,滑动窗口通过一个固定长度和一个固定间隔来定义。如果间隔小于长度,则窗口之间会重叠。如果间隔等于长度,这就是固定窗口。如果间隔大于长度,则被称为取样窗口,它只会查看一部分数据。与固定窗口一样,滑动窗口一般都是对齐的,尽管在特定情况下会使用未对齐的作为性能优化。注意图8中的滑动窗口这样画是为了展示一种滑动感,事实上,所有5个窗口都会应用到整个数据集上。

  • 会话:会话是动态窗口的一种,它是由通过超过某个时长的非活跃间隙切分的事件序列组成。通过将一系列时间相关的事件划分在一起,会话通常被用于分析用户行为。会话的长度无法提前定义,它们依赖实际的数据。由于对于不同的数据子集(例如不同的用户)会话也不会相同,因此会话也是经典的未对齐窗口。

对于 processing time 和 event time 两种时间概念,时间窗口都是适用的,所以我们会详细的讲解并查看它们的区别。由于 processing time 在现有的系统中更加普遍,我们先来介绍它。

基于 processing time 的时间窗口

enter image description here

图9:基于 processing time 划分的固定时间窗口。基于数据到达的顺序划分到窗口中。

当基于 processing time 创建时间窗口时,系统会将到来的数据缓存进窗口中直到超过了某段 processing time。例如,对于5分钟固定窗口,系统会按 processing time 缓存5分钟的数据,然后会把5分钟内收到的所有数据封装进一个窗口并发送给下游处理。

基于 processing time 的时间窗口有如下优点:

  • 简单。由于从来不需要关心根据时间来 shuffle 数据,所以它的实现是很简单直接的。你只需要缓存到来的数据,当窗口关闭时把它们发送给下游即可。

  • 很容易判断窗口的完整性。由于系统完全知道某个窗口的输入数据是否已经到达,所以它完全可以判断某个窗口的数据是否完整。这意味着当基于 processing time 划分窗口时完全不需要处理晚到数据。

  • 适用于根据观测推断数据源相关信息的场景。许多监控场景都是这种类型。例如通过计算发送给一个 Web 服务的每秒请求数来探测服务是否中断。

不过基于 processing time 的窗口有一个非常大的缺点:如果需要 processing time 窗口反映事件真正发生的时间,那么这些数据必须按 event time 有序到达。不幸的是,对于分布式输入源,按 event-time 有序的数据是几乎不存在的。

举个简单例子,假设手机上的一个 app 会收集用户统计信息。当手机未连接网络时(例如乘飞机时使用飞行模式),这段时间收集的数据无法上传直到手机再次连上网络。这就意味着这些数据会比 event time 晚几分钟、几小时、几天、几周甚至更长时间才能到达。当基于 processing time 划分时间窗口时,不可能从这样的数据上获取任何有用的结论。

另一个例子,当整个系统健康运行时,许多分布式输入源可能看起来能够提供按 event-time 有序的数据。不幸的是,健康状态下 event-time skew 很低并不意味着一直能保持如此。假设有一个从各个大陆上收集数据的全球服务。如果网络问题造成带宽下降或者延迟增加,那么可能会造成一部分输入数据的 event-time skew 变大。如果是基于 processing time 划分的窗口,那么窗口将无法再表示数据真正产生的情况。相反,它们表示的是事件到达时的情况,是新旧数据混合在一起的。

这两个例子其实都应该基于 event time 来划分时间窗口。

基于 event time 的时间窗口

当你想反映事件真实发生的时间时需要使用基于 event time 的时间窗口。基于 event time 的时间窗口是窗口划分的黄金标准。遗憾的是,如今使用的大部分数据处理系统对它缺少原生的支持。

下图展示了基于 event time ,将无界数据划分成1小时的固定时间窗口:

enter image description here

图10:基于 event time 划分成固定时间窗口。数据按照它们产生的时间被划分进窗口中。白色箭头示意数据所在的 processing time 窗口与 event time 窗口不同。

图中的白色箭头标识了两个特殊的数据。这两个数据所在的 processing time 窗口与 event time 窗口是不匹配的。因此,对于关心 event times 的情况,如果这些数据被划分进 processing time 窗口,那么计算结果就是错误的。由此可见,能够提供 event time 的正确性是使用 event time 窗口的一大优势。

基于 event time 的时间窗口的另一个优势是它可以创建动态大小的窗口,例如会话,再不会发生像基于固定窗口生成的会话出现跨窗口的情况(正如在”无界数据 – 批量”章节看到的会话例子那样)。

enter image description here

图11:基于 event time 划分成会话时间窗口。基于事件发生的时间,数据被划分进会话时间窗口。白色箭头标识了需要对数据进行基于时间的 shuffle 操作,来将其放入正确的 event-time 窗口位置。

Event time 窗口虽然强大,但其同样也有缺点。由于窗口通常存在时间比窗口本身的长度要更长一些,event time 窗口具有两个明显的缺点:

  • 缓存:由于延长了时间窗口的生命期,需要缓存更多的数据。庆幸的是,持久化存储已经是大部分数据处理系统所依赖的最廉价的资源了(其它资源是 CPU、网络带宽、内存)。因此,当使用设计良好的带有强一致持久化状态和内存缓存层的数据处理系统时这个问题就不那么重要了。而且,很多聚合操作不需要缓存完整的输入数据(例如求和或者均值),相反可以递增执行,只需要把更小的中间聚合状态存储在持久化状态中。

  • 完整性:由于我们通常都不知道某个时间窗口下的数据何时到齐,那么我们如何知道何时开始处理这个窗口下的数据?事实上,我们无法得知。对于很多类型的输入,系统可以通过像 MillWheel 的 watermarks 给出一个窗口完整性的启发式评估。但是对于需要绝对正确性的场景(例如记账),唯一的解决方法是提供一种方式能够重新处理窗口中的数据从而不断修正计算结果。

总结

本文涵盖了很多信息。在进入第二部分之前,有必要温习沉淀下前面介绍的信息。第一部分是比较无聊的,而第二部分会有趣很多。

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

发表评论

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