基本架构
主从架构
角色
- leader
- follower:参与选举投票
- observer:没有投票权
模式
- 恢复模式
整个集群不可用,启动、无leader、无法定数量的follower - 广播模式
存在leader,并且有法定数量的follower,整个集群可用
读写分离
- 写转发给leader,保证消息的有序,采用类似两阶段提交
- 读直接从client连接的server读取
原子广播消息系统
消息保证
- 可靠投递(Reliable delivery)
一台服务器提交了消息M,那么最终所有服务器都会提交消息M - 总的有序(Total order)
- 一台服务器在消息b之前提交了消息a,那么所有服务器都会在消息b之前提交消息a
- 每次更新都带有事务id(zxid),zxid包括(epoch, count) ,epoch为leader代id,每次选出新的leader,epoch都会在上一代的基础上+1,count为当期顺序id。zid为64位整数,高32位为epoch,低32位为count。
- 因果有序(Cause order)
服务器在提交消息a之后发送了消息b,在消息b之后发送了消息c,那么a排在b前,b排在c前
消息类型
- 选举消息
- follower中zxid最大者,如果存在多个follower的zxid相同,则以follower的名称序号判断
- 达到法定数量的follower追随
- 活动消息
1.leader生成zxid,并发送日志给follower
2.follower日志持久化成功,回复ack
3.leader收到法定数量的follower回复,则通知follower提交数据
网络结构
- 选举采用网状结构
- 活动消息采用星型结构
法定数量(Quorums)
- 过半(n/2+1)
- 权重方式
- 层级分组方式
数据模型
zookeeper采用目录树结构
节点分类
- 持久节点
- 顺序节点(节点路径末尾增加递增计数)
- 会话节点(session创建激活,结束删除)
节点主要数据结构
- 数据
- 版本号
- acl
- timestamp
zab协议
特性
- 可靠性
正常的server广播消息M,那么所有正常的server最终都会提交消息M - 有序性
1. 某个server在消息M2之前提交了消息M1,那么所有的server都必须在M2之前提交M1
2. leader消息有序性- 如果leader先后广播了M1,M2,那么其他follower将先提交M1,再提交M2
- 如果leader1 广播了消息M1,leader2广播了消息M2,leader1 是leader2的前代,那么folloer将在M2之前提交M1
- 如果leader2 广播了消息M2,某个follower提交了leader1广播的消息M1,那么leader2要先提交M1,才能广播M2
- 完整性
只有消息M的发送者广播了消息M,消息M才能被提交,不能重复提交
协议阶段
- 选举阶段
选出预期leader,预期leader状态为leading,follower状态为following - discovery阶段
收集follower中已提交的最新事务,并更新leader代级关系(epoch) - synchronization
整个集群同步最新的事务数据,保持整体一直,至此预期leader才成为真正的leader - broadcast
更新事务广播
zab对paxos的改进
- paxos不支持多个未提交事务
- paxos无FIFO消息通道,允许消息丢失及重排序
- paxos的提案顺序号需要向前代学习,主故障之后的恢复效率低
特性
- 高可用
主从架构 - 高性能
数据在内存,读写分离 - 高可靠
- 数据一致性
- 写操作原子性,需要投票,顺序一致
- 读操作有序,但不能保证是最新数据
- 更新数据被接受后将会一直存在,直到下一个更新被接受
- 可扩展
随着follower数量的增加,必然带来整个集群写入效率的降低,zk引入了observer节点,observer节点负责读,但是没有投票权,保证了读写性能的平衡 - 及时性——数据在一定时间范围内保证是最新的
- 单系统镜像
无论连接到哪台服务器,看到的是相同的服务视图,即使会话被故障转移到另外的服务器 - 严格有序
watch
事件类型
- create(exist)
- delete(exist/getData/getChildren)
- change(exist/getData)
- children(getChildren)
特点
- 一次性
如果需要监控节点后续变化,需要再次发起监控请求,接收到事件与再次发起监控请求之间存在延迟,中间节点可能已经发生变化 - 会话期内有效
- 有序
- watch根据其他事件、监控、异步复制排序,客户端库保证有序的分发
- client先看见监控事件,然后才是更新后的数据
- watch event的顺序与zookeeper服务看见的更新顺序是一致的
注意事项
- watch维护在与client 连接的server上,如果连接新的sever,会触发session event以及watch重新注册
- 使用exists添加在尚未创建node上的watch,如果断开时创建node并删除,该watch将会丢失
- 连接断开后不会收到任何事件
- 节点发生改变操作成功的结果先于事件到达客户端,节点不会看到watch之前的数据变化
- 节点change包括(节点自身和节点的子节点),节点和子节点,getData和exist 设置节点监控,getChildren设置子节点监控
应用场景
- 配置中心
- 注册中心
- 分布式锁
- 争抢锁阶段需要考虑锁的重入
- 结果的通知
- 轮询——存在延迟,以及轮询带来的请求压力
- watch
- 关注同一节点会增加系统压力;
- 排队,只关注自己前一节点