本文共 3100 字,大约阅读时间需要 10 分钟。
业务背景:
商户提交表单数据至旺铺(deco项目,以下皆称为deco),deco需要接入poi系统进行装修内容的人工审核,详细流程见下图。
店铺装修审核状态在deco系统和poi系统之间不一致,下图中1,2,3步提交流程会出现同一次提交审核流在deco系统中的装修状态为未装修,而在poi系统为审核中。同样在4,5,6步骤的审核回调过程也会有同类的状态不一致问题。两块问题都是同一技术问题,本文只以1,2,3步提交过程为例进行分析解决。
从业务中抽离出来,问题的核心原因可用下图流程模型来描述。
系统A的某个业务功能包含两步操作,第一步把数据写入A系统本地库,第二步远程调用系统B,这两步操作在A系统用一个数据库事务来包装。伪代码如下:
$db->begain();
// 第一步操作本地数据库
$res = $db->update($sql_a);
if (!$res) {
$db->rollback();
return;
}
// 第二步远程调用B系统
$res = $http_request->get($url_b);
if ('success' != $res) {
$db->rollback();
return;
}
$db->commit();
第一步有两种结果成功、失败,第二步则有3种结果成功、失败、超时,其中导致超时原因可能是网络中断,也可能是B系统服务异常。那么我们根据两步骤的执行结果情况来分别分析一下是否会导致A、B系统之间的数据不一致。
可得当第一步执行成功,第二步远程调用超时时,A系统事务会回滚,那么就发生A、B系统数据不一致的情况,A库中写入失败,但是B库中却成功写入。我们习惯于使用关系型数据库事务的ACID特性来达到一致性的目的,但是当事务中发生跨系统的调用时ACID就无效了,只从数据库层面来看,跨系统就意味着同一个业务存在多个数据副本,对应着不同的数据库实例,而且分布在不同的机器上,而关系型数据库的事务只是针对同一个库的同一个connection而言的。
我们先重新认识一下什么是一致性?首先想到的是关系型数据库事务,又会想到最经典的甲给乙转钱的例子,事务的四大基本特性ACID保证了甲账户扣钱和乙账户入钱同时发生或同时不发生,其中的C特性就是指一致性,它是指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。在web2.0之前大部分网站或者项目都是单系统,对应底层存储也只是单数据库,所以使用数据库本身的事务特性就满足了一致性。
但是随着互联网用户和数据量的指数级增长,对于每个系统的计算能力、吞吐量以及响应速度的要求都大大提高,于是单节点服务器肯定满足不了要求,所以都在考虑拆分和系统扩展性,无论是经过水平拆分还是垂直拆分,单机系统就变成了分布式系统,分布式系统就肯定存在某节点或者网络故障的情况,之前说的事务的ACID中的强一致性就无法保证。
再回到我们的问题上来,poi系统其实就可以理解为垂直拆分出的一个微服务,deco调用poi的提交审核接口就是分布式系统之间的调用,但是deco中仍然用关系型数据库的事务来达到强一致性的目的,根据CAP理论,分布式系统的一致性、可用性、分区容错性不可能同时得到满足,只能满足其中两个,而分布式系统的分区容错性都需要得到满足,所以就需要在一致性和可用性之间进行取舍。Deco的这种实现其实就是为了保证一致性,而牺牲了可用性。
而对于现在的系统而言,可用性是至关重要的必须要保证,要做到即使poi系统出现偶尔的网络故障或者超时,也尽可能不要用户的一次提交失败掉。
再来了解一个概念BASE理论,BASE理论是CAP理论的一种实现,它对分布式系统的一致性和可用性不可兼得的问题提出了一种方案,即基本可用和最终一致是目标。既然提到了强一致性和最终一致性,再介绍一下业界对一致性的分层次定义。
对上面几段分析的总结就是:关系型数据库的事务可以满足单系统的强一致性,大部分分布式系统只能把最终一致性作为追求。而我们的deco和poi系统显然也是应该追求最终一致性,因为对于poi和deco之间装修审核数据出现短时间的不一致是完全可以接受的。
基于上述理论,我们可以有以下两种方案来达到可用性和最终一致性:
方案一、
解耦,异步任务处理,由原来同步调用poi系统变为异步调用,将deco系统信息入库和调用poi创建审核任务这两个操作分开。
方案二、
引入消息队列,相当于对方案一的升级版。
本群提供免费的学习指导 架构资料 以及免费的解答
不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导
转载地址:http://nvvml.baihongyu.com/