▼ 场景 一个转账业务操作,需要同时调用记账服务(Account Service - AS)和支付服务(Payment Service - PS),需要满足要么同时成功;要么同时失败。记账服务和支付服务可能是多个不同部门开发、部署在不同服务器上的远程服务。 ▼ 分布式事务解决方案 我们可以使用分布式事务将记账操作和支付操作变为一个整体操作。好处很明显,可以实现数据强一致性,但是分布式事务由于有很多的同步操作, 对系统的吞吐量和请求的响应时间产生较大的影响。
思考 在工程实践上,为了保障系统的可用性,互联网系统大多将强一致性需求转换成最终一致性的需求,并通过系统执行幂等性的保证,保证数据的最终一致性。但在电商等场景中,对于数据一致性的解决方法和常见的互联网系统(如 MySQL 主从同步)又有一定的区别。
▼ 消息及补偿机制 另外一种方式是使用消息及补偿机制来确保最终一致性,并同时避免分布式事务。此方案的核心是将需要分布式处理的任务通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或消息队列,再通过业务规则自动或人工发起重试。人工重试更多的是应用于支付场景,通过对账系统对事后问题的处理。
▼ 业务设计 如果大家读过 Domain Driven Design 这本书,在领域设计中,当领域对象 Aggregator 状态发生变化时,它会发布领域事件(Domain Event)给订阅方。我们可以使用领域事件来追踪领域对象的变化并用于维护事件的一致性。 原有的做法: · 同步方法 · 要么转账成功,要么转账失败 现在的做法: · 异步方法 · 增加新的状态,例如转账中 · 增加重试机制,尽可能保证转账成功 ▼ 领域事务与事件 领域事务(Domain Transaction) · ID(全局唯一) · Status · 服务事件列表 领域事件(Domain Event) · ID(全局唯一) · DT_ID(领域事务ID) · System · Type · Status · Timestamp · Message 示例:转账领域事务 · 转账开始事件 · 转账记账完成事件 · 支付完成事件 事务状态由事件决定
▼ 事务流程图 ▼ 对账及补偿机制 · 对账机制:业务层面宏观监控,例如入账/出账总账平衡 · 重试机制:如果某一步未执行,则重发已经记录的领域事件 · 回滚机制:如果某一步执行失败,则根据领域事件依次回滚之前的操作 · 去重机制:利用事务 ID 和事件 ID 来去重
总结 这里我们使用事件机制和补偿机制实现了一种数据一致性的解决方案。该方案具备高吞吐量及低响应时间的特性,但是在某些服务失败场景下会存在数据不一致的情况,需要通过业务设计(引入新的中间状态),对账机制,重试机制,回滚机制等机制来确保数据最终一致性。
微服务的 Event Sourcing(事件溯源)和 Command Query Responsibility Separation (CQRS) 模式则天然能够更好支持这种数据一致性方案,我们会在下一篇文章《使用 Axon 框架实现 CQRS 和 ES》中进行详细描述并给出示例实现。 推 荐 阅 读 点击标题即可阅读 |
|