首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

ZAB协议

背景

ZAB协议中主要有两种模式,第一是消息广播模式;第二是崩溃恢复模式

消息广播模式就是2pc,奔溃恢复模式就是在leader宕机如何重新同步数据

1

zookeeper(server + client )不是一个数据存储系统,不能存储大量的数据,它存储的是数据的状态,server端维护数据状态来保证client端实现 分布式锁、选举算法、分布式互斥等语义!

如何保证数据一致性,即多副本之间数据一致性,就成为server端必须解决的问题! 使用zab协议来实现

2

写到事务提交的时候,发现自己对分布式事务理解还不够深

之前的片面理解: 搜索广告点击产生分布式事务: 广告展示系统A + 广告扣费系统B 两个系统动作必须要同时成功或者回滚! 如果在同一个系统中,在一个事务中很好操作,但是现在是分布式系统了难度提高

现在的场景: zk leader 写请求 + zk follower 1 写同步 +.. , 这也是分布式系统,也需要保证同时成功或者失败!

所以都是分布式事务,所以用到的解决理论也是同一套: 2PC,3PC, TCC(try, commit, cancel)

正文

zk知识背景

a: 只有一个leader,多个follower,多个observer(只读),只有leader 能写,follow能提供读和选举投票

zk节点数要求是2f+1,在写或者选举的时候需要f+1个节点通过才能成功!

b: 只有leader能写,保证了其写的顺序性,因为只与一个节点通讯能保证接收的顺序

c: leader 奔溃,需要借助(myid, zxid) 比较大小来选举,最大的称为新的leader

d:zk 重读轻写场景

e:Zk规定节点的数据大小不能超过1M

Zab(Zookeeper Atomic Broadcast)

a:定义

Zxid: 在 ZAB 协议的事务编号 Zxid 设计中,Zxid 是一个 64 位的数字,其中低 32 位是一个简单的单调递增的计数器,针对客户端每一个事务请求,计数器加 1;而高 32 位则代表 Leader 周期 epoch 的编号,每个当选产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务的ZXID,并从中读取 epoch 值,然后加 1,以此作为新的 epoch,并将低 32 位从 0 开始计数。@hxx 每个follower只会接收比自己lastZxid 大的zxid的提议

epoch:可以理解为当前集群所处的年代或者周期,每个 leader 就像皇帝,都有自己的年号,所以每次改朝换代,leader 变更之后,都会在前一个年代的基础上加 1。这样就算旧的 leader 崩溃恢复之后,也没有人听他的了,因为 follower 只听从当前年代的 leader 的命令。@hxx 防止旧leader复活了,行使权力

选举: 每个follower都提供一个序列(myid, zxid)告诉集群自己要投这个节点称为leader,刚开始的时候当然都投自己啦, 然后每个节点都收到了其他节点发过来的二数据序列,然后与自己当前的(myid, zxid)比较

比较的过程是:先比zxid,找到最大的,然后再比myid找到最大的,这个时候得到一个新的序列,更新自己的序列,再次告诉集群,我这次投了新的这个序列(如果自己最大,因为上一次就是投的自己就不更新了保持)

最后统计票数,每个节点收到的投票结果,把超过半数的作为自己节点承认的leader(有可能某个节点没有统计的结果和别人有差别,那么它会连接到其实是一台follower的节点,但是连接的时候会遭到拒绝(因为那台follower知道自己不是leader,你不要连接我),认错leader的节点开始重新统计),只有当所有的节点都认为leader一致时,leader才会真正上位!

@hxx: 选zxid最大的是因为这个值最大说明这个节点的数据最新,可以减少主从数据同步;而myid最大没有特殊含义,因为myid是自己编号的,只是一种策略!

b: zab 奔溃恢复模式@hxx 当leader崩溃或者leader失去大多数的follower,这时zk进入恢复模式

step1: 选举, 上面讲了, 注意选出来的leader拥有最大的zxid!

step2: 恢复或称为发现, follower和leader 通讯,让leader知道自己有多少个follower,leader更新自己,并且为新leader生成新的epoch,让follower更新自己的acceptedEpoch@hxx 改朝换代了,老朝代的东西都要更新成新朝代的啦

step3:同步,follower接收leader的事务提议,当然follower只会更新比自己lastZxid的事务就好,或者进行事务的回退(如果在leader之后又接收了事务,这个时候不算)

step4: 广播, leader开始上朝了,zk集群正式对外提供事务服务,如果有新节点加入对新节点同步

注意,奔溃恢复模式需要保证两点:确保已经被leader提交的proposal必须最终被所有的follower服务器提交; 确保丢弃已经被leader提出的但是没有被提交的proposal。

c: zab 数据同步-事务提交

有一点不明,上面说了zk写请求,只会与leader通讯,那么直接写入leader就行呀,而且只要保证写入的顺序性就行使用TCP协议就可以做到这个顺序性,这里会有什么问题呢?

见前言

过程(2PC): client 写请求,follower将请求转发给leader(一个client只会连接一台server),leader收到请求,将提议发给所有follower,收到follower 写成功的ack超过半数,则再次像所有follower发送commit 命令,要求提交此次事务,否则cancel,leader将最新的数据同步给observer节点,follower将此次写请求结果返回给client!

@hxx 2pc 之前有笔记说过,缺陷是有一个协调中心(leader)单点,并且通信比较多,3pc是增加了通信超时策略

zookeeper中消息广播的具体步骤如下:

c.1. 客户端发起一个写操作请求

c.2. Leader服务器将客户端的request请求转化为事物proposql提案,同时为每个proposal分配一个全局唯一的ID,即ZXID。

c.3. leader服务器与每个follower之间都有一个队列,leader将消息发送到该队列

c.4. follower机器从队列中取出消息处理完(写入本地事物日志中)毕后,向leader服务器发送ACK确认。

c.5. leader服务器收到半数以上的follower的ACK后,即认为可以发送commit

c.6. leader向所有的follower服务器发送commit消息。

注意,zookeeper采用ZAB协议的核心就是只要有一台服务器提交了proposal,就要确保所有的服务器最终都能正确提交proposal。这也是CAP/BASE最终实现一致性的一个体现。

leader服务器与每个follower之间都有一个单独的队列进行收发消息,使用队列消息可以做到异步解耦。leader和follower之间只要往队列中发送了消息即可。如果使用同步方式容易引起阻塞。性能上要下降很多。@hxx 因为一个client只会连接到一个follower,所以不用担心队列间的数据顺序

d: observer 角色作用

在之前老的版本zk中没有observer,当client越来愈多时,需要对集群扩节点,那么扩的是follower节点,读性能提升了,但是写性能会严重下降

有了observer,扩节点时只扩observer节点,由于observer不参与投票,那么不会引起写性能的下降,所有observer出现是为了提高系统的弹性能力!

e:zookeeper部署模式

单机模式(一台zk),集群模式(3台或以上),伪集群(在一台机器上搭建多节点)

集群模式下的 observer模式

为了使用Observer模式,在任何想变成Observer模式的配置文件($ZOOKEEPER_HOME/conf/zoo.cfg)中加入如下配置:

peerType=observer

并在所有Server的配置文件($ZOOKEEPER_HOME/conf/zoo.cfg)中,配置成Observer模式的server的那行配置追加:observer,例如:

server.1:localhost:2181:3181:observer

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190205G0C4UE00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券