zookeeper是一个开源的分布式协调服务,它能为分布式的应用提供高效且可靠的分布式的协调服务,分布式应用可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协 调/通知、集群管理、Master 选举、配置维护,名字服务、分布式同步、分布式锁和分布式队列 等功能(这个是官方对于zookeeper具体的定义)
网上关于zookeeper的原理的文档很多,而我在去理解zookeeper原理的时候,主要是从下面几个主要的问题去探索zookeeper
在zookeeeper的集群中,各个节点共有以下三种角色
三种角色:
leader:事务请求的唯一调度者和处理者,保证集群事务处理的顺序性。
follower:处理客户端非事务性请求,转发事务请求给Leader服务器(事务请求都由Leader处理) ,参与Leader选举投票
observer:Observer充当观察者角色,观察zk集群的最新状态变化并将这些状态同步过来,对于非事务请求可以进行独立的处理,对于事务请求,则会转发给Leader服务器进行处理,Observer不会参与任何形式的投票,包括事务请求Proposal的投票和Leader选举的投票。
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步,实现这个机制的协议叫做Zab协议(ZooKeeper Atomic Broadcast protocol),Zab协议有两种模式,它们分别是恢复模式(Recovery选主)和广播模式(Broadcast同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
server.A=B:C:D中的A是一个数字,表示这个是第几号服务器,B是这个服务器的IP地址,C第一个端口用来集群成员的信息交换,表示这个服务器与集群中的leader服务器交换信息的端口,D是在leader挂掉时专门用来进行选举leader所用的端口。
zookeeper在选举leader的时候,具有这样的一个策略:只有超过半数以上节点的投票,才能选出leader,因此,
当节点个数为2的时候,默认两个节点都为可用的时候,zookeeper集群才可用,
当节点个数为3的时候,默认需要两个以上的节点为可用的时候,zookeeper集群才可用,因此节点为3的时候,zookeeper的集群节点不可用的容忍度为1
当节点个数为4的时候,默认需要三个以上的节点为可用的时候,zookeeper集群才可用,因此节点为4的时候,zookeeper的结群节点不可用的容忍度为1,
因此,我们会发现,当节点的个数为2n-1和2n的时候,zookeeper的集群节点不可用的容忍度都是n-1,本着节省性能的原则,所以zookeeper集群的节点的个数最好为奇数
当集群中的节点监听不到leader节点的心跳的时候,就会认为leader节点出了问题,此时集群将分裂为不同的小集群, 这些小集群会各自选举出自己的leader节点,当原始的leader节点出现恢复的时候, 导致原有的集群中出现多个leader节点.,而zookeeper的leader节点是进行事务请求的统一调度,出现多个leader节点的时候,就会导致数据的不一致,
为什么会出现脑裂的现场
集群中网络通信不好, 导致心跳监测超时 —— follower认为leader节点由于某种原因挂掉了, 可其实leader节点并未真正挂掉 —— 这就是假死现象.
leader节点假死后, ZooKeeper通知所有follower节点进行选举 ==> 某个follower节点升级为新的leader. —— 此时集群中存在2个leader节点.
此时ZooKeeper需要将新leader节点的信息通知给所有的follower节点, 还要通知到所有的client(比如通过: 搭建的Solr集群中的Solr实例就是一个client), 而这个过程由于网络等环境的影响, 消息到达就会存在快慢之分.
如果部分client获得了新leader节点的信息, 而部分没有获得, 而此时client向ZooKeeper发起读写请求, ZooKeeper内部的不一致就会导致: 部分client连接到了新的leader节点上, 而部分client连接到了旧的leader节点上
zookeeper是如何解决这种可能出现的脑裂现场?
zookeeper默认采取Quorums(法定人数)的方式: 只有获得超过半数节点的投票, 才能选举出leader.
zookeeper的具体的实现
假设: leader发生了假死, followers选举出了一个新的leader.
当旧的leader复活并认为自己仍然是leader, 它向其他followers发出写请求时, 会被拒绝.
—— 因为ZooKeeper维护了一个叫epoch的变量, 每当新leader产生时, epoch都会递增, followers如果确认了新的leader存在, 同时也会知道其epoch的值 —— 它们会拒绝
如何你看了上面的zookeeper的几个主要的问题之后,其实,在你的脑海里,你会对于zookeeper有一个大致的了解,
1,zookeeper的集群中,会通过某一个算法去选举一个leader角色,没有选举到的会变成follower或者是observer角色,只是follower会处理客户端非事务性请求,转发事务请求给Leader服务器(事务请求都由Leader处理) ,参与Leader选举投票,而observer只会充当观察者的身份,只是观察集群的状态,不会参与任何形式的投票,包括事务请求Proposal的投票和Leader选举的投票。
2,在zookeeper集群中,出现某种情况下,导致的leader节点出现问题时,zookeeper集群的zab机制会变成恢复模式,进行leader节点的重新选举,选举的策略是,只有超过半数的节点进行投票的时候,才能进行选举。
理解这个的时候,你会有这么一个很大的疑问,zookeeper是如何进行选leader的呢,怎么选的,选的原则是什么,
一切的不理解paxos算法的时候,你是无法掌握这个zookeeper的真滴的
在去理解zookeeper的选举算法的时候,你首先需要去了解paxos这个牛逼的算法
讲道理,这个算法看的很烧脑子,有点晕,在网上看了很多关于这个算法的讲解,感觉大部分都是说了很多的废话,并没有去深入的讲解它,但是,有这么一篇文章,讲的很不错【自认为】,贴出地址
https://www.jianshu.com/p/d9d067a8a086
但是,这么一个牛逼的讲解,下面的评论说是抄的
这个明显和我半毛钱关系都没有,当我本着真诚的相信这个哥们说的话的时候,打开了他发的url,发现里面的图片竟然显示不出来,,,,那,,我就只能看这个人的了!
其实,有一个人一直在下面评论有一个文章中的疑问不理解,我也是回复了这个问题的个人看法(仅仅是个人)
如果你理解了这个paxos算法之后,你在看这个文档的时候,相信你会对zookeeper关于怎么选leader有一个进一步的理解的
https://blog.csdn.net/wuliu_forever/article/details/52053557 2.1部分
如果你看了上面,并且通过你的努力,对于zookeeper的原理有了进一步自认为不错的理解【我就是这样,哈哈】,下面,你可以对于zookeeper的使用,以及apache提供的zookeeper的源码做进一步的了解
阅读源码有时候是为了提升自己,也可以为了装逼
下面是贴出了一个github上对于源码解读的项目地址(似乎这个哥们的代码是抄官方文档的)
路径地址 | 阅读说明 |
---|---|
https://github.com/llohellohe/zookeeper.git | 参考README.md阅读,里面有关于zookeeper中重要的ZooKeeper,ClientCnxn,ClientCnxnSocketNIO 的解析 |