分布式系统下数据最终一致性的实现策略

59 篇文章 0 订阅
54 篇文章 0 订阅

今天我们来讨论一下数据最终一致性的相关问题。这个问题在分布式环境下非常典型,我们可以通过一个具体的业务场景来进行说明,下面是这个业务场景的示例图:
图片
设想以下业务场景:系统中同时运行着两个关键服务——订单服务和积分服务。用户完成一笔订单后,订单信息需被记录到订单数据库中,同时,系统会根据订单金额给用户增加对应的积分。这一系列操作横跨了订单数据库和积分数据库,因此确保这两个服务间数据的一致性变得尤为重要。

因为这里的订单服务和积分服务是两个独立的微服务,所以保存订单信息和积分信息的实现过程伴随着一个典型的问题,也就是如何确保订单数据与用户积分数据的一致性。

虽然通过分布式事务,我们可以在一定程度上实现这一目标,但分布式事务提供的是一种强一致性方案,缺乏系统弹性和扩展性。为了更好地处理这一场景,我们将探讨数据最终一致性的三种实现模式,也就是可靠事件模式、补偿模式和 TCC 模式。
图片

一、可靠事件模式

我们先来看可靠事件模式。就像这个模式的名称所表明的,这个模式依赖于事件,可以认为是一种事件驱动架构的具体应用方式。但为了更好地保证数据在不同服务之间的一致性,我们还需要引入一些特定的实现技巧。

针对事件驱动架构,我们首先想到的实现方案是引入消息中间件。在可靠事件模式中,当订单服务和积分服务之间的数据需要进行统一管理时,我们引入消息中间件来完成数据的传递。接下来,我们看一下具体的操作流程。

流程的第一步,是用户进行订单付款流程。成功付款后,订单服务会首先保存这个订单信息,这是本地数据库操作,不涉及分布式场景。在这之后,订单服务会生成一条“订单支付完成消息”并发送到消息中间件。这一操作流程可以用下图加以表示:
图片
第二步是,当消息中间件接收到“订单支付完成消息”之后,把这条消息发送到积分服务。作为消息的消费者,积分服务会根据这条消息进行积分计算,并最终保存到本地数据库中。

请注意,因为消息发送和消费过程都可能出现异常,所以这时候积分服务需要发送一条“回执消息”给到消息中间件,这一过程可以用下图表示:
图片
在流程的第三步,我们再次来到订单服务,该服务收到积分服务发送的“回执消息”之后同样也会执行一定的业务逻辑,比方说设置订单的状态等。
图片
在整个流程中,很显然的一点是:我们需要确保消息发送和接收过程的可靠性,这也是“可靠事件”这一名称的由来。目前,诸如 RabbitMQ、Kafka 等主流的消息中间件都支持消息持久化操作,同时也具备消息至少被投递一次的功能特性,这在一定程度上能够确保消息的可靠传递。

二、补偿模式

我们要介绍的第二种模式是补偿模式。所谓补偿,是指对所有已生成的数据来说,都具备一种类似“撤销”的能力。在整个数据处理链路中,如果某一个环节出现了异常,那么我们就可以通过补偿机制恢复那些已经保存的数据。

让我们回到前面的案例。显然,如果在积分服务中针对用户积分的处理过程发生了异常,为了保证数据一致性,那么就应该同时取消原先的订单所生成的数据。为了达到这种效果,订单服务和积分服务都需要提供额外的补偿操作入口,而系统中也应该存在一个独立的补偿服务来根据业务运行结果统一调用这些入口。
图片
显然,如果想要实现补偿操作,我们需要明确补偿的对象。所以,通常的做法都是在各个微服务中保存详细的操作日志和对应的业务数据。

就今天讨论的案例而言,当用户发起一次操作时,系统需要为对应的请求生成全局唯一的操作编号,该编号会在整个调用链路中进行传递。同时,对于订单服务而言,需要根据这个唯一编号来更新业务状态。而在积分服务中,同样需要记录用户积分相关的流水信息和业务状态。
图片
一旦发生异常,例如用户积分计算失败,那么补偿服务就会执行补偿过程,它可以从操作日志和业务状态中知道补偿的范围以及对应的业务数据。

三、TCC 模式

讲完补偿模式,我们接着来看 TCC 模式。所谓的 TCC,实际上是三个操作的组合,即 Try(尝试)、Confirm(确认)和 Cancel(取消),它的基本结构如下图所示:
图片
在上图中,我们对 TCC 模式中的三个操作做一个展开。其中,Try 操作用于完成所有业务规则检查,对业务数据进行预先的处理;Confirm 操作则用来执行具体的业务操作;而 Cancel 操作实际上就是一种补偿操作,用户补偿 Try 阶段被占用的业务数据。

我们还是通过案例分析进一步理解 TCC 模式的设计思路,下图展示了基于 TCC 模式的用户操作流程。
图片
请注意,在上图中,Try、Confirm 和 Cancel 这三个操作具备严格的时序性,开发人员需要按顺序来依次执行这三个操作。接下来,我们同样结合具体的业务场景来分析各个操作的具体内容。

Try 阶段:进行业务规则检查,预留必要的业务资源。例如,检查订单金额是否足够,以及预扣库存等。
Confirm 阶段:若 Try 阶段成功,则执行实际的业务操作,如完成订单处理并正式扣除库存,同时向积分服务发送积分发放请求。
Cancel 阶段:若发生异常,则释放 Try 阶段预留的资源,并执行相应的补偿操作,如撤销订单并恢复库存,同时通知积分服务撤销积分的发放。
讲到这里,我们可以把 TCC 模式看作是对补偿模式的一种优化。一方面,在 TCC 模式中,我们把如何对数据进行补偿这一过程进行了拆分,从而能够让开发人员更好地完成补偿数据的管理,业务系统和补偿服务之间的分工也更加明确。另一方面,正如上面图中所示的那样,基于 TCC 模式,补偿服务通常被设计成一种平台化的框架,这种框架能够协调各个服务中 Try、Confirm 和 Cancel 操作的时序,典型的例子就是阿里巴巴开源的 Seata TCC 框架。

总结
数据一致性是一个重要且复杂的话题。今天,我们基于典型的案例,对如何实现分布式环境下的数据最终一致性的思路和方案做了分析,并提供了业界具有代表性的几种实现模式,包括可靠事件模式、补偿模式和 TCC 模式。

对于可靠事件模式来说,它依赖于事件,可以认为是一种事件驱动架构的具体应用方式;对于补偿模式来说,它侧重于通过补偿机制恢复那些已经保存的数据处理链路中的数据;对于 TCC 模式来说,我们可以把它看作是对补偿模式的一种优化,这些模式各都有各的设计思想和功能特性。

当然,无论采用哪一种模式,想要实现最终数据一致性,开发人员还需要准备一种最基础的处理机制,即人工干预机制。可以认为基于业务数据进行人工的补偿就是一种兜底方案,这也是在使用这些数据最终一致性模式时同时需要考虑的重要一点。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值