文章目录
【关于作者】
关于作者,我目前蚂蚁金服搬砖任职,在营销投放领域工作了多年,目前在专注于内存数据库相关的应用学习,如果你有任何技术交流或大厂内推及面试咨询,都可以从我的个人博客(https://0522-isniceday.top/)联系上我~
Zookeeper
是什么
一句话
- (分布式)数据的一致性解决方案
场景
-
维护配置信息
-
分布式锁服务
- 利用临时有序节点的方式
-
集群管理
- 通过watcher机制,以事件的方式将机器的信息推送给机器
-
生产分布式唯一id
- 通过持久有序节点创建并返回当前节点序号
设计目标
-
高性能
- 数据存储在内存中
-
高可用
- 集群部署
- 读写的模型,写请求只能发往leader节点,并经过zab协议同步给从节点,写请求在被写入内存之前先写入磁盘持久化
-
严格顺序访问
-
针对客户端的每次请求生产唯一的事务编号(全局递增的编号),由此保证客户端的事务顺序(由编号顺序决定),事务请求都由leader节点来执行
-
请求分类
-
事务性请求
- 写请求
-
非事务性请求
-
读请求
- 可能存在无法读到最新数据的情况
-
-
-
数据模型
-
树状结构
-
znode(节点)
- cZxid:创建节点时的事务id
- mZxid:数据节点最后一次更新时候的事务id
- pZxid:数据节点子节点最后一次被修改的事务id
- cversion:子节点被修改的次数
- dataversion:节点数据的修改次数
- aclVersion:节点acl修改次数(权限)
- ephemeralOwner:如果节点是临时节点,则表示创建该节点的会话的 SessionID;如果节点是持久节点,则该属性值为 0
- dataLength:数据内容的长度(字节)
-
节点类型
-
临时节点
- 会话关闭时候节点会消失
-
持久节点
-
有序节点
-
-
ACL权限控制
-
特性
- 权限控制基于每个znode节点
- 每个znode支持多种权限控制方案和多个权限
- 子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点
- 类似于linux文件的权限结构
-
概念
-
权限模式(scheme):授权的策略
- world 只有一个用户:anyone,代表登录zokeeper所有人(默认)
- ip 对客户端使用IP地址认证
- auth 使用已添加认证的用户认证
- digest 使用“用户名:密码”方式认证
-
授权对象(id):授权的对象,权限所在的用户或者指定的权限实体
-
权限(permission):授予的权限
-
-
命令
-
组成
- Scheme:ID:Permission组合成一个有效的ACL信息
怎么用
shell指令操作
-
新增节点
- 并发写的一致性控制:写的请求都由leader来执行,原子级别的一致性
synchronized (parent) {
Set<String> children = parent.getChildren();
if (children != null) {
if (children.contains(childName)) {
throw new KeeperException.NodeExistsException();
}
}
if (parentCVersion == -1) {
parentCVersion = parent.stat.getCversion();
parentCVersion++;
}
parent.stat.setCversion(parentCVersion);
parent.stat.setPzxid(zxid);
Long longval = convertAcls(acl);
DataNode child = new DataNode(parent, data, longval, stat);
parent.addChild(childName);
nodes.put(path, child);
if (ephemeralOwner != 0) {
HashSet<String> list = ephemerals.get(ephemeralOwner);
if (list == null) {
list = new HashSet<String>();
ephemerals.put(ephemeralOwner, list);
}
synchronized (list) {
list.add(path);
}
}
}
-
删除节点
-
更新节点
-
事务控制
-
-
监听器(配置中心)
-
添加监听器
-
get、stat [path] watch
-
ls/ls2 [path] watch
能够监听节点及其子节点
-
-
客户端会话消失监听器也消失
-
进阶(使用场景、集群选举、一致性协议)
监听机制
-
Watcher
-
概念
- 订阅/通知机制
-
特性
-
一个watcher回调逻辑不应该太多,以免影响别的watcher执行
-
-
使用场景
-
配置中心
- 利用watcher机制,通过watcher的回调方法进行数据的改变
-
生成分布式唯一id
- 通过临时有序节点的特性,并取序列号及为分布式环境下的唯一ID
-
分布式锁
-
阻塞锁
- 概念:未拿到锁的线程会持续等待,获得锁后再执行操作
-
非阻塞锁
- 概念:未拿到锁的线程会直接返回结果
-
原理
-
利用临时有序节点的有序行,线程先进行锁的申请(也就是再临时有序节点下创建一个节点),然后进行取锁操作(获得临时有序节点的所有值并排序,观察排序列表的第一个值是否为自己所申请的节点,如果是就拿到锁,不是监听有序节点的上一个节点,因为该节点的线程拿到锁释放时候会监听通知该线程),然后再执行取锁操作,释放锁(删除该临时有序节点)
- 该种监听方式可以避免羊群效应(其实可以都监听子节点的变更操作也可以达到锁的需求,但是这样子当子节点变更时候会通知所有的节点,造成不必要的开销)
-
-
-
master选举
- 利用zk的强一致性, 可以保证在分布式环境下多个节点高并发的同时创建节点唯一,即只会创建一个节点,创建成功的节点则作为master,创建失败的节点去监听该节点,如果master挂了则从节点会去从新选举master
-
分布式队列
- 利用临时有序节点进行编号的排序
一致性协议(zab协议:Zookeeper Atomic Broadcast)
-
概念
-
ZAB协议定义整个zookeeper中关于事务的处理流程
-
Paxos算法
- 1.所有提出的提案最终只有一个被选定
- 2.如果没有提案,那么最终没有任何选定的提案
- 3.当提案被选定后,所有客户端都应该能获取到提案信息
-
-
状态
-
崩溃恢复
-
定义
- 当leader节点崩溃、或者leader与半数的follower节点通信异常的情况下,ZAB就会进入崩溃恢复模式
-
目标
- 1.leader服务器提交的请求,其他服务器也必须提交成功
- 2.leader服务器再第一阶段提交的消息,但是并没有commit,需要保证该事务消息被丢弃
-
目标的解决
-
第一个目标解决
-
1.leader选举
-
2.数据同步
- leader需要确认队列中的proposal被半数的follower同步完成,才代表数据同步完成,因为只有follower同步完成才能放入可用机器列表中,半数的节点可用集群才能提供正常服务进入消息广播状态
-
-
第二个目标解决
-
zxid的设计
-
64位数字,高32位代表选举的epoch,每次选举找出zxid最大的值并解析出该32位+1并归零低32位,完成选举
-
当leader选举出来之后,连接上leader的follower会何leader比较proposal(zxid),这个时候leader会根据比较情况要求回滚或者同步,等到集群中过半机器都同步完成,此时再提供服务
- 因此过大的proposal。也就是leader再第一阶段发起的proposal但是没有在第一阶段发送给follower,因此就被丢弃了
-
-
-
-
-
消息广播
-
定义
- 当ZAB选举出一个新的leader之后,进入消息广播模式,如果在该模式下加入一个follower节点之后,再次进入崩溃恢复模式,直至与leader节点状态同步完成为止
-
流程
-
- leader从客户端收到一个事务请求(写请求)
-
- leader生成一个新的事务并为这个事务生成一个唯一的ZXID
-
- leader将这个事务提议(proposal)发送给所有的follows节点
-
4.,leader会为每一个follower分配一个单独的FIFO队列,follower节点将收到的事务请求加入到历史队列(history queue)中,并发送ack给 leader
- 此时follow节点会进行事务日志的写入
-
- 当leader收到大多数follower(半数以上节点)的ack消息,leader会发送commit请求
- 这个会发送给observer
- 并不需要中断等待所有的follower返回选票信息,超过半数就可以直接进行第二阶段
-
- 当follower收到commit请求时,从历史队列中将事务请求commit(此时leader也会进行提交操作)
-
-
-
保护模式
- 一旦集群中的半数节点不可用则进入保护模式,只可读
-
leader选举
-
四种角色
-
looking:寻找leader状态。当服务器处于该状态时,它会认为当前集群中没有 leader,因此需要进入leader选举状态。
-
leading: 领导者状态。表明当前服务器角色是leader。
-
following: 跟随者状态。表明当前服务器角色是follower。
- 接收到事务请求之后会转发给leader节点进行统一事务处理(ZAB一致性协议)
-
observing:观察者状态。表明当前服务器角色是observer。
- 不参与集群的选举
- 不参与集群中写数据的ack反馈
- 负责处理来自客户端的诸如查询数据节点等非事务性的会话请求操作
- 数据没有事务化到硬盘。即Observer只会把数据加载到内存
-
-
启动时的选举
-
1.每个server发起一个投票
- 每个服务器发出选票,选票规则如下:(myid-集群编号,zxid-最近的事务id)
-
2.接受到其他服务端实例发来的选票并校验选票
-
校验处理选票,例如是不是本轮的选票、是否是looking状态下的选票
-
服务器收到选票后比较选票并修改选票,是否修改规则如下:先比较zxid,zxid大的胜出,如果想等则比较myid,大的胜出。然后修改选票(就是比较过后的选票)。
- zxid最大代表选举出来的Leader有所有已经被提交的提案
-
修改选票完成后再起发起投票
-
-
3.统计选票。每轮统计完成后都会统计选票,超过半数的机器收到相同的选票则选举完成
-
4.同步服务端实例状态
-
-
运行时的选举
- 新增following节点并不会发起选举,只有当leader节点挂了后才会,此时zookeeper会暂停服务并进入looking状态并进入选举
-
选举算法
这三种选举算法分别对应值为0-3,其中0为LeaderElection算法,使用的是UDP协议实现,1代表UDP版本的FastLeaderElection算法,这种算法是非授权模式,2代表的也是UDP版本的FastLeaderElection算法,不过这种使用的是授权模式,3代表是TCP协议实现的FastLeaderElection算法。
不过需要注意的是,从Zookeeper3.4.X版本开始,Zookeeper官方已经废弃了UDP协议实现的0-2这三种Leader选举算法,仅仅保留了3这一种TCP协议实现的FastLeaderElection算法,这也是为什么上面我们介绍选举的大致流程中不针对每一种选举算法进行分析的原因。- TCP版本的FastLeaderElection
会话
-
属性
-
sessionId
- session由64个字节组成,能够保持唯一(时间戳+sid)
-
sessionTimeout
- 由客户端发送的timeout计算并确定
-
isClosing
-
TickTime
- 用于分桶的计算
-
-
会话管理
-
SesssionTracker
-
会话清理
-
会话分桶
-
根据会话的下个超时时间作为桶,计算方式:当前时间戳+会话sessionTimeout
-
激活会话会重新给该会话计算分桶
-
激活方式
-
读写请求
当客户端向服务端发送请求的时候,包括读写请求,都会主动触发一次会话激活
-
ping(心跳机制)
.如果客户端在sessionTimeOut / 3时间范围内尚未和服务器之间进行通信,即没有发送任何请求,就会主动发起一个PING请求,去触发服务端的会话激活操作
-
-
-
-
-
-
会话清理
https://www.jianshu.com/p/960f05732a30
-
会话重连
https://www.jianshu.com/p/960f05732a30
四字命令
- 用户在客户端可以通过 telnet 或 nc 向 zooKeeper提交相应的命令