Skip to content

确定性流处理 = 可重放可测试的事件处理 ​

解决什么问题:同一输入流多次处理结果不一致—— 确定性流处理保证"同一流 → 同一结果",让重放、测试、恢复都简单。

业务问题 ​

真实场景 ​

场景 1:订单事件流的非确定性

python
# 反模式:非确定性处理
def process_order_event(event):
    order = parse(event)
    order.processed_at = datetime.now()  # 时间依赖
    if random.random() > 0.5:            # 随机依赖
        order.priority = "HIGH"
    response = call_external_api(order)  # 外部依赖
    return response

# 问题:
# - 多次处理同一事件 → 每次结果不同
# - 测试无法稳定
# - 失败后重放结果不一致

Bellemare Ch 6 原话:

"Deterministic Stream Processing... The same input stream produces the same output stream. This allows for testing, replay, and recovery."

失败模式 ​

失败模式后果
时间依赖多次处理结果不同
随机数不可重放
外部 API不一致
多线程顺序同输入不同结果

控制论视角 ​

Ch 4 §4.6:"没有反馈,就没有自动控制" + Ch 6 §6.7:"可重复性是控制律的基本要求"

确定性流处理 = Ch 4 §4.6 可重复性
  - 控制律对同一输入必须产生同一输出
  - 事件流是控制律的输入
  - 确定性 = 控制律可验证、可重放、可调试

对位:

  • 事件流 = 控制律输入
  • 处理函数 = 控制律
  • 确定性 = 控制律的可验证性
  • Watermark = 时间同步机制

核心概念 ​

确定性 vs 非确定性 ​

维度确定性非确定性
输入相同 → 输出相同是否
可重放是否
可测试是难
可恢复是难
性能可预测难预测

三个时间概念 ​

Broker Ingestion Time(Broker 摄取时间):
  - 事件进入 broker 的时间
  - 唯一确定(broker 控制)
  
Consumer Ingestion Time(消费者摄取时间):
  - 消费者读到事件的时间
  - 因消费者速度而异(**不可重放**)
  
Event Time / Processing Time:
  - 事件实际发生的时间 vs 处理时间
  - 关键区分:处理可能延迟

Watermark(水位线) ​

Watermark = "事件时间 t 之前的数据都已到达"

作用:
  - 处理乱序事件(late events)
  - 触发窗口计算
  - 检测数据完整性
  - 推进处理进度

Bellemare 强调:分布式系统时钟不同步是常态,确定性处理必须基于 event time + watermark。

窗口类型 ​

Tumbling Window(翻滚窗口):
  - 不重叠、固定大小
  - 例:每分钟统计订单数
  
Sliding Window(滑动窗口):
  - 重叠、固定步长
  - 例:最近 5 分钟内订单数(每分钟更新)
  
Session Window(会话窗口):
  - 基于活动间隔
  - 例:用户会话(30 分钟无活动则结束)

确定性原则 ​

原则 1:处理函数无副作用
  - 不依赖外部状态
  - 不调用随机数
  - 不调用外部 API(或结果缓存)
  
原则 2:基于事件时间
  - 用 event time 而非 processing time
  - watermark 推进时间
  
原则 3:相同 key 顺序处理
  - 同一分区顺序处理
  - 保证同 key 事件不并发

工程实践 ​

实战 1:确定性处理模板 ​

python
def deterministic_process(event):
    # ✓ 用事件自带的时间戳
    event_time = event.timestamp
    
    # ✓ 用事件自带的 ID 作为随机种子
    seed = hash(event.id)
    
    # ✓ 不调用外部 API(如果需要,先查询并放入事件)
    # external_data = call_api(...)  # ✗ 反模式
    
    # ✓ 纯函数:输入相同 → 输出相同
    result = pure_transform(event, event_time, seed)
    
    return result

实战 2:处理非确定性需求 ​

场景 1:需要时间戳怎么办?
  - 用事件时间戳(自带)
  - 或注入(测试时)
  
场景 2:需要随机数怎么办?
  - 用事件 ID 作为种子
  - 或预生成随机数并放入事件
  
场景 3:需要外部数据怎么办?
  - 改为异步查询(先发请求,事件携带结果)
  - 或缓存到事件流

实战 3:Watermark 推进 ​

策略:
  - Periodic Watermark:周期性发出
  - Punctuated Watermark:特殊事件触发
  
例(Flink):
  env.set_stream_time_characteristic(TimeCharacteristic.EventTime)
  stream.assign_timestamps_and_watermarks(
      WatermarkStrategy
          .for_bounded_out_of_orderness(Duration.of_seconds(5))
  )

反模式 vs 正模式 ​

反模式正模式
用 datetime.now()用事件 timestamp
random.random()用事件 ID 作 seed
调用外部 API数据预先放入事件
多线程处理同 key同 key 顺序处理

性能指标 ​

指标衡量健康值
确定性保证多次处理结果一致100%
Watermark 延迟事件时间 vs 当前水印< 10s
Late event 比例迟到事件 / 总事件< 1%
重放成功率失败后重放恢复100%

边界判断 ​

何时必须确定性(★ 强烈推荐) ​

  • 金融交易
  • 状态物化
  • 事件溯源
  • 测试环境

何时可放宽 ​

  • 纯通知类事件
  • 监控指标
  • 一次性处理

何时升级 ​

当前升级到触发条件
非确定性确定性重放/测试需求
Processing timeEvent time乱序/延迟场景

关键洞察 ​

  1. 确定性 = 可重放——这是分布式系统测试和恢复的基础。
  2. 事件时间 vs 处理时间——用事件时间才能处理乱序。
  3. Watermark 是分布式时钟——没有它,多分区无法协调。
  4. 副作用是确定性的天敌——纯函数才能保证可重放。
  5. 与 cybernetics 同构——Ch 4 §4.6 可重复 = 确定性 = 控制律的基本要求。

从名家方法论与工程化思路中蒸馏出自己的工程体系。