前面介绍了ZooKeeper的基本知识,这一节我们介绍一下ZooKeeper使用的协议。只有了解了ZooKeeper的协议,才能更好得理解ZooKeeper源代码的实现。ZooKeeper使用的是Zab(ZooKeeper Atomic Broadcast)协议,它是基于Paoxs算法实现的。所以这一节我们按照这个顺序来讲解:

  • Paoxs算法
  • Zab协议

  

Paoxs算法

首先看一下Paoxs算法,一般说到zookeeper,我们都会提起Paoxs算法Lesile Lamport.

Paoxs算法是zookeeper的灵魂,这个算法是Leslie Lamport在1990年提出的一种基于消息传递的一致性算法.Paxos 算法解决的问题是一个分布式系统如何就某个值(决议)达成一致。在ZooKeeper中的应用场景就是Leader选举。

该算法由Leslie于1990年在文章The Part-Time Parliament中首次提出,但是这篇文章相当的晦涩难懂(也有一些轶事,可以看文章链接中Leslie自己写的内容),于是,Lesilie在2001年写下了Paxos Made Simple.他对此解释道:

At the PODC 2001 conference, I got tired of everyone saying how difficult it was to understand the Paxos algorithm, published in [122]. Although people got so hung up in the pseudo-Greek names that they found the paper hard to understand, the algorithm itself is very simple. So, I cornered a couple of people at the conference and explained the algorithm to them orally, with no paper. When I got home, I wrote down the explanation as a short note, which I later revised based on comments from Fred Schneider and Butler Lampson. The current version is 13 pages long, and contains no formula more complicated than n1 > n2.

Paxos Made Simple的abstract只有一句话:

The Paxos algorithm, when presented in plain English, is very simple.

在上文中是这样描述Paoxs算法执行过程的:

Phase 1.

(a) A proposer selects a proposal number n and sends a prepare request with number n to a majority of acceptors.

(b) If an acceptor receives a prepare request with number n greater than that of any prepare request to which it has already responded, then it responds to the request with a promise not to accept any more proposals numbered less than n and with the highest-numbered proposal (if any) that it has accepted.

Phase 2.

(a) If the proposer receives a response to its prepare requests (numbered n) from a majority of acceptors, then it sends an accept request to each of those acceptors for a proposal numbered n with a value v, where v is the value of the highest-numbered proposal among the responses, or is any value if the responses reported no proposals.

(b) If an acceptor receives an accept request for a proposal numbered n, it accepts the proposal unless it has already responded to a prepare request having a number greater than n.

这几乎就是Paxos的全部了.  这里就不一句一句翻译了。

Zab协议

Zab是一个高性能的广播协议,主要用于主备系统,它是专门为ZooKeeper设计的。Zab协议的详细内容请参考论文《Zab: High-performance broadcast for primary-backup systems》。

ZAB相比Paxos的优点有:

  • 状态一致性保证,为了保证状态一致性,Zookeeper提出了两个安全属性(Safety Property) :

    • 全序(Total order):如果消息a在消息b之前发送,则所有Server应该看到相同的结果。
    • 因果顺序(Causal order):如果消息a在消息b之前发生(a导致了b),并被一起发送,则a始终在b之前被执行。
  • 更高效得从失败中恢复。状态一致性保证了多个ZooKeeper客户端同时进行多个事务操作的正确性。所以当一个leader挂掉之后,新的leader只需要从选举它的一个多数派中获得当前最大的事务号作为它的恢复点,这样leader最多只需要跟具有最大的事务号的那一个进程(如果有多个,由于状态一致性保证,随机挑一个即可)同步即可。而在Paoxs中,由于同一个事务(这里实际上是指序列号)可以有多个不同的投票,不同的进程对于同一个事务可能接受不同的值,所以不能简单的使用事务号来选择恢复点,新的leader需要找到当前最大的事务号,然后对于它已经commit的事务号跟这个最大的事务号之间的每一个事务号都需要重新执行一遍Phase1得到最终commit的值,这样的恢复过程 复杂而且不够高效。

  Paxos的一致性不能达到ZooKeeper的要求。因为Paoxs只是保证最终一致性,如果处理的请求之间有依赖关系,利用Paoxs处理的时候可能满足不了这些依赖关系。举个例子:假设一开始Paxos系统中的leader是P1,它发起了两个事务<t1, v1>(表示序号为t1的事务要写的值是v1)和<t2, v2>,过程中挂了。新来个leader是P2,它发起了事务<t1, v1'>。而后又来个新leader是P3,它汇总了一下,得出最终的执行序列<t1, v1'>和<t2, v2>,即P2的t1在前,P1的t2在后。对应到ZooKeeper中的操作,P1对应的事务t1要创建"/a",事务t2要创建"/a/test",而P2的事务t1要创建"/b",P3汇总了之后得出的结论是先创建"/b",再创建"/a/test"。而对于ZooKeeper中的创建操作,只有父节点已经存在的情况下才能创建子节点,也即只有先成功创建了"/a",接下来创建"/a/test"才能成功,所以创建完"/b"之后再创建"/a/test"就会失败,这不是我们希望的结果。

  为了保证这一点,ZAB要保证同一个leader的发起的事务要按顺序被apply,同时还要保证只有先前的leader的所有事务都被apply之后,新选的leader才能发起新的事务。ZAB的核心思想,形象的说就是保证任意时刻只有一个节点是leader,所有更新事务都由leader发起去更新所有复本(称为follower),更新时用的就是两阶段提交协议,只要多数节点prepare成功,就通知他们commit。各follower要按当初leader让他们prepare的顺序来apply事务。因为ZAB处理的事务永远不会回滚,ZAB的2阶段提交做了点优化,多个事务只要通知zxid最大的那个commit,之前的各follower会统统commit。

  

  

  剩下的就是怎么来保证leader的可靠性,因为leader是会crash的,所以引入了leader选举机制。leader选举是基于Paoxs协议的,成为leader的条件是必须要有一个多数派支持,此外还需要知道以下知识:

  • leader跟follower之间通过心跳来检测异常;
  • follower检测到leader心跳异常之后,会重新发起leader选举,一个follower若试图成为新的leader,首先要获得一个多数派的支持,然后从状态最新的节点同步事务,完成后才可正式成为leader发起新的事务;

  Leader选举遇到的最大问题是:新Leader是否要继续老Leader的状态。这里要按老Leader Crash的时机分两种情况:

  • 老Leader在COMMIT前Crash(已经提交到本地)
  • 老Leader在COMMIT后Crash,但有部分Follower接收到了Commit请求

  第一种情况,这些数据只有老Leader自己知道,当老Leader重启后,需要与新Leader同步并把这些数据从本地删除,以维持状态一致。

  第二种情况,新Leader应该能通过一个多数派获得老Leader提交的最新数据。

  老Leader重启后,可能还会认为自己是Leader,可能会继续发送未完成的请求,从而因为两个Leader同时存在导致算法过程失败,ZooKeeper的解决办法是把Leader信息加入每条消息的id中,Zookeeper中称为zxid,zxid为一64位数字,高32位为leader信息又称为epoch,每次leader转换时递增;低32位为消息编号,Leader转换时应该从0重新开始编号。通过zxid,Follower能很容易发现请求是否来自老Leader,从而拒绝老Leader的请求。

综上可见,Zab协议实际上还是基于Paoxs衍生出来的,Paoxs中没有保证请求之间的逻辑顺序,只考虑数据的全序,Zab在这方面进行了完善补充,同时由于leader的存在,简化了Paoxs的二段提交为一段提交(Phase2),最后为了确保leader的可靠性,又基于Paoxs协议实现了leader的选举机制。

[ZooKeeper研究]二 ZooKeeper协议介绍的更多相关文章

  1. [Zookeeper研究]一 Zookeeper技术简介

    最近的项目中使用到了Zookeeper.Kafka以及Storm.仔细研究了一下,觉得这几个开源项目对于搞分布式的人来说是非常有用的,所以想把自己的一点心得体会总结一下,希望能对大家有所帮助. 首先从 ...

  2. 分布式服务框架 Zookeeper(二)官方介绍

    ZooKeeper:为分布式应用而生的分布式协调服务 ZooKeeper是一个为分布式应用而设计的分布式的.开源的协调服务.它提供了一套简单的原语,分布式应用利用这套原语可以实现更高层的服务,比如一致 ...

  3. zookeeper笔记(二)

    title: zookeeper笔记(二) zookeeper ALC权限控制 getAcl path 可以查看某个node的权限 设置权限: 2. world方式 setAcl <path&g ...

  4. zookeeper核心之ZAB协议就这么简单!

    背景 我们都知道 Zookeeper 是基于 ZAB 协议实现的,在介绍 ZAB 协议之前,先回顾一下 Zookeeper 的起源与发展. Zookeeper 究竟是在什么样的时代背景下被提出?为了解 ...

  5. 【Zookeeper系列】Zookeeper简单介绍(转)

    原文链接:https://www.cnblogs.com/sunddenly/p/4033574.html 一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技 ...

  6. ZooKeeper学习之-Zookeeper简单介绍(一)

    一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技术.那么什么是分布式协调技术?那么我来告诉大家,其实分布式协调技术主要用来解决分布式环境当中多个进程之间的同 ...

  7. Zookeeper架构、ZAB协议、选举

    转载:深入浅出Zookeeper(一) Zookeeper架构及FastLeaderElection机制  (nice) ZooKeeper学习第六期---ZooKeeper机制架构 一.Zookee ...

  8. 分布式助手Zookeeper(二)

    分布式助手Zookeeper(二)博客分类: Zookeeper zookeeperzookeeper的安装和配置观察者observer 散仙在上篇文章介绍了,zookeeper的一系列基础知识,如果 ...

  9. zookeeper(二): Curator vs zkClient

    目录 zookeeper Curator zkClient 客户端对比 写在前面 1.1. zookeeper应用开发 1.1.1. ZkClient简介 1.1.2. Curator简介 写在最后 ...

随机推荐

  1. web api简单验证实现办法

    需要使用WEBAPI,但是有验证问题没解决.后来参考网上文章做了一下DEMO 思路: 就是根据用户的账号在服务端加密一个字符串,然后返回给用户端. 具体: 一个用户编号用于唯一身份识别,密码,一个密钥 ...

  2. Form 表单常用正则验证 (收藏)

    1.^\d+$ //匹配非负整数(正整数 + 0) 2.^[0-9]*[1-9][0-9]*$ //匹配正整数 3.^((-\d+)|(0+))$ //匹配非正整数(负整数 + 0) 4.^-[0-9 ...

  3. 兼容性之IOS下label 无法点击

    今天做移动端的页面时碰到一个稀奇的问题,那就是点击label无法选中与之相关的checkbox,下面是问题代码: <li class="list-item clearfix notif ...

  4. hadoop中datanode无法启动

    一.问题描述 当我多次格式化文件系统时,如 [hadoop@xsh hadoop]$ ./bin/hdfs namenode -format 会出现datanode无法启动,查看日志(/usr/loc ...

  5. [转载]linux下mysql 自动备份

    ySQL :: Linux 下自动备份数据库的 shell 脚本Linux 服务器上的程序每天都在更新 MySQL 数据库,于是就想起写一个 shell 脚本,结合 crontab,定时备份数据库.其 ...

  6. Python核心编程(第九章)--文件和输入输出

    文件内建函数: open()函数提供了初始化输入/输出操作的通用接口 open()基本语法:file_object = open(filename,access_mode='r',buffering= ...

  7. 字符串:各种奇葩的内置方法 - 零基础入门学习Python014

    字符串:各种奇葩的内置方法 让编程改变世界 Change the world by program 字符串:各种奇葩的内置方法 或许现在又回过头来谈字符串,有些朋友可能会觉得没必要,也有些朋友会觉得不 ...

  8. hdu 5305Friends

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5305 Problem Description There are n people and m pai ...

  9. nginx日志管理与限速

    1.日志简介nginx日志主要有两种:访问日志和错误日志.访问日志主要记录客户端访问nginx的每一个请求,格式可以自定义:错误日志主要记录客户端访问nginx出错时的日志,格式不支持自定义.两种日志 ...

  10. 关于android:focusable属性

    http://www.cnblogs.com/Gaojiecai/archive/2013/06/18/3142783.html Android属性 android:focusableInTouchM ...