分布式事物理论与实践

在日常讨论技术方向的时候,经常听伙伴抛出一些概念高可用性,一致性关键词。但是未必每个
人都能把这些概念说清楚。今天我们就来聊聊分布式事物那些事,分享一下我们在项目中是如何使用的。
一、CAP理论

1.什么是CAP理论

2000年,Eric Brewer教授在PODC的研讨会上提出了一个猜想。一致性、可用性和分区容错性三者无法在分布式系统中被同时满足,并且最多只能满足其中两个!Brewer教授当时想象的分布式场景是webservice,一组websevrice后台运行着众多的server,对service的读写会反应到后台的server集群。
分布式事物理论与实践_第1张图片

强一致性 (Consistency):系统在执行过某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读取到最新的值,这样的系统被认为具有强一致性。
可用性 (Availability):每一个操作总是能够在一定的时间内返回结果,超时和不能返回结果均不符合条件。
分区容错性(Partition Tolerance):分区容错性可以理解为系统在存在网络分区的情况下仍然可以接受请求。这里网络分区是指由于某种原因网络被分成若干个孤立的区域,而区域之间互不相通。还有一些人将分区容错性理解为系统对节点动态加入和离开的处理能力,因为节点的加入和离开可以认为是集群内部的网络分区。

2.系统为什么不能同时满足CAP特性

如下图所示,在网络中有两个节点分别为G1和G2,这两个节点上存储着同一数据的不同副本,现在数据是一致的,两个副本的值都为V0,A、B分别是运行在G1、G2上与数据交互的应用程序。

分布式事物理论与实践_第2张图片

在正常情况下,操作过程如下(如下图所示):
(1) A将V0更新,数据值为V1;
(2) G1发送消息m给G2,数据V0更新为V1;
(3) B读取到G2中的数据V1。

分布式事物理论与实践_第3张图片

如果发生网络分区故障,那么在操作的步骤(2)将发生错误:G1发送的消息不能传送到G2上。这样数据就处于不一致的状态,B读取到的就不是最新的数据,如下图所示。如果我们采用一些技术如阻塞、加锁、集中控制等来保证数据的一致,那么必然会影响到系统的可用性和分区容错性。所以同时满足三点,总是需要放弃一部分。

分布式事物理论与实践_第4张图片

系统满足三个条件中不同的两个条件会具有不同的特点
放弃P,保证AC:如果想避免分区容错性问题的发生,一种做法是将所有的数据(与事务相关的)都放到一台机器上。
放弃A,保证CP:一旦遇到分区容错故障,那么受到影响的服务需要等待数据最终一致性
放弃C,保证AP:这里所说的放弃一致性,而保留数据的最终一致性。该方式也是解决分布式事物的主流方式。

二、分布式事物解决方案

eBay的架构师Dan Pritchett 在2008年发给ACM的文档。文章中描述了一个最常见的场景,如果产生了一笔交易,需要在交易表增加记录,同时还要修改用户表的金额。这两个表属于不同的远程服务,涉及到分布式事务一致性的问题。经典的解决方法,引入本地消息表和消息中间件,将写入本地消息表、更新用户表,发送Q放在一个本地事务中完成。同时为了避免重复消费用户表消息带来的问题,保证幂等性增加一个接收端记录表。
举个例子,系统中有以下两个表user,transaction.

分布式事物理论与实践_第5张图片

其中user表记录用户交易汇总信息,transaction表记录每个交易的详细信息。transaction表和user表存储在不同的节点上,那么上述事务是一个分布式事务。要消除这一分布式事务,将它拆分成两个子事务。保证消息的幂等性还需要在接收端创建消息接收表message_applied(msg_id),保证不能重复接收消息。

begin transaction
  insert into transaction(xid, $seller_id, $buyer_id, $amount);
  put_to_queue "update user("seller",$seller_id,amount)";
  put_to_queue "update user("buyer",$buyer_id,amount)";
end transaction
--------------------------------------------------------
for each message in queue
  peek message
  begin transaction
    select count(*) as cnt from message_applied where msg_id=message.id
        and balance = message.balance and user_id=message.user_id
    if cnt == 0 
then
          if message.type = “seller” then
    update user SET amt_sold = amt_sold + message.amount where id = message.user_id;
else
update user set amt_bought = amt_bought + message.amount where id = message.user_id;
         insert into message_applied values(message.id); 
end
end transaction
end fors

第一阶段:transation表和操作队列在同一实例上,可以通过本地的数据库的事务保证。
第二阶段:message_applied表和user表在同一个实上,可以通过本地的数据的事务保证,当有重试或者重复消息过来时,通过message_applied表可以判断是否是重复数据。

三、实际项目对理论的实践

  1. A、B两个系统服务进行异步数据通信
    本场景我们采用Q作为消息中间件。可以借鉴ebay模式。

①应用A的业务逻辑、写本地消息表、写消息队列放在一个队列里。写消息队列业务逻辑放在最后。
②所有步骤执行成功,事物提交。
③有一步骤执行失败,则进行回滚。
④此方案需要在记录服务A发送的完整消息日志,以防Q出现问题进行消息补发,在B端创建接收表,去重,保证消息的幂等性。

  1. D调用A、B、C三个服务

本场景保证事物一致性有两种解决方案,一种是调用中间服务出错后回滚掉其他所有服务的数据,这需要每个应用提供回滚服务。另一种认为服务一定会调用成功,一旦出现问题,会不断重试。下面会根据这两种情况进行详细说明。
第一, 服务调用采用回滚方式处理,如下示意图所示

分布式事物理论与实践_第6张图片

以上思路还是借鉴ebay模型来解决最终一致性问题。
第二,不断重试保证消息一致性相对第一种情况要简单一些。一旦调用异常需要记录到错误表中不断的进行重试。

你可能感兴趣的:(一致性)