为何会有ZooKeeper 服务器
咱们知道要写一个分布式应用是很是困难的,主要缘由就是局部故障。一个消息经过网络在两个节点之间传递时,网络若是发生故障,发送方并不知道接收方是否接收到了这个消息。有多是收到消息之后发生了网络故障,也有多是没有收到消息,又或者可能接收方的进程死了。发送方惟一的确认方法就是再次链接发送消息,并向他进行询问。这就是局部故障:根本不知道操做是否失败。所以,大部分分布式应用须要一个主控、协调控制器来管理物理分布的子进程。因此大部分应用须要开发私有的协调程序,协调程序的反复编写浪费时间,这个时候就须要一个通用的、伸缩性好的协调器。就是由于这样的场景,ZooKeeper应运而生,ZooKeeper的设计目的,就是为了减轻分布式应用程序所承担的协调任务。 网络
ZooKeeper经常使用的应用场景 架构
01 / 分布式协调并发
分布式协调简单说就是有人对ZooKeeper中的数据作了监听,若是修改了ZooKeeper中被监听的数据,ZooKeeper反过来会告诉给发起监听的人数据的变动。好比在Kafka的设计中,Kafka的一个节点在ZooKeeper中建立了一个数据,Kafka的策略是谁建立了这个数据谁就是Kafka集群的主节点,其他的节点都会去监听这个数据。若是主节点宕机了,这ZooKeeper对应的数据就会发生变动,既而监听这个数据的其他节点就会感知到主节点宕机了,而后从新进行选举。分布式
02 / 元数据管理ide
不少分布式的程序须要集中式的管理本身的元数据,这个时候ZooKeeper就是一个很好的选择。好比Kafka,Storm等分布式的工具就会把集群里核心的元数据存放在ZooKeeper中。高并发
03 / 高可用工具
不少分布式的项目都是主从式的架构,正常状况下集群里有一个是主节点,其他的都是从节点。可是若是只有一个主节点的话,程序就会有单点故障问题,那么这个时候就须要部署多个主节点实现高可用了,利用ZooKeeper从多个主节点中选出一个做为master,其他的做为StandBy。好比鼎鼎大名的HDFS就是靠ZooKeeper实现的高可用。性能
04 / 分布式锁学习
在企业里面不少的项目须要分布式锁,咱们可使用ZooKeeper搞分布式锁,不过这儿你们要注意一点,ZooKeeper确实是能够搞分布式锁的,可是ZooKeeper不支持过高的并发,也就是说若是是高并发的状况下,分布式锁用ZooKeeper可能也不太适合,若是在高并发的状况下建议你们使用Redis去搞分布式锁,可是并发不过高的状况下用ZooKeeper搞分布式锁是比较方便的,也有不少人确实是这么使用的。
ZooKeeper核心原理
01 / ZooKeeper集群架构
在ZooKeeper集群当中,集群中的服务器角色分为leader和learner,learner又分为observer和follower,具体功能以下:
0x0一、leader(领导者)
为客户端提供读和写的功能,负责投票的发起和决议,集群里面只有leader才能接受写的服务。
0x0二、follower(跟随者)
为客户端提供读服务,若是是写的服务则转发给leader。在选举过程当中进行投票。
0x0三、observer(观察者)
为客户端提供读服务,若是是写服务就转发个leader。不参与leader的选举投票。也不参与写的过半原则机制。在不影响写的前提下,提升集群读的性能,此角色于zookeeper3.3系列新增的角色。
0x0四、client(客户端)
链接zookeeper集群的使用者,请求的发起者,独立于zookeeper集群的角色。
02 / ZooKeeper读写机制
在ZooKeeper的选举中,若是过半的节点都选一个节点为leader的话,那么这个节点就会是leader节点,也就是由于这个缘由,ZooKeeper集群,只要有过半的节点是存活的,那么这个ZooKeeper就能够正常的提供服务。好比有5个ZooKeeper节点,其中有2个节点宕机了,这个时候还有3个节点存活,存活个数超过半数,此时集群仍是正常提供服务,因此ZooKeeper集群本生是没有高可用问题的。又由于存活的判断依据是超过半数,因此咱们通常搭建ZooKeeper集群的时候,都使用奇数台,这样会比较节约机器,好比咱们安装一个6台的ZooKeeper集群,若是宕机了3台就会致使集群不可用,由于这个时候存活的节点数没有超过半数了,因此6台和5台的效果是同样的,咱们用5台比较合适。
对应一个ZooKeeper集群,咱们可能有多个客户端,客户端能任意链接其中一台ZooKeeper节点,可是全部的客户端都只能往leader节点上面去写数据,全部的客户端能从全部的节点上面读取数据。若是有客户端链接的是follower节点,而后往follower上发送了写数据的请求,这个时候follower就会把这个写请求转发给leader节点处理。leader接受到写请求就会往其余节点(包括本身)同步数据,若是过半的节点接受到消息后发送回来ack消息,那么leader节点就对这条消息进行commit,commit后该消息就对用户可见了。由于须要过半的节点发送ack后,leader才对消息进行commit,这个时候会有一个问题,若是集群越大,那么等待过半节点发送回来ack消息这个过程就须要越久,也就是说节点越多虽然会增长集群的读性能,可是会影响到集群的写性能,因此咱们通常建议ZooKeeper的集群规模在3到5个节点左右。为了解决这个问题,后来的ZooKeeper中增长了一个observer 的角色,这个节点不参与投票,只是负责同步数据。好比咱们leader写数据须要过半的节点发送ack响应,这个observer节点是不参与过半的数量统计的。它只是负责从leader同步数据,而后提供给客户端读取,因此引入这个角色目的就是为了增长集群读的性能,而后不影响集群的写性能。用户搭建集群的时候能够本身设置该角色。
03 / Zookeeper 特色
0x0一、一致性
client客户端不管链接到集群中的哪一个节点,读到的数据都是同样的
0x0二、实时性
ZooKeeper保证客户端在必定的时间间隔内得到结果,包括成功和失败,可是因为网络延迟缘由,ZooKeeper不能保证两台客户端同时获得刚更新的消息。若是都须要最新的消息须要调用sync()接口。
0x0三、原子性
leader在同步数据的时候,同步过程保证事务性,要么都成功,要么都失败。
0x0四、顺序性
一台服务器上若是消息a在消息b前发布,那么全部的server上的消息a都是在消息b前发布的。
04 / Zookeeper数据一致性保证
刚刚咱们看到了ZooKeeper有多个特色,可是我相信多个特色中,你们最好奇都就是Zookeeper是如何保证数据一致性的。ZooKeeper保证数据一致性用的是ZAB协议。经过这个协议来进行ZooKeeper集群间的数据同步,保证数据的一致性。
0x0一、两阶段提交+过半写机制
ZooKeeper写数据的机制是客户端把写请求发送到leader节点上(若是发送的是follower节点,follower节点会把写请求转发到leader节点),leader节点会把数据经过proposal请求发送到全部节点(包括本身),全部到节点接受到数据之后都会写到本身到本地磁盘上面,写好了之后会发送一个ack请求给leader,leader只要接受到过半的节点发送ack响应回来,就会发送commit消息给各个节点,各个节点就会把消息放入到内存中(放内存是为了保证高性能),该消息就会用户可见了。那么这个时候,若是ZooKeeper要想保证数据一致性,就须要考虑以下两个状况,状况一:leader执行commit了,还没来得及给follower发送commit的时候,leader宕机了,这个时候如何保证消息一致性?状况二:客户端把消息写到leader了,可是leader还没发送proposal消息给其余节点,这个时候leader宕机了,leader宕机后恢复的时候此消息又该如何处理?
0x0二、ZAB的崩溃恢复机制
针对状况一,当leader宕机之后,ZooKeeper会选举出来新的leader,新的leader启动之后要到磁盘上面去检查是否存在没有commit的消息,若是存在,就继续检查看其余follower有没有对这条消息进行了commit,若是有过半节点对这条消息进行了ack,可是没有commit,那么新对leader要完成commit的操做。
0x0三、ZAB恢复中删除数据机制
针对状况二,客户端把消息写到leader了,可是leader还没发送portal消息给其余节点,这个时候leader宕机了,这个时候对于用户来讲,这条消息是写失败的。假设过了一段时间之后leader节点又恢复了,不过这个时候角色就变为了follower了,它在检查本身磁盘的时候会发现本身有一条消息没有进行commit,此时就会检测消息的编号,消息是有编号的,由高32位和低32位组成,高32位是用来体现是否发生过leader切换的,低32位就是展现消息的顺序的。这个时候当前的节点就会根据高32位知道目前leader已经切换过了,因此就把当前的消息删除,而后重新的leader同步数据,这样保证了数据一致性。
最后
各位同窗,ZooKeeper是咱们学习架构的过程中,很是很是重要的一个知识点,咱们今天只是从其中一些角度去分析的ZooKeeper,咱们后面会有不少文章从不一样角度深刻全面的剖析ZooKeeper,帮助你们掌握ZooKeeper,欢迎你们持续关注。
领取更多免费技术资料及视频