概念:
ZooKeeper是一个为分布式应用提供协调服务的开源项目
工作机制:
从设计模式来讲,ZooKeeper是一个基于观察者模式,为分布式服务提供支持的框架。其本身用于存储和管理数据,可以接受观察者的注册,数据发生变化时候,ZooKeeper就会主动去通知这些观察者。
特点:
- ZooKeeper的服务端是由一个领导者(leader)和多个跟随者(follower)所组成的集群,集群之间通过Zab(Zookeeper Atomic Broadcast)来保持数据的一致性
- ZooKeeper中有半数以上节点存活,ZooKeeper就能提供正常服务,这也是为何ZooKeeper服务器要奇数台的原因。假设当你有5台服务器,挂掉3台,这个时候ZooKeeper就不能正常工作了,可是当你有6台服务器,此时挂掉3台,服务器也不能使用了,所以偶数台服务器的时候会浪费掉一台。
- 每个server存放的数据都是一致的(镜像)
- 数据更新具有原子性
- 请求具有顺序性(对于客户端的每个更新请求,Zookeeper都会分配一个全局唯一的递增编号),同一个client发出的请求是按照顺序来执行的
- 可靠性:一次更改请求被应用,更改的结果就会被持久化
数据结构:
ZooKeeper的数据结构跟树差不多,每个znode可存放1MB的数据,每个节点都可以通过路径唯一标识
应用场景:
消息发布订阅、负载均衡、命名服务、集群管理、统一配置管理等当然对于本身搞java分布式的,ZooKeeper最常见的应用场景还是担任生产者和消费者服务的注册中心,经常结合dubbo使用。
zookeeper概念杂谈:
- 为了保持高可用,ZooKeeper一般是以集群的方式部署的,只有集群中没有超过半数的机器挂掉,那么ZooKeeper就能正常使用,具有一定容错性
- ZooKeeper的数据存放量较小,因为它将数据保持在内存中,但是这样的数据访问效率提高了
- ZooKeeper有临时节点(跟session绑定)和永久节点的概念,当会话结束的时候,临时节点就会被删除,数据也会被清除,而永久节点则会一直保持。临时节点和持久节点都支持编号,单调递增,编号可以用于为所有事件进行全局排序,分布式系统中,可以通过编号来推断事件顺序
- ZooKeeper底层主要提供的功能:(1)管理用户提交的数据(2)为用户程序提交数据节点监听服务
- 会话(session),客户端启动的时候,会与服务端建立一个TCP长链接。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够通过该链接接收来自服务器的Watch事件通知
- session的sessionTimeout值用来设置一个客户端会话的超时事件,如果因为意外情况导致客户端和服务端的连接断开,只要在sessionTimeout规定的时间内能够重新连接上集群任意一台服务器,那么之前创建的会话仍然有效
- Znode:ZooKeeper中节点分为两类:(1)一类是构成集群的机器,称之为机器节点。(2)一类是数据模型中的数据节点。
- Zookeeper中Znode用来存放数据,对于每个Znode,Zookeeper都会维持一个Stat的数据结构,这个数据结构会记录一些版本信息等
- Watcher,数据监听器,允许用户在指定节点注册一些监听,在一些特定事件触发时候,服务端就会将事件通知到注册的客户端中去。
- ACL策略:全称AccessControILists,是权限控制的策略,有以下五种权限:(1)CREATE:创建子节点的权限 (2) READ: 获取节点数据和子节点列表 (3) WIRTE: 更新节点数据 (4)DELETE: 删除子节点的权限 (5)ADMIN:设置节点的ACL权限。
Zookeeper内部原理:
(1)选举机制:
- ZooKeeper集群中没有使用传统的主备模式,而是引入了Observer、Follower和Leader的方式。集群中所有的机器会通过一个选举,来选举出一台为leader的机器。
- Leader:负责发起投票和决议,更新系统状态。Follower:用于接收客户端请求并向客户端返回结果,在选举过程中参与投票。Observer:接收客户端连接,将请求转发给leader节点,但是Observer不参与投票过程,只同步leader状态。
以上述这张图来说明选举过程
- id为1的服务器启动,发起一次选举,投了自己一票,因为此时不够半数以上,选举无法完成,id为1的服务器状态为looking
- id为2的服务器启动,再次发起一次选举,服务器2投自己一票,并和id为1的服务器交换选票信息,服务器1发现服务器2的id比自己大,就会把自己的选票也给服务器2,所以此时服务器1为0票,服务器2为2票,但是此时还没超过半数,选举也无法完成。服务器1和2的状态都为looking
- 服务器3启动发起一次选举,此时服务器1和2都会更改选票为服务器3,所以服务器3就有3票了,超过半数,即当选为leader。服务器1、2更新状态为FOLLOWING,服务器3的状态为leading
- 服务器4启动,投自己一票。因为服务器1、2、3此时的状态都不是looking,所以没人会再投它了,它和服务器3一比较,少数服从多数,就把选票给服务器3了
- 服务器5同服务器4
关于选举机制,这里还要提及到zab协议,zab协议包括两种基本模式:崩溃恢复和消息广播
6. 崩溃恢复当整个服务框架在启动过程中,或者当Leader服务器中断,退出。zab协议就会进入崩溃恢复模式并选举产生新的Leader服务器。
7. 当集群中已经有过半Follower服务器完成了和Leader服务器的状态同步,那么整个服务就可以进去广播模式了,当系统处于广播模式,此时有新服务器加入,新加入的服务器就会自觉进入数据恢复模式,找到leader所在服务器,并与其进行数据同步
(2)Stat结构体:
上述中我们提到Stat结构体,那么这个结构体中包含哪些数据呢?
czxid //创建节点的事务id
ctime //节点被创建的毫秒数
mzxid //更新节点的最后事务id
mtime //节点最后被修改的毫秒数
pZxid //最后更新的子节点
cversion //子节点变化号
dataversion //数据变化号
aclVersion //访问控制列表的变化号
ephemeralOwner //如果为临时节点,就是session id 否则就为0
dataLength //数据长度
numChildren //子节点数量
(3)监听器工作流程:
- 首先main线程中创建ZooKeeper客户端,这个时候就同时创建两个线程,一个负责通信,一个负责监听
- 通过通信线程将监听的事件发送给ZooKeeper
- ZooKeeper将监听事件添加到注册监听器列表中
- ZooKeeper监听到有数据或者路径变化,就会发送给监听线程
- 然后监听线程就会调用process方法
(4)写数据流程:
- 客户端向ZooKepper的Server1(非leader节点)发送写请求
- Server1会将请求转发到leader节点,这个leader会将写请求广播给各个Server,各个Server会将写请求加入到待写队列,并向leader发送成功消息
- leader收到半数以上server的成功消息,说明写操作可以执行,这个时候就会向各个server发送提交信息,各个server接收到信息后,就会执行队列里面的写请求。
- 执行完写请求后,各个Server就会通知各个Client数据写成功了,此时就认为整个写操作成功