在开发微服务的过程中,分布式数据管理是必须解决的问题。不同服务数据库选择的多样性,事务问题及跨服务的数据查询都是我们要面对的挑战。
对于大多数应用而言,要实现微服务和管理分布数据,都需要采用事件驱动架构。在事件驱动架构中,某个服务在发生重要事情的时候,比如,创建一个订单会发布一个事件,而其他服务订阅这些事件。作为对事件的回应,接收事件的服务通常会更新自身的状态,或许会发布更多事件,让其他服务进行更新。
我们分析一下上述用例,我的的业务代码必需完成在MySQL数据库中加入订单相关数据并将事件发布到Kafka中。如何避免不一致性发生,保证这两个操作在同一个事务中呢?
传统方法中,我们可以使用包含数据库和消息代理的分布式事务,但我们都知道分布式事务带来的诸多问题与限制,。然而,事件溯源(Event Sourcing)也是一个不错的办法。它已经存在了几十年,直到Greg Young用于DDD中后,逐步流行了起来。
这里我们借助Martin Fowler对事件溯源给出的一些解释:
事件溯源的核心理念是说,在对系统的状态做出变更时,把每次变更记录为一个事件,在未来的任何时刻,都可以通过重新处理这些事件来重建系统的状态。事件存储是主要的事件来源,可以从事件存储中重建系统的状态。对于程序员来说,版本控制系统是一个最好的例子。提交日志就是事件存储,而代码工作副本就是系统状态。在某个指定的工作副本上重播提交日志就可以创建另一个工作副本,也就是重建了某个时刻的系统状态。
拿订单为例,在整个订单的生命周期中所发生的重要的事情,都会记录在事件存储中。
再看看事件事件溯源是如何工作的:
这里的订单是订单服务中的订单聚合,可能有的读者会问,这样的架构怎样解决订单更新与保存的一致性呢?其实订单没有对应的MySQL数据库,只存在于内存中,需要持久化的只有订单业务过程中的领域事件,保存在了事件存储中,单一的存储类型,这样就不存在一致性问题了。
关于不同服务的joins问题,事件溯源推荐使用CQRS架构,将查询与事件处理分离,在DDD中我们会定义成领域报告。详细内容后续文章会有处理。