事件源核心概念
事件溯源是一种功能强大但又复杂的模式,常用于现代软件架构中,尤其是在 C# 和 .NET Core 应用程序中。 为了充分理解如何实现事件溯源,我们将按照CodeOpinion.com的 Derek Comartin 在他的视频" 事件溯源核心概念"中解释的关键原则进行讲解。
如果您想更好地了解事件存储概念、领域驱动设计或如何构建事件溯源系统,那么您来对地方了。 让我们深入了解!
事件溯源简介
在视频开头(0:00),Derek 讨论了人们对事件溯源及其相关核心概念的困惑。他将事件溯源定义为不仅仅是"捕获当前状态",而是存储事件——将领域模型发生的每一次变化都记录在一个只追加的日志中。
这样,您就可以完整地保存系统状态变化的历史记录。 与其只持久化最终状态,不如持久化反映所发生业务逻辑的事件。
事件:捕捉商业事实
在 0:33,德里克解释了什么是真正的事件。 事件代表系统中已经发生的事情——一个业务事实。 例如,"ProductReceived"事件将包含收到的数量和日期。
Derek 强调,存储事件时,必须使用反映过去时的命名约定来命名,例如"产品已发货"或"库存已调整"。 在事件架构中,您可能会有诸如公共 Guid ID、公共字符串名称和时间戳之类的字段。

每个事件都应该有一个唯一的标识符,这对于仅追加存储系统至关重要,因为在这种系统中,事件是追加到事件流中的。
活动流程:组织活动
2:02,Derek 转入事件流。 他将其与关系数据库表进行比较,并解释说,在事件溯源中,与领域对象(例如库存项目)相关的所有事件都属于同一个事件流。
每个事件流都与一个特定的实体相关联——通常由一个公共 Guid ID 和一个字符串名称定义。 例如,SKU 为 ABC123 的产品将拥有自己的数据流,其中包含收货或发货等持久化事件。
Derek 建议,在对这些进行建模时,要从聚合根和领域对象的角度来思考,借鉴领域驱动设计的概念。
对生命周期(无论是短寿命还是长寿命)进行建模有助于优化流的数量和规模。 这对于提高复杂系统的性能至关重要。
预测和读取模型
4:12,Derek 介绍了预测和读取模型。 由于您的事件溯源系统捕获的是事件而不是当前状态,因此您必须重放事件才能回答诸如"当前库存数量是多少?"之类的问题。
要构建读取模型,您需要处理来自流的事件。 例如,使用 private void Apply(Event e) 或类似方法,您可以根据每种事件类型的事件处理程序来增加或减少股票数量。
Derek 演示了如何在文档数据库或关系数据库中构建读取模型——也许一个投影只是简单地显示现有数量,另一个投影显示发货历史记录。
这体现了命令查询职责分离(CQRS):将写入操作(命令)与读取操作(查询)分开。
针对写入模型的预测
6:48,Derek 展示了如何在写入端应用投影。 这对于在允许行动发生之前对其进行验证至关重要。
在命令处理程序中,发货前需要验证产品数量是否充足。 Derek 使用了类似 private void Apply(List) 的方法
诸如 public int Version 之类的字段有助于跟踪流的演变,确保最终一致性。

这种实际应用有助于在处理新事件时强制执行业务逻辑,确保您的系统只对有效的状态转换执行操作。
订阅:对新事件做出反应
8:01,德里克谈到了订阅服务。 订阅功能让活动消费者可以监听新活动并做出反应。
例如,投影仪可以订阅事件流,并在看到"产品已发货"事件时更新读取模型。 或者,发布者可以监听事件并将其发布到 RabbitMQ 或 Kafka 等外部系统,与其他服务集成。

Derek 描述的订阅不仅用于更新内部模型,还用于在不同的事件系统之间分发数据,从而保持最终一致性。
这展现了事件驱动架构的另一个主要优势:您的服务最终保持一致性,但可以独立扩展。
核心概念回顾
9点21分,德里克总结了核心概念:
事件反映事实。
事件流按实体组织事件。
- 投影将流转换为可查询的读取模型或可操作的写入模型。
订阅功能允许服务做出相应的反应和更新。
他强调,应将事件持久化到仅追加日志中,维护审计跟踪,并在必要时重放事件。
快照和优化
9:39,Derek 讲解了快照功能。 虽然快照经常与事件溯源一起被讨论,但他澄清说,快照是一种性能优化,而不是核心需求。
快照通过定期保存部分状态来减少重放所有事件的开销,但完整的历史记录仍然通过仅追加日志存在。
主要区别:事件溯源与事件驱动架构
10:00,Derek 提醒大家注意一个常见的误解:事件溯源和事件驱动架构是不同的! Kafka 等工具可以帮助进行数据分发,但真正的事件溯源侧重于将领域事件记录为不可变的审计跟踪。
在将事件溯源集成到复杂系统中时,理解这种区别至关重要。
结论
看完 Derek Comartin 的视频后,很明显,事件溯源是指将每一次变化都记录为一个事件,而不仅仅是最终状态。 通过将事件存储在仅追加存储系统中,您可以构建丰富的事件模式,从而提供审计跟踪、灵活的事件查询以及对命令查询职责分离的强大支持。
无论你是在 .NET Core 还是任何其他平台上处理 C# 事件溯源,Derek 对核心概念、事件处理程序、私有集、受保护集以及在模型中应用事件(例如 private void Apply())的结构化解释都非常有价值。
如果你正在构建弹性域模型、改进存储系统,或者创建具有最终一致性等诸多优势的复杂模式,那么研究 Derek 的方法是必不可少的。也请关注他的YouTube 频道,那里有更多精彩的视频。

