事件溯源和事件驱动,被混用得最严重的一对架构词
“我们用了事件驱动,所以也算事件溯源吧。”这句话在架构评审里出现的频率不低,但两者解决的问题几乎没有重叠。混淆它们的代价不是概念不准确,而是该存的东西没存,不该存的存了一堆。
事件驱动描述的是通信方式:组件之间通过事件异步传递消息,生产者不知道消费者是谁,消费者按兴趣订阅。订单创建后发一条 OrderCreated 消息,库存服务扣减、通知服务发邮件、积分服务加积分,彼此不直接调用。它的核心价值是解耦和削峰,事件是“通知”,处理完通常就可以丢弃。
事件溯源描述的是状态存储方式:不保存实体的当前状态,而是保存导致状态变化的所有事件序列,当前状态由事件重放得出。订单不是一条 status = 'shipped' 的记录,而是一串 OrderCreated、OrderPaid、OrderShipped 事件,每次查询时按顺序重放,得到当前状态。它的核心价值是完整的审计轨迹和时间旅行能力,事件是“事实”,必须持久保留。
两者可以组合,但组合方式决定了系统复杂度。如果只用事件驱动,消息队列消费完就删,你得到的是解耦,不是审计;出问题回溯时只能看日志,而不是重放事实。如果只用事件溯源而不需要异步通信,事件存在事件存储里,投影出读模型,系统是同步的,只是存储模型不同。很多团队真正需要的其实是事件驱动加变更日志,而不是完整的事件溯源——后者要求聚合边界清晰、事件版本管理、投影重建、最终一致性处理,是一套完整的工程体系,不是“把消息存起来”就完事。
一个实用的判断顺序:先问“我需要的是解耦还是审计”。需要解耦,用事件驱动,消息可以不持久;需要审计和状态重建,才考虑事件溯源。再问“我能不能接受最终一致性”。事件溯源天然带来读写分离和投影延迟,如果业务要求强一致读,要么在投影层做同步等待,要么重新考虑是否真的需要事件溯源。最后问“事件 schema 能不能稳定”。事件是长期事实,一次发布之后可能几年都要能被重放,schema 演进策略必须提前设计,否则重放历史事件时旧版本解析不了。
混用最典型的症状是“事件存了但没人重放”。团队建了事件表,写入了所有变更,但查询仍然走当前状态表,事件表只用来审计。这不是事件溯源,这是变更日志,而且通常可以用 CDC 更低的成本实现。先明确你要的是通信解耦、审计轨迹还是状态重建,再决定事件该存多久、存在哪、谁来消费。
- 点赞
- 收藏
- 关注作者
评论(0)