Zookeeper是一个分布式协调服务。
ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式系统可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
zookeeper=文件系统+通知机制
文件系统
zookeeper在内存中维护一个类似文件系统的数据结构
其中路径上的每个节点都称为znode,znode可以存储数据,但是每个znode最多只能存储1MB,所以说zookeeper的设计目标是协同服务,而不是大容量数据存储。
处理来自客户端对目标节点的请求时,zookeeper并非从根节点开始一层层查找目标节点,而是通过一个hashtable直接定位到目标节点,这样做的目的是提高查找效率(zookeeper的特点就是速度快)
通知机制
客户端注册监听某一个znode,当znode发生变化变动(其中的数据改变、该znode被删除、该znode下新建or删除子节点)时,zookeeper会通知客户端。
也就是说,zookeeper的通知机制是通过对节点变化的监听机制实现的。
分布式集群
zookeeper不仅为分布式系统提供协同,而且zookeeper服务本身就是一个分布式系统。它设计成分布式的主要目的是避免单点故障,3-5台机器就可以组成集群,超过半数正常工作就能对外提供服务。需要注意的是,集群结点数需要是奇数个(2N+1),当至少有N+1个投票才能执行写操作,奇数个的目的就是防止投票时正反数量相同,陷入僵局。
集群中有三种角色:Leader、Follower和Observer。
- Leader:一个集群只有一个Leader,负责接收和协调所有写请求,发送到Follower和Observer的写请求会被转发给Leader处理, Leader协调各Follower,通过投票机制决定是否接受该写请求。 如果超过半数以上的Leader、Follower节点返回写入成功,那么Leader提交该请求并返回成功,否则返回失败。 Follower或Observer返回写请求处理结果。
- Follower:Follower可以处理读请求,且在Leader宕机时作为Leader的候选人参与选举。
- Observer:只负责处理读请求,不参与选举。(因为Leader候选人不需要太多,加入Observer的概念减少开销)
选举机制
zookeeper的选举机制跟Raft协议很像,感觉Raft是参考了zab协议。所以就不细看了,到时再复习Raft即可,我对Raft的理解更深入。
持久化
zookeeper为了更快的响应速度,把数据存放在内存,但是为了保证高可靠性,它同时还有持久化功能,通过快照和事务日志的形式将数据保存在磁盘中。
快照
zookeeper在执行了固定次数个事务后,生成快照文件(当前内存中数据的备份)存放在磁盘上,文件名为 snapShot.{zxid},其中zxid当时已执行的最新事务的zxid。代表[1,zxid]的事务已经保存下来了。
事务日志
zookeeper将执行过的每一条事务写入到事务日志中,为了防止写日志影响zookeeper的响应速度,它一直写同一个日志文件,使用预分配策略,每次扩容时预分配64MB磁盘空间。当执行了固定数量的事务,生成快照之后,才创建新的日志文件。
数据恢复过程
zookeeper从磁盘中恢复数据共有两个步骤,
- 从快照中恢复DataTree,返回通过快照恢复的数据的最大zxid。
- 从事务日志中获取大于zxid的所有日志,将他们应用到步骤1中初步恢复的DataTree中。
其中快照恢复速度快(直接拷贝到内存),事务日志执行速度慢(一条条地执行)。快照的作用是快速恢复大量的数据,日志的作用是恢复快照没有保存到的最后那部分事务。(快照保存开销比较大,所以不能频繁保存快照,期间就用事务日志来保证可靠性)
应用场景
配置管理
程序需要有配置,当程序分散部署到多台服务器上时,每次修改配置都需要逐个修改。但是如果将配置信息放到zookeeper上,保存在一个znode中,让所有相关的应用程序都监听这个znode,那么一旦配置信息发生变化,每个应用程序都能收到zookeeper的通知,然后从zookeeper中获取新的配置信息。
分布式锁
分布式锁用于协调分布式系统中多个节点对一个共享资源的访问。
排他锁
就是指每个需要访问一个共享资源的客户端都向zookeeper申请在某一个路径下创建一个名为distribute_lock的znode,由于同一个路径下的znode不能重名,所以只有一个客户端能够创建成功,则这个客户端持有分布式锁,并且能够访问资源,其他客户端则监听该znode。当该客户端访问完毕后,就删除掉这个znode,zookeeper通知监听中的客户端,这些客户端再申请创建distribute_lock。