一、Zookeeper的基本概念
1.1 ZooKeeper的作用:
ZooKeeper是一个分布式协调技术、高性能的,开源的分布式系统的协调(Coordination)服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用程序一致性和分布式协调技术服务的软件。
用途:统一配置管理、统一命名服务、分布式锁、集群管理等。
1.2 znode
ZooKeeper操作和维护一个小型的数据节点,这些节点被称为znode,以 key/value 形式存储数据,采用类似于文件系统的层级树状结构进行管理。
znode类型
一共有4种
- 持久节点:持久节点只能通过delete来进行删除。
- 临时节点:当创建该节点的客户端崩溃或者关闭了与Zookeeper的连接时,这个节点就会被删除。
- 持久/临时有序节点:一个有序节点被分配唯一一个单调递增的整数。当创建有序节点时,一个序号会被追加到路径之后。
znode属性
每一个znode都有一个版本号,使用版本号来阻止并行操作的不一致性。
1.3 监听与通知
为了替换客户端的轮询,Zookeeper选择了基于通知(notification) 的机制:
客户端向Zookeeper注册需要接收通知的znode,通过对znode设置监视点(watch)来接收通知。
监视点有两种类型:数据监视点和子节点监视点。创建、删除或设置一个znode节点的数据都会触发数据监视点。子节点监视点只有在znode子节点创建或删除时才触发。
羊群效应
如果有1000个客户端通过监听某个znode节点,那么当znode变化时会发送1000个通知,因而产生一个高峰的通知,可能带来性能影响。所以在使用Zookeeper时,避免在一个特定节点设置大量的监视点,理想情况下最多只设置一个。
Zookeeper实现分布式锁(独占锁/读写锁、公平锁/非公平锁)
通过创建同一个路径节点,使用路径的唯一性来确保只终一个对象能创建成功。
n个客户端竞争一个锁,如果znode存在了,则这些客户端会监听这个znode节点的删除事件。当znode删除时会引发羊群效应。
另一个不同的方法,让客户端创建有序临时节点,获取锁时,通过getChildren方法获取所有子节点,判断自己若是为最小序号的节点则获得锁,若不是只需要监听前一个节点,这样每个节点上设置的监视点只有最多一个客户端,形成链式监听。
与Redis分布式锁的不同:
- Redis通过key值唯一性,Zookeeper通过节点路径唯一性实现。
- Redis需要轮询竞争锁,Zookeeper可以通过监听获得锁。
- redis如果未设置实效时间会导致死锁,Zookeeper使用临时节点不会死锁
- Redis性能更高
- Zookeeper的集群一致性,Redis集群可能会不一致。
二、ACL权限控制
zookeeper 的 acl 通过 [scheme: id :permissions] 来构成权限列表。
- scheme:代表采用的某种权限机制,包括 world、auth、digest、ip、super 几种。
- id:代表允许访问的用户。
- permissions:权限组合字符串,由 cdrwa 组成,其中每个字母代表支持不同权限, 创建权限
create©、删除权限 delete(d)、读权限 read®、写权限 write(w)、管理权限admin(a)。
ACL命令行
getAcl命令:获取某个节点的 acl 权限信息。
setAcl命令:设置某个节点的 acl 权限信息。
addauth命令:输入认证授权信息,注册时输入明文密码,加密形式保存。
示例:
$ setAcl /runoob/child auth:user1:123456:cdrwa
$ addauth digest user1:123456
$ setAcl /runoob/child auth:user1:123456:cdrwa
$ getAcl /runoob/child
$ delete /runoob/child
ACL
SASL和Kerberos
三、Zookeeper的主从模式
3.1 CAP理论
-
一致性(Consistency):在分布式环境中,一致性是指数据在多个副本之间是否能够保持一致的特性,等同于所有节点访问同一份最新的数据副本。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态。
-
可用性(Availability):每次请求都能获取到正确的响应,但是不保证获取的数据为最新数据。
-
分区容错性(Partition tolerance):分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。
在这三个基本需求中,最多只能同时满足其中的两项,P 是必须的,因此只能在 CP 和 AP 中选择,zookeeper 保证的是 CP,对比 spring cloud 系统中的注册中心 eruka 实现的是 AP。
3.2 数据同步
Zookeeper服务器会在本地处理只读请求(exist、getData、getChildren),那些会改变Zookeeper状态的客户端请求(create、delete、setData)将会被妆发给leader,leader执行请求并形成更新,称之为事物。
- 服务器 ID(myid):服务器标识,编号越大在选举算法中权重越大。
- 事务 ID(zxid):值越大说明数据越新,权重越大。zxid为一个long型(64位)整数。分为两部分:时间戳(epoch)部分和计数器(counter)部分,每个部分32位。
- 逻辑时钟(epoch-logicalclock):同一轮投票过程中的逻辑时钟值是相同的,每投完一次值会增加
3.2.1 Zab协议:Zookeeper原子广播协议(Zookeeper Atomic Broadcast protocol)
ZAB 协议分为两部分:
- 消息广播
Zookeeper 使用单一的主进程 Leader 来接收和处理客户端所有事务请求,并采用 ZAB 协议的原子广播协议,将事务请求以 Proposal 提议广播到所有 Follower 节点,当集群中有过半的Follower 服务器进行正确的 ACK 反馈,那么Leader就会再次向所有的 Follower 服务器发送commit 消息,将此次提案进行提交。这个过程可以简称为 2pc 事务提交,整个流程可以参考下图,注意 Observer 节点只负责同步 Leader 数据,不参与 2PC 数据同步过程。
- 崩溃恢复
在正常情况消息广播情况下能运行良好,但是一旦 Leader 服务器出现崩溃,或者由于网络原理导致 Leader 服务器失去了与过半 Follower 的通信,那么就会进入崩溃恢复模式,需要选举出一个新的 Leader 服务器。在这个过程中可能会出现两种数据不一致性的隐患,需要 ZAB 协议的特性进行避免。
- Leader 服务器将消息 commit 发出后,立即崩溃
- Leader 服务器刚提出 proposal 后,立即崩溃
ZAB 协议的恢复模式使用了以下策略:
- 选举 zxid 最大的节点作为新的 leader
- 新 leader 将事务日志中尚未提交的消息进行处理
3.3 lead选举
zookeeper 的 leader 选举存在两个阶段,一个是服务器启动时 leader 选举,另一个是运行过程中 leader 服务器宕机。
选举状态:
- LOOKING: 竞选状态
- FOLLOWING: 随从状态,同步 leader 状态,参与投票
- OBSERVING: 观察状态,同步 leader 状态,不参与投票
- LEADING: 领导者状态
每个节点启动的时候都 LOOKING 观望状态,接下来就开始进行选举主流程。这里选取三台机器组成的集群为例。第一台服务器 server1启动时,无法进行 leader 选举,当第二台服务器 server2 启动时,两台机器可以相互通信,进入 leader 选举过程。
-
每台 server 发出一个投票,由于是初始情况,server1 和 server2 都将自己作为 leader 服务器进行投票,每次投票包含所推举的服务器myid、zxid、epoch,使用(myid,zxid)表示,此时 server1 投票为(1,0),server2 投票为(2,0),然后将各自投票发送给集群中其他机器。
-
接收来自各个服务器的投票。集群中的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票(epoch)、是否来自 LOOKING 状态的服务器。
-
分别处理投票。针对每一次投票,服务器都需要将其他服务器的投票和自己的投票进行对比,对比规则如下:
a. 检查 zxid,zxid 比较大的服务器优先作为 leader
b. 如果 zxid 相同,那么就比较 myid,myid 较大的服务器作为 leader 服务器 -
统计投票。每次投票后,服务器统计投票信息,判断是都有过半机器接收到相同的投票信息。server1、server2 都统计出集群中有两台机器接受了(2,0)的投票信息,此时已经选出了 server2 为 leader 节点。
-
改变服务器状态。一旦确定了 leader,每个服务器响应更新自己的状态,如果是 follower,那么就变更为 FOLLOWING,如果是 Leader,变更为 LEADING。此时 server3继续启动,直接加入变更自己为 FOLLOWING。
2、运行过程中的 leader 选举
当集群中 leader 服务器出现宕机或者不可用情况时,整个集群无法对外提供服务,进入新一轮的 leader 选举。
- 变更状态。leader 挂后,其他非 Oberver服务器将自身服务器状态变更为 LOOKING。
- 每个 server 发出一个投票。在运行期间,每个服务器上 zxid 可能不同。
- 处理投票。规则同启动过程。
- 统计投票。与启动过程相同。
- 改变服务器状态。与启动过程相同。
脑裂
两个集合的服务器分别独自运行,形成了两个集群。这种情况将导致整个系统状态的不一致性。
原因:一般是网络原因导致一部分节点认为leader下线,进入崩溃恢复模式重新选举leader。
解决方案:采用过半原则。
四、Curator:Zookeeper API的高级封装库
Curator作为Zookeeper的一个高层次封装库,为开发人员封装了了Zookeeper的一组开发库,核心目标就是为你管理Zookeeper的相关操作。Curator实现了锁、屏障、缓存等接口,还实现了流畅式(fluent)的开发风格接口。
参考书籍:《Zookeeper分布式过程协同技术详解》
参考博客: Zookeeper 教程