Zookeeper
基本概念
-
定义:一款高性能的分布式协调服务软件。
-
功能:
-
功能:分布式协调(基于zookeeper实现分布式锁),分布式队列,分布式同步,数据发布/订阅,负载均衡,通知、集群管理,master选举,协调资源锁,命名服务,配置维护,域名服务,组服务等功能。
-
常用功能:
-
分布式锁:利用临时有序节点实现。
-
服务注册与发现:利用ZNode和Watcher特性,实现分布式的注册与发现,一般用作dubbo的注册中心
-
共享配置和状态信息:redis的分布式解决方案,codis,利用zookeeper存放数据路由表,存放codis-proxy节点的原信息,同时,codis-config发起命令,也通过zookeeper同步到各个存活的codis-proxy
-
保障高可用:kafka, hbase, hadoop都依靠zookeeper同步节点信息。
-
-
-
数据存储:
Zookeeper内部的数据会以分层存储的文件结构,存储在内存中,本质上也是一个分布式的小型存储系统,可以通过选举算法,和集群复制避免单点故障。Zookeeper中的每个节点都是可以存储数据的,但是容量只有1M。
-
设计模式:
观察者模式,接受观察者的注册,一旦数据发生变化,zookeeper发出通知,让观察者做出反应,实现了集群中的master/slave的管理模式。
-
特点:
-
简单化:允许各分布式进程通过一个共享的命名空间通信
-
健壮性:严格有序访问,高性能,高可靠。
-
有序性:每次更新操作都打上了一个数字标签,严格保证有序,同步原语可以借此实现
-
速度快:适合用于读写比例为10:1的场合
-
-
特性:
-
同一时刻,多台机器创建同一个节点,只有一个能争抢成功。用于分布式锁。
-
临时节点的生命周期与会话一致,会话关闭,临时节点删除,这个特性被用作心跳,动态监控,负载等动作。
-
顺序节点的节点名全局唯一,可以用来实现分布式环境的全局自增长Id
-
zookeeper是一个又多个server组成的集群,一个leader多个follow,leader负责写,更新,请求转发。follow负责读,
-
更新请求按顺序进行,来自同一个客户端的请求,按发送顺序依次执行
-
数据更新具有原子性,一次更新,要么成功,要么失败
-
全局数据一致,无论客户端连接的哪一台zookeeper,在一定时间范围内,都能读到最新数据
-
-
与eureka的对比
-
根据CAP理论,分区容错性是必须要满足的,即在网络分区的时候,仍然能保证系统运转。但是可用性,与一致性就只能满足一个了,zookeeper保证了一致性,即在一定时间范围内,数据是完全一致的。而不能满足可用性,即,可能在一段时间内,访问不了zookeeper。Eureka则选择了可用性,可能在一段时间内,分区的网络数据是不一致的。而eureka的每一个节点都是平等的关系,一部分节点挂了,不影响别的节点工作。但zk的master不可用了,就会进行重新选举,在重新选举的这一段时间内,是不可用的。
-
Eureka有一个本地缓存,即使所有的节点都挂了,也能拿到本地的缓存数据。
-
如果数据不经常变动,那就选择保证了分区可用性和高可用的。
-
-
数据结构:树状
-
节点类型,
-
持久:当在树形结构上创建了一个节点,除非对该节点进行移除,否则永远保留在zk上
-
临时:生命周期与客户端的会话绑定,如果会话失效,这个客户端的所有临时节点都会被删除
-
持久有序:由父节点维护的自增整型,顺序属性
-
临时有序:同上
-
投票选举机制
-
服务器的三种角色:
-
leader:事务请求的唯一调度和处理者。集群内部各种服务的调度者,能够保证集群事务处理的正确性。
-
follower:处理非事务请求,将事务请求转发给Leader,参与事务请求的proposal投票和leader选举。
-
observer:zk3.0之后引入的一个角色,提升了非事务处理能力,将事务请求转发给leader,但不参与各种投票和选举。
-
-
Zk的四种状态:
-
Looking:寻找leader的状态,如果处于该状态,则代表集群当前没有Leader,需要立即进行Leader选举
-
following:表示当前服务器的角色是follower
-
leading:表示当前服务器的角色是leader
-
observing:表示当前服务器的角色是observer
-
-
选举背景
- 一个zk集群应该有2n+1台服务器,只要超过半数服务器节点正常服务,zk集群就能保持服务。
-
选举流程
zk具有自己的Myid,在执行写数据的时候,每个节点自己都会维护自己的zxid记录,本地事务日志,里边每个数据都有zxid,,本地故障恢复,节点重启的时候zxid最大的作为leader。如果因为一些原因导致zxid一致了,那么就判断myid。注:集群也有个共享的集群事务日志,记录了整个 ZooKeeper 集群中发生的所有事务操作,包括写操作和更新。这个共享的有序事务日志是保证 ZooKeeper 数据一致性的关键。
通知机制
-
特性:zk的一大特性就是,带有watcher的通知机制,客户端对Znode建立一个watcher事件,当服务端的一些指令使znode发生变化,触发了这个watcher,客户端会收到zk发来的通知。
-
工作流程
-
客户端注册watcher
-
服务端处理watcher
-
客户端回调watcher
-
-
watcher特性
-
一次性:watcher一旦被触发,服务端就会将watcher从服务器的节点上移除。
-
客户端串行执行:watcher回调过程是一个串行的过程,如果znode发生了变化,这个节点上的多个watcher,一个一个进行回调,不会同时进行。
-
轻量级:watcher只会告诉客户端发生了事件,但是不会说明具体发生了什么事件。客户端注册的时候,并不会将watcher实体传送给服务端,只是使用boolean进行标记。
-
服务端发送到客户端是异步进行的,不能期望立即能监听到节点的每次变化。只保证了最终一致性。
-
ZAB协议(Zookeeper Atomic Broadcast)
zab协议有两种模式,恢复模式和广播模式。当服务启动的时候,或者leader崩溃了,zab进入恢复模式,当领导者被选举出来,且大多数server已经完成了和leader的状态同步,恢复模式就结束。Zxid使用了64位数字,前32位标记到底是哪个leader,后32位用于递增计数。
一旦leader和大多数follower进行数据同步,leader就可以开始进行广播,新的follower接入集群,会在恢复模式下启动,与leader同步过数据,也开始参与广播。
当leader崩了,或者失去了与大部分follower的通信,就停止广播,广播要保证提议被按顺序处理,zxid可以实现这种需求。
Zookeeper的使用
一般是使用奈飞的Curator开源框架,实现了对底层API的封装,客户端的重试策略,事件监听,分布式锁,分布式计数器等等高级特性。
分布式锁的实现
-
使用ZK作为分布式锁的原因:ZK节点不能重复,所有的写都要经过leader节点,属于单线程操作。
-
分类:
-
排它锁
获得锁:zk会保证所有的客户端,只有一个客户端能够创建成功临时节点,没有创建成功的客户端,就要到/exclusive_lock节点上,注册一个子节点变更的Watcher监听。以便实时得到lock节点的变更情况。
释放锁:1. 已经获取到锁的客户端发生宕机,会话结束,临时节点自动被删除,锁被释放。2. 正常逻辑执行结束,客户端自己删除临时节点。zk通知所有在/exclusive_lock节点注册了节点变更watcher监听的客户端,重新获取锁。
-
共享锁
区别就是在同一时刻能否同时监听这个锁。排它锁不能实时监听。
-
-
缺点:由于每次写操作,都要与follower进行通信,效率不如redis
与dubbo的联系
- zk实现ip地址与服务进行对应,dubbo实现服务接入与服务提供的调度。