zookeeper

1、什么是zookeeper?

zk是一个开源的分布式协调服务,是集群的管理者,可以监视集群中各个节点状态,根据节点提交的反馈进行下一步合理的操作;最终将简单易用的接口和性能高效,功能稳定的系统提供给用户。

应用场景

分布式的应用程序可以基于zk实现诸如 

数据发布/订阅:配置中心

负载均衡:通过服务者列表(服务端注册到zk上,客户端访问zk就可以获得服务端列表)

命名服务:提供服务名到服务地址的映射

分布式协调/通知:通过watch机制和临时节点,获取各节点的任务进度,或者通过修改节点发送通知

集群管理:是否有机器退出和加入

master选举

分布式锁

分布式队列

2、zookeeper提供了什么?

zk提供了文件系统和通知机制两大块。

文件系统: zk提供了一个多层级的节点命名空间(节点为znode),类似于Windows中的文件系统,但是有区别的是,zk中的节点中都可以存储一定大小的数据,而windows中目录不可以存数据,只有文件可以存数据。

zk为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,因此zk每个节点存储的数据大小是又上限的(1M)。

3、什么是ZAB协议?

zookeeper atomic broadcast ,zk原子广播协议;zk作为非常重要的分布式协调组件,通常需要集群部署,一般为一主多从的形式,ZAB解决了zk中的崩溃恢复和主从数据同步的问题。

当整个zk集群

刚刚启动、

或者leader服务器宕机/重启、

或者网络故障灯导致不存在过半的服务器与leader服务器保持正常通行状态时,

所有的服务器(zk进程)进入崩溃恢复模式:

首先选举产生新的leader服务器,

然后集群中follower服务器开始与新的leader服务器进行数据同步,

当集群中超过半数的及其与该leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,

然后leader服务器开始接受客户端的事务请求生成事务提案来进行事务的处理。

ZAB定义的四种节点状态

looking:选择状态

following:从节点的状态

leading:主节点的状态

observing:观察者节点所处的状态

4、zk集群中的三种角色:

leader:处理集群中的所有事务请求,集群中只有一个leader

follower:只能处理读请求,参与leader的选举

observer:只能处理读请求,提升集群的读性能,但是不参与leader的选举

5、zk集群启动时的leader选举过程(假设集群中有三台服务器)

首先明确选票格式:(myid, zxid )   

myid(集群设置时给服务器的id) 和 zxid(事务id,服务器在经历了数据的增删改后,就会+1,其实描述了执行事务的次数)

选举过程

  1. 首先启动服务器1,服务器1生成一张自己的选票投给自己(1,0),但是因为只启动了1台服务器,自己活得的选票没有过半,集群无法启动
  2. 启动服务器2,服务器2也生成一张投给自己的选票(2,0),然后服务器1和服务器2交换选票信息,服务器会比较两张选票:
    1. 首先比较 zxid,谁大投给谁,此时事务id都是0,相同
    2. 然后比较myid, 谁大头给谁,2大于1,因此服务器1和2都将选票投给2;
  3. 此时,服务器2获得了超过半数的选票,选举结束,服务器2成为leader节点
  4. 后续的服务器启动时,发现集群已经选举出了leader,因此把自己作为follower;

因此三台服务器逐个启动时,服务器2必然是leader

6、崩溃恢复时的leader选举过程

首先明确如果leader挂了,follower是怎么知道的

leader和follower之间会建立一个socket连接,leader会给follower发送一个ping命令,这个是一个空的数据,follower会周期性的去socket读这个ping命令,如果leader宕机,那么socket就会断开,follower去读socket的时候就会报错,然后follower就会从following变成looking状态,开始进行选举;

选举的过程还是参照上述选举过程,先根据 zxid大小,然后根据myid大小进行比较,大的值为leader;

7、zk中的主从数据同步的原理(整个过程是个两阶段提交)

  1. 首先,如果客户端连接的是主节点,客户端向主节点写数据
  2. 主节点先把数据写到自己的数据文件中,并给自己返回一个ack
  3. 主节点把数据发送给所有的从节点(一个广播的过程)
  4. 从节点将数据写到本地数据文件中
  5. 从节点返回ack给主节点进行确认
  6. 主节点收到半数以上的ack后,向从节点发送commit,当然这个commit自己也会执行(数据文件中的内容写到内存中)-----为什么是半数以上?提高集群的写性能;
  7. 从节点收到commit后把数据文件中的数据写到内存中

8、此时,回过头来看 observer观察者节点的作用是什么呢?

一般来说,集群中服务器的数量越多,性能越高,但是刚刚介绍了zk中数据的主从同步原理,当发生写操作的时候,leader节点要接收超过半数以上的从节点的ack确认,才可以commit,因此,如果集群中服务器的数量越多,要接收超半数的ack确认也越多,因此,虽然增加服务器可以大大提升读操作,但是却会影响写操作的效率。

为了解决这个问题,引入了observer观察者节点的概念,observer既不参与leader的选举,也不需要在写操作是给leader发送ack确认信息。

观察源码,observer观察者节点更新内容的时机发生在commit执行之后,至于是否需要持久化日志,是可以配置的

9、zookeeper是怎么保证事务的顺序一致性的?

zk采用了全局递增的事务id来进行标识,所有的proposal(提议)都在被提出的时候加了zxid,zxid是一个64位的数字,高32位是epoch,标识leader周期,如果有新的leader选举出来,epoch就会自增;低32位用来递增计数。zxid就保证了执行事务的顺序一致性。

10、为什么zk集群建议配置奇数台机器呢?

从可用性的角度考虑的,比如集群有5台机器,那么保持正常工作允许至多2台机器出现故障,而如果有6台机器时,保持正常工作也至多只能2台出现故障。当然,多出一台机器,对于可读性能提升是有帮助的,要结合实际情况分析。

11、zookeeper会出现脑裂现象吗?

不会!(因为leader的选举有一个过半机制) 我们讨论以下两种场景:

1、一个集群的机器分布在两个机房AB,每个机房的机器数量相同

正常情况下,zk集群会选举出一个leader进行工作(假设leader在A机房),如果两个机房之间的网络断开,但是机房内的网络是通的。刚刚说过,在主从同步机制中,leader会发送心跳给follower,因此,A机房内的ack都可以收到,但是B机房的收不到 ,A机房未超过半数,因此leader退位,重新选举,但是由于AB机房的机器一样,哪个机房都无法选举出新的leader,因此集群处于不可用状态

2、一个集群的机器分布在两个机房AB,每个机房的机器数量不同

也是假设leader在A机房,且A机房数量大于B机房,两个机房网络断开,A机房内网络互通,且机器数过半,因此leader不受影响,A机房机器正常工作, B机房内网络互通,但是因为机器数量不够,无法选举出新leader,因此B机房机器处于不可用状态。

因此,zookeeper的过半选举机制不会发生脑裂现象。

12、分布式系统中为什么会有master?

分布式环境中,有些业务逻辑只需要集群中的一台机器进行执行,其他的机器就可以共享这个结果,这样一来可以大大减少重复计算,提高性能,二来,避免脑裂,即多台机器同时操作一个数据,不知道以哪个结果为准。

13、zookeeper中的BIO和NIO应用

  • NIO:
    • 用于被客户端连接的2181端口,使用的是NIO和客户端建立连接
    • 客户端开启watch是,也使用NIO,等到zk服务器回调
  • BIO:
    • 集群选举时,多个节点之间的投票通信端口,使用BIO通信。

14、zookeeper的持久化机制

因为zk是运行在内存中,因此为了数据不丢失,需要进行持久化,zk中提供了两种持久化机制:事务日志和数据快照;

事务日志

zk把执行的命令以日志的形式保存在dataLogDir指定的路径中的二进制文件(如果没有指定dataLogDir,则按照dataDir指定的路径)

数据快照

zk会在一定的时间间隔内做一次内存数据的快照,吧该时刻的内存数据保存在快照中

zk通过两种形式的持久化,在恢复时先恢复快照文件的中的数据导内存中,在利用日志文件中的数据做增量恢复,这样恢复的速度更快。

15、zk的乐观锁删除

zk节点的删除,除了普通的删除外,还给了一种乐观锁删除机制,及删除的时候增加一个版本识别

delete -v [version]  /testNode

只有版本号匹配的时候,才可以删除成功。

16、zk如何实现分布式锁

核心思想:当一个客户端想要获取锁,则创建节点,使用完锁的时候,删除节点读锁共享,写锁排他

读锁:大家都可以读,想要加读锁的前提是:之前的锁没有写锁。

如何上读锁?

  1. 指定路径下创建一个临时顺序节点,节点的数据为read,表示为读锁
  2. 获取当前zk中比自己序号小的所有节点
  3. 判断最小节点是否为读锁
    1. 如果不是读锁,则上锁失败,给最小节点设置监听,阻塞等待,zk的watch机制会在当前最小节点变化时通知当前节点,然后继续执行步骤2 
    2. 如果是读锁的话,则上锁成功

写锁:只有得到写锁,才能进行写操作;想要上写锁的前提是之前没有任何锁。

如何上写锁?

  1. 指定路径下创建一个临时序号节点,节点的数据为write,标识写锁
  2. 获取zk中所有的子节点
  3. 判断自己是否是最小节点(写锁前不能有锁)
    1. 如果是,则上锁成功
    2. 如果不是,说明前面还有锁,则上锁失败,监听最小的节点,如果最小节点有变化,则回到第二步的流程

上述的上锁方式中,写的是监听最小的节点,一旦这个节点有变化,就会触发其他节点的监听事件,如果ZK等待锁的节点过多的时候,对zk的压力是十分巨大的,称为羊群效应(惊群效应),解决这个的办法就是调整为链式监听:即当前节点只监听序号比自己小的上一个节点,如图,node1发送变化时,只有node2 触发监听事件,而node3和node4是不会感知的。

17、zk实现分布式锁的时候,为什么创建的是临时顺序节点?

如果当前客户端创建了一个节点获得了锁,那么改节点被删除才认为是锁已经释放了,但是如果遇到异常情况,业务已经处理完毕,但是该节点没有被删除,说明锁没有释放,那么其他的客户端就没有办法继续获得锁了。

因此创建为临时节点,即便客户端发生异常,只要会话结束,该临时节点就会被删除,这样其他客户端可以继续获得锁。

18、zk中的监听机制,watch机制

可以将watch理解为注册在特定znode节点上的触发器,当这个znode发生改变的时候,即调用了create,delete,set方法的时候,会触发znode上注册的对应事件,请求watch的客户端就会接收到异步通知,此时客户端就可以根据watch通知状态和事件类型做出相应的业务处理。

命令行使用watch

get -w /test 一次性监听节点,节点内容改变或者节点删除后收到通知

ls -w /test 监听目录,创建和删除子节点收到通知,但是子节点中新增节点不会收到通知

ls -R -w /test 监听子节点中子节点的变化 ,但是内容变化不会收到通知

watch机制的实现

1、客户端 注册watch事件

客户端发送一个watch监控事件的会话请求时,做了一下内容

  •  对该会话进行标记 --- 标记是一个带有watch事件的请求
  • 将watch事件存储到ZKWatchManager中。

2、服务端注册watch事件

  • 解析收到的请求是否含有watch事件
  • 将对应的watch存到WatchMagager中

3、服务端watch事件的触发过程

  • 节点数据变更后,会调用WatchMagager.triggerWatch方法触发变更事件(先封装一个带有会话状态,事件类型,数据节点三种属性的WacthEvent对象)
  • 根据节点路径去WatchMagager中查询是否有注册watch事件,如果有,就删除WatchMagager中的事件(删除说明是一次性的watch),然后把这个事件存在一个Watchers集合里面,通过process方法给客户端发通知。

4、客户端回调watch事件

  • 客户端使用 SendThread线程接收事件通知
  • 使用EventThread线程回调watcher (这个线程也会删除ZKWatchManager中对应的watch,因此也是一次性的)

19、zk中对节点的监听是永久的吗?为什么?

不是,watch是一个一次性的触发器,当被设置watch的节点发生了改变,则服务器会将这个改变发送给设置了watch的客户端,以便通知他们。

watch是轻量的机制:只通知监听者发生了事件,具体的事件内容不会告知,这样也是为了减轻服务器和带宽的压力。

为什么不是永久?如果服务端变动频繁,而且监听的客户端很多,这种情况下,每次变动都要通知到所有的客户端,给网络和服务器会带来很大的压力。(3.6.0版本之后支持持久递归,可以多次触发)

20、watch机制三个角色:

客户端线程,客户端的watchManager 和 zookeeper服务器

客户端向zookeeper服务器注册一个watcher监听

客户端把这个监听信息存到客户端的watchManager中

当zookeeper中的节点发生变化,通知客户端,客户端回调用相应watcher对象中的回调方法,其中watch回调是串行同步的。

21、CAP理论

一个分布式系统最多只能同时满足一致性,可用性,分区容错性三项中的两项。

  • 一致性consistency:更新操作成功并返回客户端后,所有节点在同一时间的数据完全一致。
  • 可用性availablity :服务一直可用
  • 分区容错性partition tolerance: 分布式系统在遇到某个节点或者网络分区故障,仍然可以对外提供满足一致性或者可用性的服务(避免单点故障)

22、BASE理论

BASE理论是对CAP理论的延伸,核心思想是及时无法做到强一致性(CAP的一致性),但是可以采用适合的方式达到最终一致性。

  • 基本可用(basically available):分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用,如电商大促,为了应对访问激增,部分用户被引导到降级页面,服务层也是降级服务
  • 软状态 soft state:指系统允许存在中间状态,而该中间状态不会影响系统的整体可用性。分布式系统存储中一般一份数据至少三份副本,允许不同节点之间的副本同步延时就是软状态的体现。
  • 最终一致性 eventual consistency : 指系统中所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的特殊情况。

23、ZK中的一个客户端修改了某节点的数据,其他客户端能够马上读到这个数据吗?

这个就是zk的一致性问题,因为过半机制,并且写的时候其他节点可以处理读的请求,因此会存在读不到新数据的情况,但是zk会保证所读到的数据是历史版本已经提交的数据,而不是脏数据。

那么能不能保证每次都读到最新的数据呢?其实是可以的,Java中有个sync函数进行同步回调,每次读之前调用一个sync函数,然后在去getdata,那么就可以保证每次都可以读到最新数据。

24、ZK和eureka的区别?

ZK:CP设计,目标是一个分布式的协调系统,用于进行统一资源管理,当主节点宕机后,需要进行leader的选举,在这个期间内,zk服务是不可用的

eureka: AP设计,目标是一个服务注册发现系统,专门用于微服务的服务发现注册。eureka的各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余节点依然可以提供注册查询服务。如果eureka的客户端在向某个eureka注册时发现连接失败,会自动切换到其他eureka节点,只要有一台eureka还能正常工作,就能保证可用性,只不过查询到的信息可能不是最新的(保证可用性,不保证强一致性)

同时,当eureka的服务端发现85%以上的服务都没有心跳的话,就会认为是自己网络出现了问题,就不会从服务列表中删除这些失去心跳的服务,同事eureka客户端也会缓存服务信息。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值