注意:以下翻译的准确性尚未经过验证。这是使用 AIP ↗ 从原始英文文本进行的机器翻译。
Foundry管道提供有状态的数据流变换,以快速流式传输速度实现复杂的数据变换行为。
在数据流中,当每个输出行可能依赖于先前处理的行中包含的信息时,数据变换是有状态的。行间持久存在的信息称为状态。每行可以访问和改变状态。
有状态变换的一个例子是求和聚合变换。考虑下表,其中可以使用求和聚合变换来计算每天具有hot
值的传感器读数的数量。最新流入的行在表中较高。
Day | SensorReading | Timestamp |
---|---|---|
Monday | hot | 3 |
Monday | cold | 2 |
Monday | hot | 1 |
一个有状态的求和聚合变换计算每天hot
读数的实时运行数量,其输出可能如下所示:
Day | SensorReading | Timestamp | State |
---|---|---|---|
Monday | hot | 3 | 2 |
Monday | cold | 2 | 1 |
Monday | hot | 1 | 1 |
有状态变换可以存储任何可序列化类型的状态,包括整个行,这使得它们能够实现复杂的行为。Pipeline Builder中的状态变换是预构建的,并自动处理状态类型及其演变方式。
状态的内容并不总是用户可访问的。状态可以用于支持后端处理行为。例如,在数据管道Flink任务中读取流输入源将存储每个分区的最后偏移量状态;这使得任务能够在失败或重启后从上次成功点恢复。
Foundry数据流使用Flink架构提供低延迟的数据管道;每行在处理后立即计算并传递到下一个操作。与批处理变换不同,流变换逐行确定下一个输出,而不是查看完整的数据。
对于非有状态(也称为无状态)流变换,这种架构意味着变换逻辑只能依赖于一行。例如,一个无状态变换总是可以将整数列加5。
相比之下,有状态流变换可以访问以前行的持久数据,同时仍然能够逐行处理,并在它们到达时立即处理。
Foundry有状态流提供精确一次保证选项,这是默认的管道配置。当选择时,导致状态变更的行被保证每个键精确且按顺序地变更状态。这使得精确和复杂的数据流行为成为可能。
例如,如果您打算求和,即使流重启或出现故障,您的求和结果也将始终准确。如果使用排序,即使在任务中排序过程中重启任务,任务已产生部分排序输出不再实时,排序也将始终对每个输入只生成一个输出。
所有Pipeline Builder有状态流变换都使用键控状态,并要求用户指定分区键列。有状态变换对于具有不同键列值的行分别处理。这允许后端并行化处理并扩展到大数据量。
例如,考虑有状态求和聚合示例,计算每天hot
读数的实时运行计数。请注意,在此示例中,Day
列被用作分区键。
Day | SensorReading | Timestamp | State |
---|---|---|---|
Tuesday | hot | 5 | 1 |
Monday | hot | 4 | 2 |
Tuesday | cold | 3 | 0 |
Monday | cold | 2 | 1 |
Monday | hot | 1 | 1 |
注意,状态独立于Day
值为Monday
的行和值为Tuesday
的行计算。Tuesday
键值行的出现不影响Monday
的存储内容,并且如果有更多行到达Day
列中具有不同值(如Wednesday
),这些键的状态将不受影响。
键应仔细选择,因为导致记录分布不均的键可能人为增加负载并限制吞吐量。参见流键最佳实践。
有状态流变换通常依赖于时间信息。因为流是持续的,并且可能随时接收到新的实时行,所以将时间上接近的行分组在一起通常是有意义的。例如,外部缓存合并变换仅在它们共享合并列的值并且行的时间戳在过期限制内时,将两个输入流的行合并在一起。Pipeline Builder流使用Flink事件时间以接近确定性的方式实现有状态变换,这将在重放时产生相同或非常相似的输出。
Pipeline Builder中执行基于时间的操作的有状态变换需要在上游进行指派时间戳和水印变换,并且如果在您的管道图中缺少它,将产生验证错误。指派时间戳和水印为每行分配一个"事件时间",通常是行中包含的时间戳列。水印是每个变换操作的近似确定性"当前时间"的概念,是一个单调递增的值,紧跟在任何输入行中看到的最大事件时间值之后。例如,当外部缓存合并确定缓存中的条目是否已过期时,它检查水印是否大于或等于过期时间,这只有在合并已接收到至少具有该事件时间的输入行时才为true。
对于单个流输入的变换操作符,水印是每个并行实例看到的最大事件时间行的最小值。对于具有多个流输入的变换,水印是输入的水印的最小值。
重放将产生相似但有时略有不同的输出。这是因为在重放时,不同的分区键可能被分配给不同的Flink并行实例,并且具有多个输入的操作符可能在上游以不同的速度处理。Flink处理时间不被支持且不被推荐,因为它在重放时可能产生显著不同且可能不直观的结果。
存储大型状态可能导致性能瓶颈,负面影响吞吐量和延迟,因此Pipeline Builder要求用户限制状态大小。
通常,状态通过用户提供的缓存时间过期来限制。对于需要缓存时间参数的有状态变换,状态通常存储在每个键的状态缓存
中,直到水印超过该键所见的最后事件时间加上过期。
聚合窗口变换允许用户设置*窗口,这是将行及其状态分组在一起的策略,以及触发器*,这是聚合应何时产生输出的策略。
当前支持的窗口有:
依赖时间的窗口(例如滚动事件时间窗口和会话窗口)将在水印足够推进时最终关闭。
依赖时间的窗口还允许指定自定义触发器。
当前支持的触发器有:
大型状态可能对性能产生负面影响,因此在设计有状态管道时,建议使用尽可能紧凑的状态过期策略。这通常意味着不要将缓存时间过期设置得比必要的大,也不要为计数窗口设置比必要大的计数。
对于需要大型状态的管道,性能(包括吞吐量、检查点持续时间和延迟)随着Flink任务的并行性而扩展。并行性可以在流管道设置中编辑,较大的并行性允许增加的数据处理能力以及状态读写速度。
适当的键应为有状态变换选择,因为键列的值过多或行分布不均衡可能导致瓶颈或扩展问题。