流分析&活动时间和水印

使用事件时间#

如果要使用事件时间,还需要提供时间戳提取器和水印 Flink 将用于跟踪事件时间进度的生成器。这将在 下面关于使用水印的部分,但首先我们应该解释什么是水印。

水印

让我们通过一个简单的例子来说明为什么需要水印,以及它们是如何工作的。

在此示例中,您有一个带有时间戳的事件流,这些事件的到达有些无序,如下所示 下面。显示的数字是指示这些事件实际发生时间的时间戳。第一个 到达的事件发生在时间 4,紧随其后的是较早发生的事件,即时间 2, 依此类推:

···23 19 22 24 21 14 17 13 12 15 9 11 7 2 4 →

现在假设您正在尝试创建一个流排序器。 这是一个应用程序,用于在流到达时处理流中的每个事件,并发出包含相同事件的新流,但按其时间戳排序。

一些观察:

(1) 您的流排序器看到的第一个元素是 4,但您不能立即将其释放为 排序流的第一个元素。它可能已无序到达,并且较早的事件可能 还到了。事实上,你对这个流的未来有一些神一样的知识,并且 您可以看到,您的流排序器应该至少等到 2 到达,然后再生成任何 结果。

一些缓冲和一些延迟是必要的。

(2)如果你做错了,你最终可能会永远等待。首先,分拣机从时间上看到了一个事件 4,然后是时间 2 的事件。时间戳小于 2 的事件会到达吗?或。 也许不是。你可以永远等待,永远看不到 1。

最终,你必须勇敢地发出 2 作为排序流的开始。

(3) 然后,您需要的是某种策略,该策略定义何时,对于任何给定的时间戳事件,何时 不要再等待早期事件的到来了。

这正是水印的作用——它们定义了何时停止等待早期事件。

Flink 中的事件时间处理依赖于插入特殊时间戳的水印生成器 元素添加到流中,称为水印。时间 t 的水印是断言 流现在(可能)在时间 t 中完成。

这个流排序器什么时候应该停止等待,并推出 2 来启动排序流?当 水印到达时的时间戳为 2 或更大。

(4) 您可以想象不同的策略来决定如何生成水印。

每个事件在一段时间后到达,这些延迟各不相同,因此某些事件的延迟超过 别人。一种简单的方法是假设这些延迟受某个最大延迟的限制。Flink 将此策略称为有界无序水印。不难想象更多 复杂的水印方法,但对于大多数应用程序来说,固定延迟已经足够好用了。

延迟与完整性

考虑水印的另一种方式是它们为您提供了流媒体的开发者 应用程序,控制延迟和完整性之间的权衡。与批处理不同, 在产生任何输入之前,人们能够完全了解输入 结果,通过流式处理,您最终必须停止等待看到更多输入,并产生一些输入 某种结果。

您可以积极地配置水印,并具有较短的有限延迟,从而 冒着在对输入的不完全了解的情况下产生结果的风险——即可能 错误的结果,产生得很快。或者,您可以等待更长的时间,并生成利用 对输入流有更全面的了解。

还可以实施混合解决方案,快速产生初步结果,然后 在处理其他(延迟)数据时提供这些结果的更新。这是一个很好的方法 一些应用程序。

迟到#

迟到是相对于水印定义的。A 断言流已完成 直到时间t;此水印之后的任何事件,其时间戳为 ≤ T,则为延迟。Watermark(t)

使用水印#

为了执行基于事件时间的事件处理,Flink 需要知道与 每个事件,它还需要流包含水印。

动手练习中使用的出租车数据源会为您处理这些细节。但是在你的 自己的应用程序,您必须自己处理,这通常是通过实现来完成的 一个类,用于从事件中提取时间戳,并按需生成水印。这 最简单的方法是使用:WatermarkStrategy

窗户#

Flink 具有非常富有表现力的窗口语义。

在本节中,您将了解:

  • 如何使用 Windows 计算无限流上的聚合,
  • Flink 支持哪些类型的窗口,以及
  • 如何实现具有窗口聚合的 DataStream 程序

介绍#

在进行流处理时,很自然地想要计算有界子集的聚合分析 的流,以回答以下问题:

  • 每分钟的页面浏览量
  • 每个用户每周的会话数
  • 每个传感器每分钟的最高温度

使用 Flink 计算窗口分析依赖于两个主要的抽象:将事件分配给窗口的窗口分配器(根据需要创建新的窗口对象)和应用于分配给窗口的事件的窗口函数

Flink 的窗口化 API 也有触发器的概念,它决定了何时调用窗口 函数和 Evictors,可以删除窗口中收集的元素。

窗口分配器#

这些窗口分配器可能用于什么以及如何指定它们的一些示例:

  • 翻滚时间窗口
    • 每分钟页面浏览量
    • TumblingEventTimeWindows.of(Time.minutes(1))
  • 滑动时间窗
    • 每 10 秒计算一次的每分钟页面浏览量
    • SlidingEventTimeWindows.of(Time.minutes(1), Time.seconds(10))
  • 会话窗口
    • 每个会话的页面浏览量,其中会话由会话之间至少 30 分钟的间隔来定义
    • EventTimeSessionWindows.withGap(Time.minutes(30))

可以使用 、 、 和 之一指定持续时间。Time.milliseconds(n)Time.seconds(n)Time.minutes(n)Time.hours(n)Time.days(n)

基于时间的窗口分配器(包括会话窗口)同时出现在事件时间和处理中 时间的味道。这两种类型的时间窗口之间存在重大权衡。跟 处理时间窗口 您必须接受以下限制:

  • 无法正确处理历史数据,
  • 无法正确处理乱序数据,
  • 结果将是不确定的,

但具有延迟较低的优点。

使用基于计数的窗口时,请记住,这些窗口在批处理之前不会触发 已完成。没有超时和处理部分窗口的选项,但您可以实现 该行为自己使用自定义触发器。

全局窗口分配器将每个事件(使用相同的键)分配给同一全局窗口。这是 仅当您要使用自定义触发器执行自己的自定义窗口时才有用。在许多情况下 如果这看起来很有用,您最好使用另一节中所述的 a。ProcessFunction

窗口函数#

对于如何处理窗口的内容,您有三个基本选项:

  1. 作为一个批处理,使用 一个 将传递一个 与窗口的内容;ProcessWindowFunctionIterable
  2. 以增量方式,当每个事件被分配给窗口时,将调用 A 或 an;ReduceFunctionAggregateFunction
  3. 或两者的组合,其中,当窗口被触发时,将a或an的预聚合结果提供给a。ReduceFunctionAggregateFunctionProcessWindowFunction

以下是方法 1 和 3 的示例。每个实现都从每个传感器找到峰值 在 1 分钟的事件时间窗口内,并生成包含 .(key, end-of-window-timestamp, max_value)

在此实现中需要注意的几点:

  • 分配给窗口的所有事件都必须以键控 Flink 状态进行缓冲,直到触发窗口。这可能非常昂贵。
  • 我们被传递了一个对象,其中包含有关窗口的信息。

windowState并且是可以存储每个键、每个窗口或全局的位置 该键的所有窗口的每个键信息。例如,如果要记录有关当前窗口的某些内容并在处理后续窗口时使用它,这可能很有用。globalState

你可能感兴趣的:(数据结构)