分布式系统设计中关于数据一致性的问题

分布式系统设计中关于数据一致性的问题

举例说明

  在电商等业务中,系统一般由多个独立的服务组成,如何解决分布式调用时候数据的一致性? 具体业务场景如下,比如一个业务操作,如果同时调用服务 A、B、C,需要满足要么同时成功;要么同时失败。A、B、C 可能是多个不同部门开发、部署在不同服务器上的远程服务。
  例如:用户下了一个订单,发现账户里面有余额,然后使用余额支付,支付成功之后,订单状态修改为支付成功,然后通知仓库发货。假设订单系统,支付系统,仓库系统是三个独立的应用,是独立部署的,系统之间通过远程服务调用。订单的有三个状态:I-初始、P-已支付、W-已出库,订单金额100, 帐户余额200。正常情况下,订单的状态会变为I->P->W,帐户余额100,订单出库。但是如果流程不顺利了呢?考虑以下几种情况:
 【1】订单系统调用支付系统支付订单,支付成功,但是返回给订单系统数据超时,订单还是I(初始状态),但是此时帐户余额100。
 【2】订单系统调用支付系统成功,状态也已经更新成功,但是通知仓库发货失败,这个时候订单是P(已支付)状态,帐户余额100,但是仓库不会发货。
 【3】订单系统调用支付系统成功,状态也已经更新成功,然后通知仓库发货,仓库告诉订单系统,没有货了。此时,数据状态与【2】一样。

 对于【1】,能想到的解决方案如下:
  1、假设调用支付系统支付订单的时候先不扣钱,订单状态更新完成之后,再通知支付系统扣钱。如果采用这种设计方案,在同一时刻,这个用户又支付了另外一笔订单,订单价格200,顺利完成了整个订单支付流程,由于当前订单的状态已经变成了支付成功,但是实际用户已经没有钱支付了,这笔订单的状态就不一致了。即使用户在同一个时刻没有进行另外的订单支付行为,通知支付系统扣钱这个动作也有可能完不成,反而增加了系统的复杂性。
  如果支付系统先不扣钱,而是先把钱冻结起来,不让用户给其他订单支付,然后等订单系统把订单状态更新为支付成功的时候,再通知支付系统,这个时候支付系统扣钱,完成后续的操作。假设订单系统在调用支付系统冻结的时候,支付系统冻结成功,但是订单系统超时,返回给用户,告知用户支付失败,如果用户再次支付这笔订单,由于支付系统进行控制,告诉订单系统冻结成功,订单系统更新状态,然后通知支付系统。如果这个时候通知失败,由于钱已经被冻结,用户不能用,只要定时扫描订单和支付状态,进行扣钱而已。但是如果用户重新拍下来一笔订单,100块钱,对新的订单进行支付,这个时候由于先前那一笔订单的钱被冻结了,这个时候用户余额剩余100,冻结100,发现可用的余额足够,直接扣钱。这个时候余额剩余0,冻结100。先前那一笔怎么办,一个办法就是定时扫描,发现订单状态是初始的话,就对用户的支付余额进行解冻处理。这个时候用户的余额变成100,订单数据和支付数据又一致了。假设原先用户余额只有100,被冻结了,用户重新下单,支付的时候就会失败,所以要尽可能的保证在第一次订单结果不明确的情况,尽早解冻用户余额,比如10秒之内。但是不管如何快速,总有数据不一致的时刻,这个是没有办法避免的。
  2、订单系统自动发起重试,多次重试,直到扣款成功为止。假设订单系统第一次调用支付系统成功,但是没有办法收到应答,订单系统又发起调用,重复支付,一次订单支付了200。
  3、在第二种方案的基础上,先解决订单的重复支付行为,需要在支付系统上对订单号进行控制,一笔订单如果已经支付成功,不能再进行支付,返回重复支付标识。订单系统根据返回的标识,更新订单状态。然后解决重试问题,假设应用重试三次,如果三次都失败,先返回给用户提示支付结果未知。假设这个时候用户重新发起支付,订单系统调用支付系统,发现订单已经支付,那么继续下面的流程。如果没有发起支付,系统定时(一分钟一次)去核对订单状态,如果发现已经被支付,则继续后续的流程。这种方案,用户体验非常差,告诉用户支付结果未知。
  上面分析了第一个的问题以及相应的方案,发现在数据分布的环境下,很难绝对的保证数据一致性(任何一段区间),但是有办法通过一种补偿机制,最终保证数据的一致性。

 对于【2】:可以采取重试机制,如果发现通知仓库发货失败,就一直重试。这里面有两种方式:
 1、异步方式:通过类似MQ(消息通知)的机制,这个是异步的通知
 2、同步调用:类似于远程过程调用
对于同步的调用的方式,比较简单,能够及时获取结果;对于异步的通知,就必须采用请求,应答的方式进行。

 对于【3】:存在以下几种解决的方案:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值