大纲
1.zk的使用场景
2.zk主要会被用于那些系统
3.为什么在分布式系统架构中需要使用zk集群
4.zk分布式系统具有哪些特点
5.zk集群机器的三种角色
6.客户端与zk之间的长连接和会话
7.zk的数据模型znode和节点类型
8.zk最核心的Watcher监听回调机制
9.ZAB协议的主从同步机制和崩溃恢复机制
10.ZAB协议流程之集群启动-数据同步-崩溃恢复
11.采用2PC两阶段提交思想的ZAB消息广播流程
12.zk到底是强一致性还是最终一致性
13.ZAB协议下两种可能存在的数据不一致问题
14.崩溃恢复时新Leader和Follower的数据同步
15.ZAB协议会如何处理需要丢弃的消息的
16.zk的Observer节点的作用
17.zk适合小集群部署 + 读多写少场景的原因
18.zk特性的总结
12.zk到底是强一致性还是最终一致性
(1)强一致性
(2)最终一致性
(3)顺序一致性
(1)强一致性
只要写入一条数据,无论从zk哪台机器上都可以马上读取到这条数据。强一致性的写入操作卡住时,直到Leader和全部Follower都进行了Commit,才能让写入操作返回,才能认为写入成功。所以只要写入成功,无论从哪个zk机器查询都能查到,这就是强一致性。很明显,ZAB协议机制下的zk不是强一致性。
(2)最终一致性
写入一条数据,方法返回写入成功。此时马上去其他zk机器上查有可能是查不到的,可能会出现短暂时间的数据不一致。但是过一会儿,一定会让其他机器同步到这条数据,最终一定可以查到写入的数据。
在ZAB协议中:当过半Follower对Proposal提议返回ACK时,Leader就会发送Commit消息给所有Follower。只要Follower或者Leader进行了Commit,那么这个数据就会被客户端读取到。
那么就有可能出现:有的Follower已经Commit了,但有的Follower还没有Commit。某个客户端连接到某个Follower时可以读取到刚刚Commit的数据,但有的客户端连接到另一个Follower时却没法读取到还没有Commit的数据。
所以zk不是强一致性的。Leader不会保证一条数据被全部Follower都Commit后,才让客户端读取到。在Commit的过程中,可能会出现在不同的Follower上读取到的数据是不一致的情况。但完成Commit后,最终一定会让客户端读取到一致的数据。
(3)顺序一致性
zk官方给自己的定义是顺序一致性,当然也属于最终一致性。但zk的顺序一致性比最终一致性更好一点,因为Leader会保证所有的Proposal提议同步到Follower时是按顺序进行同步的。
如果要求zk是强一致性,那么可以手动调用zk的sync()方法。
13.ZAB协议下两种可能存在的数据不一致问题
(1)Leader还没发送Commit消息就崩溃
(2)Leader还没广播Proposal提议就崩溃
(1)Leader还没发送Commit消息就崩溃
Leader收到了过半的Follower的ACK,接着Leader自己Commit了,但还没来得及发送Commit消息给所有Follower自己却宕机了。此时相当于Leader的数据跟所有Follower是不一致的,所以得保证全部Follower最终都完成Commit。
因此Leader崩溃后,就会选举一个拥有最大ZXID的Follower作为Leader,这个Leader会检查事务日志。如果发现自己事务日志里有一个还没进行提交的Proposal提议,那么旧说明旧Leader没来得及发送Commit消息就崩溃了。此时它作为新Leader会为这个Proposal提议向Follower发送Commit消息,从而保证旧Leader提交的事务最终可以被提交到所有Follower中。
同理,如果Leader收到过半Follower的ACK响应后,在发送Commit消息的过程中,出现Leader宕机或者Leader和Follower的网络问题。那么Follower只要与它能找到的Leader(新选举的ZXID最大的Follower或者原来的Leader)进行数据同步,就可以保证新数据在该Follower中完成Commit。
(2)Leader还没广播Proposal提议就崩溃
Leader没来得及发送Proposal提议给所有Follower的时候就宕机了,此时Leader上的这个请求应该是要被丢弃的。
对于这种情况:如果旧Leader日志里有一个事务Proposal提议,它重启后跟新Leader同步,发现这个事务Proposal提议其实是不应该存在的,那么就会直接丢弃。
14.崩溃恢复时新Leader和Follower的数据同步
(1)先发送Proposal提议再发送Commit消息
(2)Commit操作会把数据写入到内存中的znode
(3)通过已同步Follower列表判断数据可用
(4)选择ZXID最大的Follower作为新Leader的原因
(1)先发送Proposal提议再发送Commit消息
新选举出一个Leader后,其他Follower就会跟它进行数据同步。Leader会给每个Follower准备一个队列,然后把所有的Proposal提议都发送给Follower,并紧接着会发送Commit消息给那个Follower。
(2)Commit操作会把数据写入到内存中的znode
Commit操作就是把这条数据加入内存中的znode树形数据结构里,这样客户端就能访问到该数据,当然也会去通知监听这个znode的客户端。而收到Proposal提议时,会将数据以事务日志的形式顺序写入到磁盘。
(3)通过已同步Follower列表判断数据可用
如果一个Follower跟新Leader完成数据同步后,就会加入新Leader的已同步Follower列表中。当这个已同步Follower列表中有过半的Follower时,那么新Leader就可以对外继续提供服务了。
(4)选择ZXID最大的Follower作为新Leader的原因
在选举新Leader时,会挑选拥有最大ZXID的那个Follower作为新Leader。比如5个机器,1Leader + 4个Follower。1个Leader把Proposal发送给4个Follower,其中3个Follower(过半)都收到了Proposal返回ACK了,但是第四个Follower没收到Proposal。此时Leader执行Commit后挂了,Commit消息没法发送给其他Follower。这时剩余4个Follower,只要其中3个投票某一个当Leader,那它就可成为Leader。假设收到Proposal的那3个Follower都投票给没收到Proposal的Follower,那么这条数据就会永久丢失,所以需要选择一个拥有最大ZXID的Follower作为新Leader。
15.ZAB协议会如何处理需要丢弃的消息的
(1)ZAB协议根据epoch处理需要丢弃的消息
(2)ZAB协议的简单总结
(1)ZAB协议根据epoch处理需要丢弃的消息
每一个事务的ZXID是64位的,高32位是Leader的epoch(表示选举轮次),低32位是自增长的序列号。
如果一个Leader刚把一个Proposal提议写入本地磁盘日志,还没来得及广播Proposal提议给全部Follower就崩溃了。那么当新Leader选举出来后,事务的epoch会自增长一位。然后当旧Leader重启后重新加入集群成为Follower时,会发现自己比新Leader多出一条Proposal提议,但该Proposal提议的epoch比新Leader的epoch低,所以会丢弃这条数据。
(2)ZAB协议的简单总结
一.启动时:过半机器选举Leader + 数据同步
二.对外提供服务时:2PC + 过半写机制,顺序一致性(最终一致性)
三.崩溃恢复时:重新选举Leader + 针对两种数据不一致的情况进行处理
16.zk的Observer节点的作用
(1)对于写请求
(2)对于读请求
Observer节点不参与Leader选举,不参与广播提议时过半Follower进行ACK的环节,只处理客户端读请求和同步数据。
(1)对于写请求
由于Leader在进行数据同步时,Observer不会参与到过半写机制里。所以zk集群无论多少台机器,只能是由一个Leader进行写。Leader单机写入最多每秒上万QPS,这是没法扩展的。
因此zk是适合写少的场景。Redis的写QPS可以达10万,zk的写QPS才上万。虽然Redis和zk都是内存级的,而且对写请求的处理都是单线程处理的。但是由于Redis没有过半写机制,所以它的写性能更高。
(2)对于读请求
Follower通常会有2个或4个,这样处理读请求时就可以达到每秒几万QPS。如果引入更多的Follower,那么在过半写机制中会有更多的Follower参与。这会影响Leader写的效率,因此就有了Observer。
所以为了进一步提升zk集群对读请求的处理能力,可以引入Observer节点。由于它只同步数据提供读服务,所以可以无限扩展节点而不影响写效率。
17.zk适合小集群部署 + 读多写少场景的原因
(1)zk集群通常采用三五台机器小集群部署
(2)zk集群适合读多写少的场景
(1)zk集群通常采用三五台机器小集群部署
假设有1个Leader + 20个Follower,总共21台机器。此时由于Follower要参与到ZAB的写请求的过半ACK,所以一个写请求要等至少10个Follower返回ACK才能发送Commit消息。Leader发送Commit消息后才能告诉客户端写请求成功,所以性能会比较差。所以ZAB协议决定了zk集群通常采用1个Leader + 2个Follower的小集群。
(2)zk集群适合读多写少的场景
zk集群的写请求的处理能力是无法扩展的。如果读请求量大,可以加Observer机器。因此zk只适合读多写少的场景,所以zk主要是用来处理分布式系统的一些协调工作。
18.zk特性的总结
(1)集群模式部署
(2)主从架构
(3)内存数据模型
(4)顺序一致性
(5)高性能
(6)高可用
(7)高并发
(1)集群模式部署
一般奇数节点部署,不能超过一半的机器挂掉。因为5台机器可以挂2台,6台机器也最多只能挂2台。所以5台和6台效果一致,所以奇数节点可以减少机器开销。而且zk集群是小集群部署,适用于读多写少的场景。
(2)主从架构
Leader、Follower、Observer。
(3)内存数据模型
znode,多种节点类型,支持Watcher机制实现监听回调通知。
(4)顺序一致性
消息按顺序同步,但是最终才会一致,不是强一致。ZXID的高32位epoch,低32位是自增长的序列号。
(5)高性能
2PC中的过半写机制,纯内存的数据结构,znode。ZAB协议:2PC、过半ACK + 写事务日志,Commit + 写内存数据。
(6)高可用
Follower宕机没影响,Leader宕机有数据不一致问题。新选举的Leader会自动处理,正常运行。但是在恢复模式期间,可能有一小段时间是没法写入zk的。客户端跟zk进行TCP长连接,通过心跳机制维持Session。
(7)高并发
单机Leader写,Observer节点可以线性扩展读QPS。