Skip to content

事件结构 3 类型 = 业务事实的不同粒度 ​

解决什么问题:不知道该用什么结构的事件—— 事件结构的选择直接决定下游能否物化完整状态。

业务问题 ​

真实场景 ​

场景 1:电商订单事件的设计选择

选项 A:Unkeyed Event
  {"action": "OrderCreated", "timestamp": 1234567890}
  → 消费者只知道"有事发生",无法关联具体订单

选项 B:Entity Event
  {"orderId": "123", "action": "OrderCreated", "timestamp": ...}
  → 消费者能关联订单,但不知道完整状态

选项 C:Keyed Event
  {"key": "order-123", "value": {"status": "CONFIRMED", "amount": 99.99}}
  → 消费者能完整重建订单状态

Bellemare Ch 2 原话:

"Events are typically represented using a key/value format. The value stores the complete details of the event, while the key is used for identification purposes, routing, and aggregation."

失败模式 ​

失败模式后果
事件信息不足消费者需查 DB 补全(紧耦合)
过度携带信息事件臃肿、性能浪费
缺少 key无法路由、无法聚合

控制论视角 ​

Ch 4 §4.6:"反馈必须包含受控对象的关键状态" + Ch 15:"测量必须能重建状态"

事件 = 控制律的输出信号
  - Key = 路由标识(哪个对象)
  - Value = 完整状态(让接收方重建)
  - 缺 Key = 无法定位对象(信号无地址)
  - 缺 Value = 无法重建(信号不完整)

核心概念 ​

事件 3 类型对比 ​

类型KeyValue用途例子
Unkeyed Event无简单描述通知/广播"系统启动"
Entity Event实体 ID实体变更生命周期追踪OrderCreated(orderId=123)
Keyed Event实体 ID完整当前状态状态重建Order(123, status=CONFIRMED)

Unkeyed Event(无 Key) ​

json
{
  "action": "UserLoggedOut",
  "timestamp": 1700000000
}

适用:

  • 全局通知
  • 不需要后续关联
  • 一次性事件

Entity Event(实体事件) ​

json
{
  "orderId": "123",
  "action": "OrderConfirmed",
  "confirmedAt": 1700000000
}

适用:

  • 实体生命周期追踪
  • 触发下游处理
  • 不携带完整状态

Keyed Event(键值事件) ​

json
{
  "key": "order-123",
  "value": {
    "orderId": "123",
    "status": "CONFIRMED",
    "amount": 99.99,
    "customerId": "cust-456",
    "items": [...],
    "confirmedAt": 1700000000
  }
}

适用:

  • 状态重建(物化)
  • 事件溯源(Event Sourcing)
  • 完整的快照

决策矩阵 ​

业务场景:
  1. 事件需要路由到特定下游?
     - 是 → 需要 Key(Entity 或 Keyed)
     - 否 → Unkeyed 即可
     
  2. 消费者需要重建实体状态?
     - 是 → Keyed Event(最完整)
     - 否 → Entity Event 即可
     
  3. 事件源是 Event Sourcing?
     - 是 → 必用 Keyed Event
     - 否 → 看下游需求
     
  4. 业务是简单通知?
     - 是 → Unkeyed

工程实践 ​

实战 1:电商订单事件流设计 ​

Producer: OrderService
  OrderCreated (Entity Event)
  OrderConfirmed (Entity Event)  
  OrderShipped (Keyed Event)  ← 含完整订单状态供物流订阅
  OrderCancelled (Entity Event)
  
Consumer 1: InventoryService
  监听 OrderCreated → 扣库存
  
Consumer 2: ShippingService
  监听 OrderShipped → 创建运单
  需要完整订单信息 → 用 Keyed Event
  
Consumer 3: AnalyticsService
  监听所有事件 → 统计

实战 2:避免事件臃肿 ​

反模式:所有事件都是 Keyed
  - OrderCreated 也带完整订单(含未来才会有的字段)
  - 浪费带宽
  
正模式:按需选择
  - 简单通知 → Unkeyed
  - 状态变更 → Keyed
  - 触发动作 → Entity

反模式 vs 正模式 ​

反模式正模式
所有事件无 Key按需选择 Key
所有事件都全量按下游需求选择结构
事件缺少上下文(时间戳)总是带 timestamp
多个事件类型混用每类型明确语义

性能指标 ​

指标衡量健康值
事件大小平均字节数< 1 KB
Key 覆盖率带 Key 事件比例> 70%
路由效率Key-based routing 比例> 80%
下游重建率消费者从事件重建状态的比例> 60%

边界判断 ​

何时用 Unkeyed(< 10%) ​

  • 全局通知
  • 系统级事件
  • 不需要路由

何时用 Entity Event(最常用) ​

  • 实体生命周期追踪
  • 触发下游处理
  • 简单业务

何时用 Keyed Event(< 30%) ​

  • 状态物化需求
  • 事件溯源
  • 多下游需要完整状态

何时升级 ​

当前升级到触发条件
UnkeyedEntity需路由
EntityKeyed下游需重建

关键洞察 ​

  1. Key 决定路由能力——无 Key = 无路由 = 单消费者。
  2. Value 决定重建能力——值越完整,下游越独立。
  3. 按需选择——不是所有事件都需要 Keyed,过度设计浪费。
  4. Keyed Event 是 Event Sourcing 的基础——状态变更 = 完整快照序列。
  5. 与 cybernetics 同构——事件结构 = Ch 15 测量的完整度,缺 Key = 测量无地址。

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