精华内容
下载资源
问答
  • 分布式技术发展下,数据一致性解决方法和技术也在不断的演进,本文就以分布式数据库作为案例,介绍分布式数据库数据一致性的原理以及实际实现。 1、数据一致性 1.1 数据一致性是什么 大部份使用传统关系型数据库...

    前言

    分布式数据库的数据一致性管理是其最重要的内核技术之一,也是保证分布式数据库满足数据库最基本的ACID特性中的 “一致性”(Consistency)的保障。在分布式技术发展下,数据一致性的解决方法和技术也在不断的演进,本文就以分布式数据库作为案例,介绍分布式数据库数据一致性的原理以及实际实现。

    1、数据一致性

    1.1 数据一致性是什么

    大部份使用传统关系型数据库的DBA在看到“数据一致性”时,第一反应可能都是数据在跨表事务中的数据一致性场景。但是本文介绍的“数据一致性”,指的是**“数据在多份副本中存储时,如何保障数据的一致性”**场景。

    由于在大数据领域,数据的安全不再由硬件来保证,而是通过软件手段,通过同时将数据写入到多个副本中,来确保数据的安全。数据库在同时向多个副本写入记录时,如何确保每个副本数据一致,称为“数据一致性”。

    1.2 关系型数据库如何保障数据一致性

    传统的关系型数据库对于运行环境–硬件要求都比较高,例如Oracle会建议用户使用小型机+共享存储作为数据库的运行环境,DB2 DPF也同样建议用户采用更好的服务器+高端存储来搭建数据库的运行环境。所以在数据存储安全的技术要求下,传统关系型数据库更多是依赖硬件的技术来保障数据的安全性。

    在这里插入图片描述
    因为关系型数据库的数据安全是基于硬件来保障,并且数据也不会通过同时存储多份来保障数据的安全,所以关系型数据库的用户默认认为数据存储是一致的。

    1.3 分布式存储如何保障数据一致性

    本文在讨论分布式存储时,主要指的是大数据产品中的分布式文件系统和分布式数据库,例如:SequoiaDB和HDFS。

    用户在搞明白分布式存储的数据一致性原理时,必须要先明白为什么他们就需要数据一致性,和分布式存储的数据存储与关系型数据库的数据存储又有什么区别。

    大数据技术的诞生,确确实实让系统的性能有新的突破,并且支持硬件以水平扩展的方式来获得线性增长的性能和存储。这些都是过去传统关系型数据库所无法提供的。另外,大数据技术也抛弃了运行环境必须足够好的硬性要求,而是允许用户通过批量廉价X86服务器+本地磁盘的方式搭建规模集群,从而获得比过去依赖硬件垂直扩展所提供的更强的计算能力和更多的存储空间。

    大数据技术的核心思想就是分布式,将一个大的工作任务分解成多个小任务,然后通过分布式并发操作的方式将其完成,从而提高整个系统的计算效率或者是存储能力。而在分布式环境下,由于硬件的要求降低,必然需要大数据产品提供另外一个重要的功能–数据安全

    在这里插入图片描述
    大数据产品在解决数据安全的方式上,都比较接近,简单来说,就是让一份数据通过异步或者同步的方式保存在多台机器上,从而保障数据的安全。

    分布式存储在解决数据安全的技术难点后,又引入了一个新的技术问题,就是如何保障多个副本中的数据一致性。目前SequoiaDB是使用Raft算法来保证数据在多个副本中一致性。

    2、Raft算法

    2.1 Raft算法背景

    在分布式环境下,最著名的一致性算法应该是Paxos算法,但是由于它实在过于晦涩难懂,并且实现起来极度困难,所以在2013年,Diego Ongaro、John Ousterhout两个人以易懂(Understandability)为目标设计了一套一致性算法Raft。Raft算法最大的特点在于简单易懂,并且实现起来简单

    2.2 Raft算法概述

    与Paxos不同,Raft强调的是易懂,Raft和Paxos一样只要保证n/2+1节点正常就能够提供服务。

    众所周知当问题较为复杂时可以把问题分解为几个小问题来处理,Raft也使用了分而治之的思想。Raft算法重点解决三个子问题:选举(Leader election)、日志复制(Log replication)、安全性(Safety)。

    Raft算法强化了Leader节点的功能,Follower节点的数据只能够从Leader中获取,所以Follower节点的实现就变得简单,只要负责和Leader保持通信,并且接受Leader推送的数据即可。

    2.3 Raft算法原理

    2.3.1 节点角色

    Raft算法中,对节点的状态分为3种角色,分别是Leader(领导者)、Follower(追随者)和Candidate(候选者)。

    Leader,负责处理来自客户端的请求,负责将日志同步到Follower中,并且保证与Follower之间的heartBeat联系;

    Follower,当集群刚刚启动时,所有节点均为Follower状态,它的工作主要为响应Leader的日志同步请求,响应Candidate的请求,以及把请求到Follower的事务请求转发给Leader;

    Candidate,选举Leader时负责投票,选举出来Leader后,节点将从Candidate状态变为Leader状态。

    在这里插入图片描述

    2.3.2 Terms

    在分布式环境下,“时间同步”一直都是老大难的技术难题。Raft为了解决这个问题,将时间划分为一个一个的Term(可以理解为“逻辑时间”)来处理在不同时间段里的数据一致性。

    Terms有以下原则

    • 每个Term中,至多存在一个Leader
    • 某些Term中,有可能存在由于选举失败,没有Leader的情况
    • 每个节点自己维护本地的currentTerm
    • 每个Term都是一个连续递增的编号
    • 如果Follower的Term编号比别的Follower Term编号小时,该Follower Term编号将更新Term编号,以保持与其他Follower Term编号一致

    2.3.3 选举

    Raft的选举由定时器触发,每个节点的触发时间都不相同。

    所有的节点在开始时状态都为Follower,当定时器触发选举后Term编号递增,该节点的状态由Follower转为Candidate,并且向其他节点发起RequestVote RPC请求,这时选举有3种情况可能发生:

    发起RequestVote的节点收到n/2+1(过半数)个节点的投票,该节点将从Candidate状态变为Leader状态,开始向其他节点发送HeartBeat以保持Leader的正常状态

    如果收到投票请求后,该节点发现发起投票的节点Term大于自己,则该节点状态从Candidate转为Follower,否则保持Candidate状态,并且拒绝该投票请求

    选举期间发生了超时,则Term编号递增,重新发起选举
    在这里插入图片描述

    2.3.4 日志复制

    日志复制主要的作用就是用来保证节点的数据一致性与高可用性。

    当Leader被选举出来后,所有的事务操作都必须要经过Leader处理。这些事务操作成功后,将会被按顺序写入到LOG中,每个LOG都包含一个index编号。

    Leader在LOG发生变化后,通过HeartBeat将新的LOG同步到Follower上,Follower在接收到LOG后,再向Leader发送ACK信息,当Leader接到大多数(2/n+1)Follower的ACK信息后,将该LOG设置为已提交,并且Leader将LOG追加到本地磁盘中。

    同时Leader将在下一个HeartBeat中,通知所有的Follower将该LOG存储在各自的本地磁盘中。

    2.3.5 安全性

    安全性是用于确保每个节点都是按照相同的日志序列进行执行的安全机制。

    如果当某个Follower在同步Leader的日志时失败,但是未来该Follower又可能被选举为Leader时,就有可能导致前一个Leader已经commit的日志发生覆盖,这样就导致了节点执行不同序列的日志。

    Raft的安全性就是用于保证选举出来的Leader一定包含先前已经commit LOG 的机制,主要遵循的原则如下:

    每个Term 只能选举一个Leader;

    Leader的日志完整性,则当Candidate重新选举Leader时,新的Leader必须要包含先前已经commit的LOG;

    Candidate在选举新的Leader时,使用Term来保证LOG的完整性;

    3、分布式数据库数据一致性技术实现

    以国产原厂的分布式数据库SequoiaDB为例,SequoiaDB在多副本的部署中,采用Raft算法保证数据在多副本环境中保持一致。

    SequoiaDB集群中,总共包含3中角色节点,分别是协调节点、编目节点和数据节点。由于协调节点本身不存任何数据,所以只有编目节点和数据节点存在事务操作,换言之,编目分区组和数据分区组的副本同步采用Raft算法保证数据一致性。

    在这里插入图片描述

    3.1 编目节点和数据节点的事务日志介绍

    编目节点和数据节点由于都是需要存储数据的,并且在集群部署中该,为了确保数据的安全,都是建议采用分布式的方式进行部署,所以在数据同步中,需要采用Raft算法的基本原理进行数据同步。

    编目节点和数据节点在存储数据时,共包含两大部分,一个真实的数据文件,另一个是事务日志文件。
    在这里插入图片描述
    SequoiaDB的节点事务日志,默认情况下由20个64MB(总大小为1.25GB)的文件构成。节点的事务日志主要包含一个index编号和数据操作内容,index编号保持永远递增状态。

    另外,SequoiaDB节点的事务日志不会永久保存,而是当所有的事务日志写满后,再重新从第一个文件开始进行覆盖写入。

    3.2 编目分区组的数据一致性

    由于编目分区组是保存SequoiaDB集群的元信息,数据同步要求高,所以编目分区组的数据一致性要求为强一致性,即每次向编目分区组执行事务操作时,必须要确保所有的编目节点操作成功,才计算该操作执行成功,否则该事务操作将在整个编目分区组中回退事务日志,以保证分区组内的数据一致性。

    另外,编目分区组还有一个比较重要的特性,即编目分区组必须要存在主节点才能够正常工作,如果老的主节点宕机了,编目分区组暂时没有主节点,则该编目分区组不能够对外提供任何事务操作和数据查询操作。

    3.3 数据分区组的数据一致性

    数据分区组的数据一致性默认情况下为最终一致性性,即只要求主节点执行事务操作成功即视为操作成功,主节点将在未来异步同步ReplicaLOG到从节点上。

    3.4 主从节点的事务日志同步

    SequoiaDB的主从节点是通过事务日志同步来保证数据一致性的,并且主从节点的事务日志同步是单线程完成。

    如果当主节点和从节点的LSN差距为一条记录,则主节点会主动将最新的事务日志推送给从节点。

    如果主节点和从节点的LSN差距超过一条记录,则从节点会主动向主节点请求同步事务日志,主节点收到同步请求后,会将从节点的LSN号到主节点最新的LSN号对应的事务日志打包一次性发送给从节点。

    3.5 从节点日志重放

    当从节点获取到主节点推送过来的事务日志后,就会自动解析事务日志和重放。从节点在重放事务日志时,默认情况下会以10并发来重放事务日志。

    从节点在执行并发重放日志时有条件限制,即在集合的唯一索引个数<=1的情况下,INSERT、DELETE、UPDATE、LOB WRITE、LOBUPDATE、LOB REMOVE操作可以支持并发重放事务日志。从节点在做并发重放时,是通过记录的OID进行打散并发执行,这样就可以保证对相同记录的操作不会由于并发重放导致数据不一致。

    但是用户需要注意,从节点在重放事务日志时, DROP CL操作不能够支持并发重放。

    4、SequoiaDB数据一致性应用

    目前SequoiaDB数据分区组的数据一致性是基于集合级别进行配置的。用户在使用SequoiaDB过程中,可以随时调整数据一致性的强度。

    4.1 创建集合时指定

    在一个多副本的SequoiaDB集群中,集合默认的数据一致性行级别为“最终一致性”。用户可以在创建集合时显式指定该集合的“数据一致性强度”,例如可以在SequoiaDB Shell中执行以下命令

    db.CSNAME.createCL(“CLNAME”,{ReplSize:3})

    ReplSize参数填写范围
    在这里插入图片描述

    4.2 修改已经存在的集合

    如果集合在创建时没有设置“数据一致性”ReplSize参数,用户也可以对已经存在的集合进行修改,在SequoiaDB Shell修改命令如下

    db.CSNAME.CLNAME.alter({ReplSize:3})

    ReplSize的取值范围和创建集合时一致。

    4.3 如何查看集合的ReplSize参数

    如果用户希望检查当前集合的RepliSize参数值,可以通过数据库快照进行查看,在SequoiaDB Shell查看命令如下

    db.snapshot(SDB_SNAP_CATALOG,{}, {“Name”:null, “IsMainCL”:null,“MainCLName”:null, “ReplSize”:null})
    打印信息如下

    {

    “MainCLName”:“test.main2”,

    “Name”: “foo.bar2”,

    “IsMainCL”: null,

    “ReplSize”: null

    }

    {

    “IsMainCL”: true,

    “Name”: “test.main2”,

    “MainCLName”: null,

    “ReplSize”: null

    }

    {

    “Name”: “foo.tt”,

    “ReplSize”: 3,

    “IsMainCL”: null,

    “MainCLName”: null

    }

    5、总结

    分布式的数据库,通过Raft算法来确保在分布式情况上数据的一致性,并且编目分区组和数据分区组对数据一致性要求又有所不同,编目分区组始终要求的是数据在多副本请情况下数据强一致性,而数据分区组则可以由用户在创建集合时来执行数据一致性的强度,强度越高,数据安全性越好,但是执行的效率就会相对较差,反之依然。

    目前SequoiaDB在数据一致性场景上,用户的调整空间较大,可以根据不同的业务要求来调整数据一致性的强度,以满足业务或追求性能最优,或者数据最安全的技术要求。

    展开全文
  • 1:会员库(会员数据,优惠券数据) 2:商品库(商品数据,库存数据) 3:订单库(订单表、订单明细表,下单事件表) 订单系统下单处理流程 1:用户提交订单前先检测资源可用(库存,账户余额,优惠券等),如果...

    数据库包含
    1:会员库(会员数据,优惠券数据)
    2:商品库(商品数据,库存数据)
    3:订单库(订单表、订单明细表,下单事件表)


    订单系统下单处理流程


    1:用户提交订单前先检测资源可用性(库存,账户余额,优惠券等),如果检测不通过,则返回失败;如果成功则进入下一步


    2:生成订单号,并将订单信息推送到消息中间件,如果该步骤失败,则流程结束;
       如果成功,则跳转到下单结果查询页,并使用轮训查询订单(或者websocket),根据查询结果决定是跳转到支付页(订单未支付)还是跳转到订单详细页(订单以付款)


    3:在信息中间件的消费者端监听下单消息,获取到下单消息的时候


    3.1:写入下单事件表(操作订单库)(订单id,库存回滚状态,优惠券回滚状态,余额回滚状态,确认状态 0 待确认  1已确认,检测时间(插入记录的时间往后延5分钟,给后续动作留足时间)),如果失败,流程结束;成功则进入下一步


    3.2:调用库存接口(操作商品库)扣减库存(记录订单号),如果失败,流程结束,如果成功则进入下一步


    3.3:(如果订单使用了优惠券)调用优惠券接口(操作会员库)修改优惠券状态为已使用(优惠券记录对应的订单号),如果失败,结束流程;如果成功则进入下一步


    3.4:(如果订单使用余额支付)调用扣减用户账户余额接口(操作会员库)扣减余额(记录对应订单号),如果失败结束流程,成功则进入下一步


    3.5:生成订单(操作订单库),如果成功后第2步中的轮训操作可以查到该订单,流程结束;如果失败则返回,并且流程结束




    4:容错机制:


    4.1:后台开启多个线程轮训下单事件表中待确认的记录,拿到订单号,然后去查询该订单是否已经生成,如果已经生成,说明数据一致性没有问题,那么将该记录更新为已确认;
         如果订单不存在,说明中间某个步骤出了问题


    4.2:如果下单事件表中库存回滚状态为“已回滚”,则略过4.2步骤;否则使用订单号去查询库存扣减记录,如果没有库存扣减记录(说明在扣减库存这里就失败了,后续的流程也不会存在),则更新下单事件的状态为以确认;
         如果有库存扣减库存记录,并且该库存扣减记录的回滚标识位为未回滚,则调用库存回滚接口回滚商品库存,如果回滚失败则稍后重试(检测时间再往后延),
    如果回滚成功更新库存扣减记录为已回滚,并更新下单事件表中库存回滚状态为已回滚并则进入下一步
    如果有扣减库存记录,但该扣减记录已经回滚过,则直接更新下单事件表中的库存回滚状态为已回滚并进入下一步


    4.3:如果下单事件表中优惠券回滚状态为“已回滚”,则略过4.3步骤;否则使用订单号去查询优惠券使用记录,如果没有优惠券使用记录(说明该订单没有使用优惠券或者是该订单使用了优惠券但是在更新优惠券这一步失败了),
         则更新优惠券回滚状态为不需要回滚;
         如果查询到优惠券使用记录并且该优惠券使用记录未回滚过则回滚,如果回滚失败则稍后重试(检测时间再往后延),
    回滚成功后更新更新优惠券回滚状态为已回滚,并更新下单时间表中的优惠券回滚状态为已回滚,进入下一步;
    如果查询到优惠券使用记录并且该优惠券使用记录已经回滚过(但是回滚后更新下单事件表中的优惠券回滚状态失败了),则直接更新下单事件表中的优惠券回滚状态为已回滚并进入下一步


    4.4:回滚账户余额,同上

    4.5:当所有的回滚操作都要完成则更新下单事件为已确认,容错检测完成

     

    该解决方案参考了网上的一篇博客,具体地址不记得了

    展开全文
  • 2.生产者可以保存数据,但是保存后执行代码报错,事务进行回滚,消息已提交到消息中间件,解决办法: (1)生产者保存的数据存放到日志或redis里,并且消息是有唯一全局ID的。 (2)添加一个消费者补单队列,补单...

    生产者------到--------消息中间件Rabbit

    1.生产者数据保存失败,则进行补偿机制。

    2.生产者可以保存数据,但是保存后执行代码报错,事务进行回滚,消息已提交到消息中间件,解决办法:

    (1)生产者保存的数据存放到日志或redis里,并且消息是有唯一全局ID的。

    (2)添加一个消费者补单队列,补单队列与派单队列监听同一个队列,且补单队列先要通过唯一全局ID 查询数据库订单数据是否已保存,如事务回滚了未查询到,则通过日志或redis获取订单数据,并保存订单数据。

       如下图:

     

    Rabbit的数据安全保证:

    通过使用持久化机制,保存到硬盘里(在生产者里设置)

    // 设置消息持久化 PERSISTENT
    producer.setDeliveryMode(DeliveryMode.PERSISTENT);

     

    Rabbit-----到-------消费者

    1.消费失败

    使用自动补偿机制(重试)(每次重试,都查一下缓存看是否已经消费过。)

    若重试5次后,消息会放到死信队列

     

    2.解决消费者幂等性问题,防止重复:

    使用全局ID ,例如

    (1)生产者将MessageID (可订单号作为唯一ID)传入消息里, 并将这个ID缓存起来(日志记录表,Redis等);

    (2)消费者先查看缓存(日志记录表,redis等),查看这个ID的状态,是否已经被消费,若未被消费,则消费者消费该消息,若已经消费了,则消费者不消费该消息,并提交告诉Rabbit这个消息已经消费了(手动应答ack,即已签收)

     

    死信队列(备胎队列,跟普通队列思想是一样的)

    消息存到死信队列的三种情况:

    1.当队列长度已满

    2.消息已过期

    3.消费者拒绝消息

    注意:1.已经创建了消息队列后,不能直接将该消息队列绑定到死信队列,需要重新删除队列,重新创建绑定。

               2.消费者报异常,做消费者拒绝消息的操作,消息存到死信队列,给死信队列消费。

     

     

    展开全文
  • 但事实上,ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeeperAtomic Broadcast (ZAB, ZooKeeper 原子消息广播协议)的协议作为其数据一致性的核心算法。 ZAB协议是为分布式协调服务ZooKeeper专门设计的一...

    一、ZAB 协议简介

    在深入了解ZooKeeper之前,认为ZooKeeper就是Paxos算法的一个实现。但事实上,ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeeper Atomic Broadcast (ZAB, ZooKeeper 原子消息广播协议)的协议作为其数据一致性的核心算法。

    ZAB协议是为分布式协调服务ZooKeeper专门设计的一种支持崩溃恢复的原子广播协议。
    ZAB协议并不像Paxos算法那样,是一种通用的分布式一致性算法,它是一种特别为ZooKeeper设计的崩溃可恢复的原子消息广播算法。

    在ZooKeeper中,主要依赖ZAB协议来实现分布式数据一致性,基于该协议,ZooKeeper实现了一种主备模式的系统架构来保持集群中各副本之间数据的一致性。具体的,ZooKeeper使用一个单一的主进程来接收并处理客户端的所有事务请求,并采用ZAB的原子广播协议,将服务器数据的状态变更以事务Proposal的形式广播到所有的副本进程上去。ZAB协议的这个主备模型架构保证了同一时刻集群中只能够有一个主进程来广播服务器的状态变更,因此能够很好地处理客户端大量的并发请求。另一方面,考虑到在分布式环境中,顺序执行的一些状态变更其前后会存在一定的依赖关系,有些状态变更必须依赖于比它早生成的那些状态变更,例如变更C需要依赖变更A和变更B。这样的依赖关系也对ZAB协议提出了一个要求:ZAB协议必须能够保证一个全局的变更序列被顺序应用,也就是说,ZAB协议需要保证如果一个状态变更已经被处理了,那么所有其依赖的状态变更都应该已经被提前处理掉了。(意思就是已经处理的事务请求不会再处理,不能丢失)最后,考虑到主进程在任何时候都有可能出现崩溃退出或重启现象,因此,ZAB协议还需要做到在当前主进程出现上述异常情况的时候,依旧能够正常工作。

    ZAB协议的核心是定义了对于那些会改变ZooKeeper服务器数据状态的事务请求的处理方式,即:

    所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为Leader 服务器,而余下的其他服务器则成为Follower服务器。Leader服务器负责将一个客户端事务请求转换成一个事务Proposal (提议),并将该Proposal 分发给集群中所有的Follower服务器。之后Leader 服务器需要等待所有Follower 服务器的反馈,一旦超过半数的Follower服务器进行了正确的反馈后,那么Leader就会再次向所有的Follower服务器分发Commit消息,要求其将前一个Proposal 进行提交。

    二、协议内容

    ZAB协议包括两种基本的模式,分别是崩溃恢复和消息广播。

    什么时候会进行Leader选举?
    当整个服务框架在启动过程中,或是当Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入恢复模式并选举产生新的Leader 服务器。

    什么时候进入消息广播模式 和 数据恢复模式?

    当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式。其中,所谓的状态同步是指数据同步,用来保证集群中存在过半的机器能够和Leader服务器的数据状态保持一致。
    当集群中已经有过半的Follower 服务器完成了和Leader 服务器的状态同步,那么整个服务框架就可以进入消息广播模式了。当一台同样遵守ZAB协议的服务器启动后加入到集群中时,如果此时集群中已经存在一个Leader服务器在负责进行消息广播,那么新加入的服务器就会自觉地进入数据恢复模式:找到Leader 所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。

    当Leader服务器出现崩溃退出或机器重启,亦或是集群中已经不存在过半的服务器与该Leader服务器保持正常通信时,那么在重新开始新一轮的原子广播事务操作之前,所有进程首先会使用崩溃恢复协议来使彼此达到一个一致的状态,于是整个ZAB流程就会从消息广播模式进入到崩溃恢复模式。
    一个机器要成为新的Leader,必须获得过半进程的支持,同时由于每个进程都有可能会崩溃,因此,在ZAB协议运行过程中,前后会出现多个Leader, 并且每个进程也有可能会多次成为Leader.进入崩溃恢复模式后,只要集群中存在过半的服务器能够彼此进行正常通信,那么就可以产生一个新的Leader并再次进人消息广播模式。

    只有Leader能处理事务,如果其他节点收到事务请求呢?
    ZooKeeper 设计成只允许唯一的一个Leader服务器来进行事务请求的处理。Leader服务器在接收到客户端的事务请求后,会生成对应的事务提案并发起一轮广播协议,而如果集群中的其他机器接收到客户端的事务请求,那么这些非Leader服务器会首先将这个事务请求转发给
    Leader服务器。

    消息广播

    ZAB协议的消息广播过程使用的是一个原子广播协议,类似于一个二阶段提交过程。针对客户端的事务请求,Leader 服务器会为其生成对应的事务Proposal, 并将其发送给集群中其余所有的机器,然后再分别收集各自的选票,最后进行事务提交,如图所示就是ZAB协议消息广播流程的示意图。
    在这里插入图片描述

    ZAB协议中涉及的二阶段提交过程的不同之处?

    在ZAB协议的二阶段提交过程中,移除了中断逻辑,所有的Follower 服务器要么正常反馈Leader提出的事务Proposal,要么就抛弃Leader服务器。同时,ZAB协议将二阶段提交中的中断逻辑移除意味着我们可以在过半的Follower 服务器已经反馈Ack之后就开始提交事务Proposal 了,而不需要等待集群中所有的Follower服务器都反馈响应。当然,在这种简化了的二阶段提交模型下,是无法处理Leader 服务器崩溃退出而带来的数据不一致问题的,因此在ZAB协议中添加了另一个模式,即采用崩溃恢复模式来解决这个问题。另外,整个消息广播协议是基于具有FIFO(先进先出)特性的TCP协议来进行网络通信的,因此能够很容易地保证消息广播过程中消息接收与发送的顺序性。

    什么是ZXID?

    在整个消息广播过程中,Leader服务器会为每个事务请求生成对应的Proposal来进行广播,并且在广播事务Proposal之前,Leader服务器会首先为这个事务Proposal分配一个全局单调递增的唯一ID, 我们称之为事务ID (即ZXID)。

    由于ZAB协议需要保证每一个消息严格的因果关系,因此必须将每一个事务Proposal按照其ZXID的先后顺序来进行排序与处理。具体的,在消息广播过程中,Leader服务器会为每一个Follower服务器都各自分配一个单独的队列,然后将需要广播的事务Proposal 依次放入这些队列中去,并且根据FIFO策略进行消息发送。每一个Follower服务器在接收到这个事务Proposal 之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且在成功写入后反馈给Leader服务器一个Ack响应。当Leader服务器接收到超过半数Follower的Ack响应后,就会广播一个Commit消息给所有的Follower服务器以通知其进行事务提交,同时Leader自身也会完成对事务的提交,而每一个 Follower服务器在接收到Commit消息后,也会完成对事务的提交。

    崩溃恢复

    什么时候进入崩溃恢复模式?

    ZAB协议的这个基于原子广播协议的消息广播过程,在正常情况下运行非常良好,但是一旦Leader服务器出现崩溃,或者说由于网络原因导致Leader服务器失去了与过半Follower的联系,那么就会进入崩溃恢复模式。

    在ZAB协议中,为了保证程序的正确运行,整个恢复过程结束后需要选举出一个新的Leader服务器。因此,ZAB协议需要一个高效且可靠的Leader选举算法,从而确保能够快速地选举出新的Leader。同时,Leader选举算法不仅仅需要让Leader自己知道其自身已经被选举为Leader,同时还需要让集群中的所有其他机器也能够快速地感知到选举产生的新的Leader服务器。

    基本特性
    根据上面的内容,我们了解到,ZAB协议规定了如果一个事务Proposal在一台机器上被处理成功,那么应该在所有的机器上都被处理成功,哪怕机器出现故障崩溃。接下来我们看看在崩溃恢复过程中,可能会出现的两个数据不一致性的隐患及针对这些情况ZAB协议所需要保证的特性。

    特性一:
    ZAB协议需要确保那些已经在Leader服务器.上提交的事务最终被所有服务器都提交。

    假设一个事务在Leader服务器上被提交了,并且已经得到过半Follower服务器的Ack反馈,但是在它将Commit消息发送给所有Follower机器之前,Leader服务器挂了
    在这里插入图片描述
    上图中的消息C2就是一个典型的例子:在集群正常运行过程中的某一个时刻,Leader服务器先后广播了消息PI、P2、C1、P3和C2,其中,当Leader服务器将消息C2(C2是CommitOfProposal2的缩写,即提交事务Proposal2)发出后就立即崩溃退出了。针对这种情况,ZAB协议就需要确保事务Proposal2最终能够在所有的服务器上都被提交成功,否则将出现不一致。

    特性二:
    ZAB协议需要确保丢弃那些只在Leader服务器上被提出的事务。

    如果在崩溃恢复过程中出现一个需要被丢弃的提案,那么在崩溃恢复结束后
    需要跳过该事务Proposal,如下图。
    在这里插入图片描述

    假设初始的Leader 服务器Server1 在提出了一个事务P3之后就崩溃退出了,从而导致集群中的其他服务器都没有收到这个事务Proposal。于是,当Serverl恢复过来再次加入到集群中的时候,ZAB协议需要确保丢弃Proposal3这个事务。

    结合上面提到的这两个崩溃恢复过程中需要处理的特殊情况,就决定了ZAB协议必须设计这样一个Leader 选举算法:
    能够确保提交已经被Leader 提交的事务Proposal, 同时丢弃已经被跳过的事务Proposal。

    针对这个要求,如果让Leader选举算法能够保证新选举出来的Leader服务器拥有集群中所有机器最高编号(即ZXID最大)的事务Proposal,那么就可以保证这个新选举出来的Leader一定具有所有已经提交的提案。因为每次提交事务ZXID都会自增,更为重要的是,如果让具有最高编号事务Proposal 的机器来成为Leader, 就可以省去Leader 服务器检查Proposal的提交和丢弃工作的这一步操作了。

    三、数据同步

    完成Leader选举之后,在正式开始工作(即接收客户端的事务请求,然后提出新的提案)之前,Leader服务器会首先确认事务日志中的所有Proposal是否都已经被集群中过半的机器提交了,即是否完成数据同步。

    ZAB协议的数据同步过程

    所有正常运行的服务器,要么成为Leader,要么成为Follower并和Leader保持同步。Leader服务器需要确保所有的Follower服务器能够接收到每一条事务Proposal,并且能够正确地将所有已经提交了的事务Proposal应用到内存数据库中去。具体的,Leader服务器会为每一个Follower服务器都准备一个队列,并将那些没有被各Follower服务器同步的事务以Proposal消息的形式逐个发送给Follower服务器,并在每一个Proposal消息后面紧接着再发送一个Commit消息,以表示该事务已经被提交。等到Follower服务器将所有其尚未同步的事务Proposal都从Leader服务器上同步过来并成功应用到本地数据库中后,Leader服务器就会将该Follower服务器加入到真正的可用Follower列表中,并开始之后的其他流程。上面讲到的就是正常情况下的数据同步逻辑。

    ZAB协议是如何处理那些需要被丟弃的事务Proposal 的。

    在ZAB协议的事务编号ZXID设计中,ZXID是一个64位的数字,其中低32位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader服务器在产生一个新的事务Proposal的时候,都会对该计数器进行加1操作;而高32位则代表了Leader周期epoch的编号,每当选举产生一个新的Leader服务器,就会从这个Leader服务器上取出其本地日志中最大事务Proposal的ZXID,并从该ZXID中解析出对应的epoch值,然后再对其进行加1操作,之后就会以此编号作为新的epoch,并将低32位置0来开始生成新的ZXID。ZAB协议中的这一通过epoch编号来区分Leader周期变化的策略,能够有效地避免不同的Leader服务器错误地使用相同的ZXID编号提出不一样的事务Proposal的异常情况,这对于识别在Leader崩溃恢复前后生成的Proposal非常有帮助,大大简化和提升了数据恢复流程。基于这样的策略,当一个包含了上一个Leader 周期中尚未提交过的事务Proposal 的服务器启动时,其肯定无法成为Leader, 原因很简单,因为当前集群中一定包含一个Quorum集合,该集合中的机器一定包含 了更高epoch的事务Proposal, 因此这台机器的事务Proposal肯定不是最高,也就无法成为Leader 了。当这台机器加入到集群中,以Follower角色连接上Leader服务器之后,Leader服务器会根据自己服务器上最后被提交的Proposal 来和Follower服务器的Proposal进行比对,比对的结果当然是Leader 会要求Follower进行一个回退操作一回退到一个确实已经被集群中过半机器提交的最新的事务Proposal。 举个例子来说,在上图中,当Serverl连接上Leader后,Leader 会要求Serverl去除P3。

    四、ZAB算法描述

    整个ZAB协议主要包括消息广播和崩溃恢复两个过程,进一步可以细分为三个阶段,分别是发现(Discovery).同步(Synchronization) 和广播( Broadcast)阶段。组成ZAB协议的每一个分布式进程,会循环地执行这三个阶段,我们将这样一个循环称为一个主进程周期。

    阶段一:发现

    阶段-.主要就是Leader选举过程,用于在多个分布式进程中选举出主进程,准Leader L和Follower F的工作流程分别如下。

    步骤F.1.1 Follower F将自己最后接受的事务Proposal 的epoch值CEPOCH发送给准Leader L。

    步骤L.1.1当接收到来 自过半Follower 的epoch值消息后,准Leader L会生成新的epoch值消息给这些过半的Follower。
    关于这个epoch值e’,准Leader L会从所有接收到的epoch值消息中选取出最大的epoch值,然后对其进行加1操作,即为e’。

    步骤F.1.2当Follower接收到来自准Leader L的新的epoch值消息后,如果其检测到当前的epoch值小于e’,那么就会将当前epoch值赋值为e’,同时向这个准Leader L反馈Ack消息。在这个反馈消息(ACK-E(F.p,hr))中,包含了当前该Follower的最后一个处理的事务,以及该Follower的历史事务Proposal集合。当LeaderL接收到来自过半Follower的确认消息Ack之后,LeaderL就会从这过半服务器中选取出一个FollowerF,并使用其作为初始化事务集合le’。
    关于这个FollowerF的选取,对于Quorum中其他任意-一个FollowerF’,F需要满足以下两个条件中的一个:
    CEPOCH(F’p) < CEPOCH (F.p) 需要小于最后一个提交事务的epoch值。
    (CEPOCH (F’p)= CEPOCH(F.p))&(F’zxid <F.zxid或F’zxid= F.zxid) 需要等于最后一个提交事务的epoch值并且zxid小于Follower f处理过的历史事务Proposal中最后一个事务Proposal 的事务标识ZXID。
    至此,ZAB协议完成阶段一的工作流程。.

    阶段二:同步

    在完成发现流程之后,就进入了同步阶段。在这一阶段中,Leader L和FollowerF的工
    作流程分别如下。

    步骤L.2.1 Leader L会将e’(最大的epcho值)和Ie’(初始化事务集合)以NEWLEADER(e’,Ie’)消息的形式发送给所有Quorum(认定整个集群是否可用的一种方式)中的Follower。

    步骤F.2.1当Follower 接收到来自Leader L的NEWLEADER(e’,le’)消息后,如果Follower发现CEPOCH (F.p) ≠e’, 那么直接进入下一轮循环,因为此时Follower发现自己还在上一轮,或者更上轮,无法参与本轮的同步。如果CEPOCH (F.p)= e’,那么Follower就会执行事务应用操作。最后,Follower 会反馈给Leader,表明自己已经接受并处理了所有L中的事务Proposal。

    步骤L.2.2当Leader接收到来自过半Follower 针对NEWLEADER(e’,Ie’)的反馈消息后,就会向所有的Follower发送Commit消息。至此Leader完成阶段二。

    步骤F.2.2当Follower收到来自Leader的Commit消息后,就会依次处理并提交所有在Ie’中未处理的事务。至此Follower完成阶段二。

    阶段三:广播
    完成同步阶段之后, ZAB协议就可以正式开始接收客户端新的事务请求,并进行消息广播流程。

    步骤L.3.1 Leader L接收到客户端新的事务请求后,会生成对应的事务Proposal,并根据ZXID的顺序向所有Follower发送提案<e’,<v,z>>,其中epoch(z) = e’

    步骤F.3.1Follower根据消息接收的先后次序来处理这些来自Leader的事务Proposal,并将他们追加到hp中去,之后再反馈给Leader。

    步骤L.3.1当Leader 接收到来自过半Follower 针对事务Proposal <e’,<v,z>>的Ack消息后,就会发送Commit <e’,<v,z>>消息给所有Follower,要求它们进行事务的提交。
    步骤F.3.2当Follower F接收到来自Leader的Commit <e’,<v,z>>消息后,就会开始提交事务Proposal<e’,<v,z>>。 需要注意的是,此时该FollowerF必定已经提交了事务Proposal<v’,z’>
    以上就是整个ZAB协议的三个核心工作流程。

    五、ZAB 与Paxos算法的联系与区别

    ZAB协议并不是Paxos算法的一个典型实现,在说ZAB和Paxos之间的区别之前,我们首先来看下两者的联系。

    • 两者都存在一个类似于Leader进程的角色,由其负责协调多个Follower进程的运行。
    • Leader进程都会等待超过半数的Follower做出正确的反馈后,才会将一个提案进行提交。
    • 在ZAB协议中,每个Proposal中都包含了一个epoch值,用来代表当前的Leader周期,在Paxos算法中,同样存在这样的一个标识,只是名字变成了Ballot。

    在Paxos算法中,一个新选举产生的主进程会进行两个阶段的工作。第一阶段被称为读阶段,在这个阶段中,这个新的主进程会通过和所有其他进程进行通信的方式来收集上一个主进程提出的提案,并将它们提交。第二阶段被称为写阶段,在这个阶段,当前主进程开始提出它自己的提案。在Paxos算法设计的基础上,ZAB协议额外添加了一个同步阶段。在同步阶段之前,ZAB协议也存在一个和Paxos算法中的读阶段非常类似的过程,称为发现(Discovery)阶段。在同步阶段中,新的Leader会确保存在过半的Follower已经提交了之前Leader周期中的所有事务Proposal。 这一同步阶段的引入,能够有效地保证Leader在新的周期中提出事务Proposal之前,所有的进程都已经完成了对之前所有事务Proposal的提交。一旦完成同步阶段后,那么ZAB就会执行和Paxos算法类似的写阶段。总的来讲,ZAB协议和Paxos 算法的本质区别在于,两者的设计目标不太一样。

    不同点总结:
    ZAB协议主要用于构建一个高可用的分布式数据主备系统,例如ZooKeeper
    Paxos算法则是用于构建一一个分布式的一致性状态机系统。

    六、运行状态

    在ZAB协议的设计中,每-一个进程都有可能处于以下三种状态之一。

    • LOOKING: Leader选举阶段
    • FOLLOWING: Follower 服务器和Leader保持同步状态
    • LEADING:Leader服务器作为主进程领导状态
    展开全文
  • 保证分布式数据一致性的6种方案

    千次阅读 2018-07-30 17:17:07
    在电商等业务中,系统一般由多个独立的服务组成,如何解决分布式调用时候数据一致性?  具体业务场景如下,比如一个业务操作,如果同时调用服务 A、B、C,需要满足要么同时成功;要么同时失败。A、B、C 可能是多...
  • 现在很多的系统都是采用分布式架构,在分布式系统中需要解决的...简单讲:数据一致性就是指在对一个副本数据进行更新的时候必须确保能够更新其他的副本,否则不同副本之间的数据将会导致不一致 一致性级别:  ...
  • LCN分布式事务框架框架介绍LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果。核心步骤创建事务组是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,...
  • 解决分布式系统一致性的问题

    千次阅读 2019-04-26 23:15:26
    一致性 随着公司的访问量增加,不但要求对用户的响应速度快,还要求吞吐量的指标向外扩展(即水平伸缩)。于是单节点的服务器已经无法满足需求,又随着人员的增多以及项目的多职责,于是我们谈论最多的话题就是拆分。...
  • 《彻底解决分布式系统一致性问题》直播者:李艳鹏 笔记作者:JKXQJ一致性问题产生的背景JEE架构:WEB容器—组合业务逻辑—>EJB容器—数据存ORM—>数据库 SSH架构:Struts MVC—组合业务逻辑—>Spring容器—...
  • 一、分布式数据一致性在分布式系统中,为了保证数据的高可用,通常会将数据保留多个副本(replica),这些副本会放置在不同的物理的机器上。1.什么是数据一致性在数据有多份副本的情况下,如果网络、服务器或者软件...
  • 如何可靠保存凭证(消息) 有两种方法:业务与消息耦合的方式 支付宝在完成扣款的同时,同时记录消息数据,这个消息数据与业务数据保存在同一数据库实例里(消息记录表表名为message);12345Begin transaction ...
  • 分布式系统的事务一致性是一个技术难题,各种解决方案孰优孰劣? 在OLTP系统领域,我们在很多业务场景下都会面临事务一致性方面的需求,例如最经典的Bob给Smith转账的案例。传统的企业开发,系统往往是以单体应用...
  • 分布式数据库一致性解决初步

    千次阅读 2015-08-20 21:46:27
    一、关于分布式系统事务一致性问题 Java 中有三种可以的事务模型,分别称作本地事务模型(Local Transaction Model),编程式事务模型(Programmatic Transaction Model),和声明式事务模型(Declarative ...
  • 如何保证分布式系统数据一致性

    万次阅读 2018-12-24 10:26:05
    面试的时候,有面试官问到:选取你比较熟悉的项目,谈谈如何在做容灾负载的时候数据一致性问题,具体点比如你里面的派单,如何保证一个司机不在同一时间内接到两个订单,然后保证实时性?  一般的解决方案是在派单...
  • 分布式事务一致性

    千次阅读 2018-05-25 17:18:45
    有人的地方,就有江湖有江湖的地方,就有纷争问题的起源在电商等业务中,系统一般由多个独立的服务组成,如何解决分布式调用时候数据一致性? 具体业务场景如下,比如一个业务操作,如果同时调用服务 A、B、C,...
  • 分布式技术发展下,数据一致性解决方法和技术也在不断的演进,本文就以作者实际研发的分布式数据库作为案例,介绍分布式数据库数据一致性的原理以及实际实现。 1.数据一致性 1.1数据一致性是什么 大部份使用传统...
  • 分布式系统 介绍了分布式系统的定义、实现原则和几种形式,详细介绍了微服务架构的分布式系统,并使用Spring Cloud框架演示了一个完整的微服务系统的实现过程。 5-1 CAP原则和BASE理论简介 5-2 分布式系统...
  • 布式事务实践 解决数据一致性 收藏
  • 面试问题(如何保证分布式数据最终一致性

    万次阅读 多人点赞 2018-03-01 10:51:42
    保证分布式系统数据一致性的6种方案编者按:本文由「高可用架构后花园」群讨论整理而成。有人的地方,就有江湖有江湖的地方,就有纷争问题的起源在电商等业务中,系统一般由多个独立的服务组成,如何解决分布式调用...
  • 分布式系统一致性研究

    千次阅读 2014-09-22 19:50:23
    本文希望对分布式系统的一致性问题做一个综合性介绍,奈何笔轻心重,语无伦次。感谢eric的敦促,感谢shuai的感召,我尝试总结一下。这个草稿堆积了一段时间了,大家提点意见,我再更新。谢谢!
  • 怎么解决分布式场景下数据一致性 问题 ,暂且用 分布式事务 来定义吧。 同样的问题还存在于其他的场景: 送礼: 调用支付服务:先扣送礼用户的金币,然后给主播加相应的荔枝 确认第一步成功后...
  • 背景  可用性(Availability)和一致性(Consistency)是分布式系统的基本问题,先有著名的CAP理论定义过分布式环境下二者不可兼... 在大数据场景下,分布式数据库的数据一致性管理是其最重要的内核技术之一,也...
  • 分布式系统一致性算法

    万次阅读 2018-07-29 21:34:32
    CAP理论 一致性(Consistency) 可用性(Availability) 分区容错性(网络分区...AP(放弃C):放弃强一致性,用最终一致性来保证。 CP(放弃A):一旦系统遇见故障,受到影响的服务器需要等待一段时间,在恢复期间...
  • 一致性算法是用来解决一致性问题的,那么什么是一致性问题呢? 在分布式系统中,一致性问题(consensus problem)是指对于一组服务器,给定一组操作,我们需要一个协议使得最后它们的结果达成一致. 更详细的解释就是,当其中...
  • “什么是分布式系统?...分布式一致性问题随处可见,任何一个实体/联接模型,都可能存在分布式一致性问题。如果把单机拆开来看,CPU、内存、I/O设备组成的机箱本身就是一个小型的分布式系统,需要确保对...
  • 背景 可用性(Availability)和一致性(Consistency)是分布式系统的基本问题,先有著名的CAP理论定义过...在大数据场景下,分布式数据库的数据一致性管理是其最重要的内核技术之一,也是保证分布式数据库满足数...
  • 文章目录一、写在前面的话二、数据库的事务三、分布式环境的各种问题三、CAP和BASE理论四、一致性协议(1)两阶段提交(2)三阶段提交(3)Paxos算法五、写在最后的话 一、写在前面的话 在分布式来临之前,主流是...
  • 保障分布式系统数据一致性

    千次阅读 2016-05-15 10:31:10
    具体业务场景如下,比如一个业务操作,如果同时调用服务 A、B、C,需要满足...在工程实践上,为了保障系统的可用性,互联网系统大多将强一致性需求转换成最终一致性的需求,并通过系统执行幂等性的保证,保证数据的最终
  • 保证分布式系统数据一致性的6种方案

    万次阅读 多人点赞 2016-04-19 22:57:20
    保证分布式系统数据一致性的6种方案

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 228,629
精华内容 91,451
关键字:

怎么解决分布式数据一致性