5.3.1 可靠事件队列

Dan Pritchett 的论文中采用”可靠事件队列“的方式实现最终一致性,可靠事件队列是一种事件驱动模式,关键在于可靠事件的投递和避免事件重复消费。现在流行的消息中间件都实现了事件的持久化和 at leastonce 的投递模式,幂等性的实现也有了成熟的方案。下面笔者以一个具体的说明 Dan Pritchett 提出的”可靠事件队列“的具体做法。

例如,在一个电商系统中,下单需要三个服务支持。

  • 访问支付服务,通知银行扣款
  • 访问库存服务,扣除购买商品的库存
  • 访问积分服务,为用户增加积分。

在这个模型中,最核心、出错影响最大的服务优先处理,即:支付扣款 -> 仓库出库 -> 为用户增加积分。

  • 支付服务进行扣款操作,如果扣款成功,则在自己的数据库内建立一张消息表,表内如下结构:事务ID,扣款¥100(状态:已完成),仓库出库(状态:待进行),赠送积分(状态:待进行)。
  • 在系统内建立一个消息服务,定时轮询消息表,将状态是”进行中“的消息同时发送到库存和积分服务区。这个时候会产生以下几种情况:
    • 库存服务和积分服务都顺利完成了出库和加分的工作,向订单服务返回执行结果,账单服务把消息改为”已完成“。整个事务顺利完成,最终实现一致性。
    • 库存服务和仓库服务完成了收款和,但回复的消息因为网络问题丢失了,此时订单服务仍会重复发出下一条消息,但因为操作具备幂等性,所以不会导致重复出库等,只会导致仓库服务重新发送一条应答消息,此过程持续自动重复至双方通信恢复正常。

BASE 理论应用

BASE 理论应用与多个微服务之间的调用。微服务的架构中,一个用户的请求往往需要多个服务配合才能完成,对于一个强一致性系统的可用性,都是所依赖服务可用性的乘积,例如,在一个事物中,涉及三个服务的操作,假设每个服务的可用性为 99.9%,则整个事务的可用性为 99.9% * 99.9% * 99.9% ≈ 99.7%

现代的应用架构中,通常由几十甚至几百个微服务组成,对于如何提高整体系统的可用性,可用 BASE 理论进行指导,在允许存在软状态的基础上,我们只需要保证整个事务的基本可用性和最终一致性即可,并不需要保证实时一致性,保障性的设计,通常采用异步补偿机制。

如果采用异步补偿机制,则需要明确哪些操作属于非关键操作,如果非关键操作失败,允许业务流程继续执行,然后再异步补偿非关键操作,以此降低非关键操作失败对整个事务的影响。

在上述电商案例中,我们可以将积分服务定义为非关键操作,非关键操作失败后,可以通过定时任务或者消息队列在下单完成后再给用户增加积分。而支付以及库存操作为关键操作,当其中任意一个发生故障时,我们都需要回滚本次事务。

采用异步补偿机制需要注意以下几点:

  • 每个补偿操作都应该设置重试机制,且需要实现幂等。
  • 整个事务应由工作流驱动,记录每个分支操作的处理结果。
  • 对于所有分支事务,都需要提供回滚事务的接口。
Last Updated:
Contributors: isno