首页 > 解决方案 > Dataflow 状态处理中的 Exactly-once 语义

问题描述

我们试图在流设置中涵盖以下场景:

我将讨论我们正在考虑的三个选项,其中前两个选项容易丢失数据,而最后一个选项不清楚。我们想更深入地了解最后一个。当然也欢迎替代方法。

谢谢!


方法 1:会话窗口、数据存储和幂等性

  1. x 秒的滑动窗口
  2. 按用户 ID 分组
  3. 更新数据存储

更新数据存储意味着:

  1. 启动 trx
  2. 为该用户读取的数据存储
  3. 合并新信息
  4. 数据存储写入
  5. 结束 trx

数据存储条目包含等于滑动窗口时间戳的幂等性 id

问题:

Windows 可以同时触发,然后可以无序处理导致数据丢失(由 Google 确认)

方法:会话窗口、数据存储和状态

  1. x 秒的滑动窗口
  2. 按用户 ID 分组
  3. 更新数据存储

更新数据存储意味着:

  1. 预检查:检查此键窗口的状态是否为true,如果是,则跳过以下步骤
  2. 启动 trx
  3. 为该用户读取的数据存储
  4. 合并新信息
  5. 数据存储写入
  6. 结束 trx
  7. 存储我们处理过的这个关键窗口的状态 ( true)

重新执行将因此跳过重复更新

问题:

5 到 7 之间的失败不会写入本地状态,导致重新执行并可能计算元素两次。我们可以通过使用多个状态来规避这个问题,但是我们仍然可以删除数据。

方法 3:全局窗口、定时器和状态

基于文章Timely (and Stateful) Processing with Apache Beam,我们将创建:

  1. 全局窗口
  2. 按用户 ID 分组
  3. 在有状态的 DoFn 中缓冲/计数所有传入事件
  4. 在第一个事件后刷新 x 次。

同花将意味着与方法 1 相同

问题:

对一次性处理和状态的保证尚不清楚。如果在状态中写入元素并且重新执行捆绑包会发生什么?状态是否恢复到该捆绑包之前?

非常感谢任何指向这方面文档的链接。例如,容错如何与定时器一起工作?

标签: google-cloud-datastoregoogle-cloud-dataflowapache-beam

解决方案


从您的方法 1 和 2 中,不清楚乱序合并是数据丢失还是问题。我能想到以下几点。

方法1:不要因为乱序问题而立即合并会话窗口聚合。相反,将它们分开存储,并在足够的时间后,您可以按时间戳顺序合并中间结果。

方法 2:将状态移动到事务中。这样,任何临时故障都不会让事务完成并合并数据。会话窗口聚合的后续成功处理不会导致重复计算。


推荐阅读