ZooKeeper基础

ZooKeeper是一个分布式协调服务的开源框架。主要用来解决分布式集群中应用系统的一致性问题。

ZooKeeper本质上是一个分布式的小文件存储系统,提供基于类似文件系统的目录树方式的数据存储。并且可以对树中的节点进行有效管理,从而用来维护和监控你存储的数据的状态变化。通过监控这些数据状态的变化,从而可以达到基于数据的集群管理。诸如:统一命名服务、分布式配置管理、分布式消息队列、分布式锁、分布式协调等功能。

1. 基本概念

角色

一个ZooKeeper集群中的机器角色分为3种:Leader,Follower和Observer。

  • Leader:负责整个集群的写操作,保证集群内事务处理的顺序性。并且负责与所有的 Follower进行内部的数据同步。
  • Follower:用于接收客户端读请求并向客户端返回结果,对于写请求转交给Leader。并且在选举过程中参与投票。
  • Observer:Observer角色不参与投票(Leader写数据时Follewer需要返回ack,而Observer则不需要),其它功能与Follower相同。引入Observer角色的目的是增加ZooKeeper集群的吞吐量。如果单纯的增加Follower,那么ZooKeeper集群的写能力会大大降低(ZooKeeper写数据时Leader会同步给Follower),因此通过引入Observer角色,使得ZooKeeper集群在写能力不降低的情况下,大大提升了读能力。

会话

zookeeper 中客户端启动时会与服务器建立一个 TCP 连接,从第一次连接建立开始,客户端会话的生命周期就开始了,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向服务器发送请求并接受响应,还能够接收来自服务器的 watch 事件通知。

节点

Zookeeper树中的每个节点被称为Znode。和文件系统的目录树一样,Zookeeper树中的每个节点可以拥有子节点。Znode具有原子性操作并且Znode的数据存储大小有限制。

每个Znode由3部分组成:

  1. stat:此为状态信息,描述该Znode的版本,权限等信息
  2. data:与该Znode关联的数据
  3. children:该Znode下的子节点

Znode有两种,分别为临时节点和永久节点。节点的类型在创建时即被确定,并且不能改变。

  • 临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,当让也可以手动删除。临时节点不允许拥有子节点
  • 永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作时,它们才能被删除。

Znode还有一个序列化的特性,如果创建的时候指定的话,该Znode的名字后面会自动追加一个不断增加的序列号。这样便会存在4种类型的Znode节点,分别对应:

  • PERSISTENT:永久节点
  • EPHEMERAL:临时节点
  • PERSISTENT_SEQUENTIAL:永久节点 序列化
  • EPHEMERAL_SEQUENTIAL:临时节点序列化

我们可以通过ZooKeeper系列号临时节点来实现分布式锁。

每个Znode都包含一系列的属性,下面是一些常见的节点的属性:

  • dataVersion:数据版本号,每次对节点进行set操作,dataVersion的值都会增加1.
  • cversion:子节点的版本号。当znode的子节点有变化时,cversion的值就会增加1
  • aclVersion:ACL版本号,用于访问权限控制
  • cZxid:Znode创建的事务id
  • mZxid:Znode被修改的事务id,即每次对znode的修改都会更新mZxid
  • ephemeralOwner:如果该节点为临时节点,ephemeralOwner值表示与该节点绑定的session id,如果不是,ephemeralOwner值为0

2. 读写流程

下图展示了ZooKeeper的读写流程:


ZooKeeper读写流程.PNG

对于读请求,不论client连接的是哪一种角色,ZooKeeper集群都能直接返回(因为每台机器都保存着相同的数据副本)。

消息广播

而对于写请求,如果client请求的是Follower或Observer,那么写请求将被转发到Leader。下面是Leader处理写请求的流程:

  1. Leader 接收到消息请求后,将消息赋予一个全局唯一的 64 位自增 id,叫做:zxid,通过 zxid 的大小比较即可实现因果有序这一特性。
  2. Leader 通过先进先出队列(会给每个follower都创建一个队列,保证发送的顺序性,通过 TCP 协议来实现,以此实现了全局有序这一特性)将带有 zxid 的消息作为一个提案(proposal)分发给所有 follower。
  3. 当 follower 接收到 proposal,先将 proposal 写到本地事务日志,写事务成功后再向 leader 回一个 ACK。
  4. 当 leader 接收到过半Follower的ACK后,leader 就向所有 follower 发送 COMMIT 命令,并在本地执行事务提交。
  5. 当 follower 收到消息的 COMMIT 命令时,就会提交事务从而写操作生效。

上面的流程也被称为消息广播。

ZAB协议(ZooKeeper使用的分布式一致性协议)的消息广播过程使用的是一个原子广播协议,类似于一个2PC提交过程,针对每个客户端的事务请求,leader服务器会为其生成对应的事务Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各自的选票,最后进行事务提交。

上面的消息广播过程在Leader宕机时可能会出现两个中间状态:

  1. 当 leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回「成功」。但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息。

  2. 当 leader生成 proposal后就挂了,其他 follower 并没有收到此 proposal(或者只有一小部分收到了这条proposal),那么这条消息就是执行失败的。如果之前挂了的 leader重新启动并成为了新的leader,他保留了这条proposal,就可能将这条proposal同步给其他Follower并进行提交,那么这条proposal就是一条脏数据了。

因此,在Leader宕机后,ZooKeeper(ZAB协议)会快速的进行Leader重新选举,即崩溃恢复过程。

崩溃恢复

ZAB协议规定的崩溃恢复过程必须完成以下两件事:

  1. 对于所有原Leader已经提交了的proposal,新Leader必须能够广播并提交。
  2. 对于原Leader还未广播或只部分广播成功的proposal,新Leader能够通知原Leader或者已经同步了的Follower删除从而保证集群数据的一致性。

对于要求1,ZAB协议会选举拥有 proposal最大值(即 zxid 最大)的节点作为新的Leader。此时所有的Follower会将自己的最大zxid发送给Leader,Leader对于每一个Follower,将其落后的commit发送给Follower,Follower提交后达成一致性状态。同时,对于落后的proposal,只有当半数Follower都存在这条proposal时,Leader才会将其同步给Follower,否则Leader会通知所有拥有这条proposal的Follower删除。当Follower服务器将所有尚未同步的事务proposal都从Leader服务器同步过来并成功应用到本地后,Leader服务器就会将该Follower加入到真正可用的Follower列表中。如下图所示:

Leader同步.jpg

另外,对于要求2,当Follower存在一条半数机器都不存在的proposal时,Leader会通知其删除。

同时,Zab协议中一个 zxid 是64位,高 32 是纪元(epoch)编号,每经过一次 leader 选举产生一个新的 leader,新 leader 会将 epoch 号 +1。低 32 位是消息计数器,每接收到一条消息这个值 +1,新 leader 选举后这个值重置为 0。ZAB协议通过epoch编号来区分Leader变化周期,能够有效的避免了不同的Leader错误的使用了相同的ZXID编号提出了不一样的proposal的异常情况。

崩溃恢复的流程可以概括如下:

  1. 首先集群内机器进行投票选举Leader(每台机器都存在三种状态:LOOKING,LEADING和FOLLOWING)
  2. Leader选举成功后向所有Follower进行proposal同步
  3. 同步完成后,Leader正式成为Leader开始对外提供服务

3. ZAB协议和RAFT协议的对比

相同点:

  • 都使用timeout来重新选择leader,都采用心跳检测存活性
  • 采用quorum来确定整个系统的一致性(也就是对某一个值的认可),这个quorum一般实现是集群中半数以上的服务器,zookeeper里还提供了带权重的quorum实现
  • 都由leader来发起写操作

不同点:

  • zab用的ZXID中的epoch和count的组合来表示选举优先级, 而raft用的是term和index
  • Raft中的每个server在某个term轮次内只能投一次票,哪个candidate先请求投票谁就可能先获得投票,这样就可能造成split vote,即各个candidate都没有收到过半的投票,Raft通过candidate设置不同的超时时间,来快速解决这个问题,使得先超时的candidate(在其他人还未超时时)优先请求来获得过半投票。ZooKeeper中的每个server,在某个electionEpoch轮次内,可以投多次票,只要遇到更大的票就更新,然后分发新的投票给所有人。这种情况下不存在split vote现象,同时有利于选出含有更新更多的日志的server,但是选举时间理论上相对Raft要花费的多。
  • raft协议的心跳是从leader到follower,而zab协议则相反

Raft协议请参考我的文章:https://www.jianshu.com/p/d5ac9eaeab30

4. ZooKeeper一致性

首先强一致性(strong consistency)表示任何时刻,任何用户都能读取到最近一次成功更新的数据。由于ZooKeeper在写数据时超过过半Follower的ACK后就返回,因此ZooKeeper可能读取到旧数据,因此显然不是强一致性。

ZooKeeper支持顺序一致性,即来自任意特定客户端的更新都会按其发送顺序被提交。也就是说,如果一个客户端将Znode z的值更新为a,在之后的操作中,它又将z的值更新为b,则没有客户端能够在看到z的值是b之后再看到值a(如果没有其他对z的更新)。

但是有可能client首先连接已经更新为b的机器,读取出值为b,然后再次连接了更新较慢的机器读出值为a。这样就不满足顺序一致性了。ZooKeeper为了解决这个问题,使用了单一视图的概念。

单一视图:Zookeeper 会为每个消息打上递增的 zxid(zookeeper transactioin id),客户端会维护一个 lastZxid,存放最后一次读取数据对应的 zxid,当客户端连接时,节点会判断 lastZxid 是不是比自己的 zxid 更大,如果是,说明节点的数据比客户端老,拒绝连接。

参考文章:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容