← 中文资源

简体中文版本

事件溯源

事件溯源把状态视为按序应用事件的结果:追加不可变事实,用投影支撑查询,并以快照限制重放时间。

阅读英文原文

状态是对事件的折叠

传统模型把订单行更新为 paid;事件溯源模型则追加 OrderPlaced 和 PaymentCaptured,当前状态是按序应用这些事件的结果。对单个聚合而言追加是原子的,事件是不可变事实。

CREATE TABLE events (
  aggregate_id text NOT NULL,
  version      bigint NOT NULL,
  event_type   text NOT NULL,
  payload      jsonb NOT NULL,
  created_at   timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (aggregate_id, version)
);

(aggregate_id, version) 主键实现乐观并发:两个写者在同一预期版本追加会冲突,其中一个必须重试。加载聚合时从最近快照读取事件并向前折叠。快照限制重放时间,它们是优化而非事实来源。

读取需要投影

为每个查询折叠全部事件无法扩展。投影消费事件流并写入反规范化的读模型,每个投影记录自己的位置以便重启后续传。投影可以从日志重建,这在读模型出错或需要新视图时很有价值。

事件流与投影是最终一致的。写入后立即读取的用户可能看到旧投影。界面要么对一致性敏感的操作读取写模型,要么明确告知延迟。不要把投影伪装成同步。

事件是契约

投影、其他服务和分析都会消费事件。重命名字段或改变含义会破坏消费者。要为事件模式做版本管理,保持增量变更兼容,并在读取时用 upcaster 转换旧事件。绝不要原地重写历史事件;应追加更正事件。

何时使用

当审计历史、重放或多个读模型是核心需求,且团队有能力运维投影和模式演进时,使用事件溯源。优点是持久、可查询的历史;代价是复杂度:最终一致性、存储增长、快照和事件版本化。与 CRUD 加审计表相比,事件溯源让历史成为一等公民,但每次读写都需要不同的心智模型。