1 什么是ZooKeeper
Zookeeper是大数据生态圈中的重要组件,其由雅虎开源并成为Apache的顶级项目。用一句话对其进行定义就是:它是一套高吞吐的分布式协调系统。
ZooKeeper致力于提供一个高性能、高可用,且具备严格的顺序访问控制能力的分布式协调服务,是雅虎公司创建,是Google的Chubby一个开源的实现,也是Hadoop和Hbase的重要组件。
Zookeeper至少具有以下特点:
- 1.Zookeeper的主要作用是为分布式系统提供协调服务,包括但不限于:分布式锁,统一命名服务,配置管理,负载均衡,主控服务器选举以及主从切换等。
-
2.Zookeeper自身通常也以分布式形式存在。一个Zookeeper服务通常由多台服务器节点构成,只要其中超过一半的节点存活,Zookeeper即可正常对外提供服务,所以Zookeeper也暗含高可用的特性。客户端可以通过TCP协议连接至任意一个服务端节点请求Zookeeper集群提供服务,而集群内部如何通信以及如何保持分布式数据一致性等细节对客户端透明,结构如下图
- 3.Zookeeper是以高吞吐量为目标进行设计的,故而在读多写少的场合有非常好的性能表现。
Zookeeper设计目标:
- 简单的数据结构:共享的树形结构,类似文件系统,存储于内存;
- 可以构建集群:避免单点故障,3-5台机器就可以组成集群,超过半数正常工作就能对外提供服务;
- 顺序访问:对于每个写请求,zk会分配一个全局唯一的递增编号,利用这个特性可以实现高级协调服务;
- 高性能:基于内存操作,服务于非事务请求,适用于读操作为主的业务场景。3台zk集群能达到13w QPS;
2 使用场景
分布式环境协调和通信到底有什么场景?
-
数据发布/订阅(配置中心)
负载均衡
-
命名服务
-
Master选举
读写分离场景中,由master处理读请求;
Master处理复杂的逻辑,并将处理结果通知到其他集群机器; -
集群管理
配置管理
分布式队列
-
分布式锁
3 节点
3.1数据模型
ZooKeeper的视图结构和标准的Unix文件系统类似,其中每个节点称为“数据节点”或ZNode,每个znode可以存储数据,还可以挂载子节点,因此可以称之为“树”
特性:
- 在Zookeeper中,znode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储或获取数据
- 通过客户端可对znode进行增删改查的操作,还可以注册watcher监控znode的变化。
3.2 节点类型
Zookeeper节点类型
- 持久节点(PERSISTENT)
zkCli退出后重连该节点还在,被持久化了 - 持久顺序节点(PERSISTENT_SEQUENTIAL)
生成的节点带有序号 - 临时节点(EPHEMERAL)
zkCli退出后重连该节点不存在了 - 临时顺序节点(EPHEMERAL_SEQUENTIAL)
生成的节点带有序号
注:对于持久节点和临时节点,同一个znode下,节点的名称是唯一的!这是实现分布式锁的基础!!!
3.3 节点状态属性
序号 | 属性 | 数据结构 | 描述 |
---|---|---|---|
1 | czxid | long | 节点被创建的Zxid值 (事务ID可以识别出请求的全局顺序) |
2 | mzxid | long | 节点被修改的Zxid值(事务ID可以识别出请求的全局顺序) |
3 | pzxid | long | 子节点最后一次被修改时的事务ID(事务ID可以识别出请求的全局顺序) |
4 | ctime | long | 节点被创建的时间 |
5 | mtime | long | 节点最后一次被修改的时间 |
6 | versoin | long | 节点被修改的版本号 (基于CAS理论保证分布式数据原子性操作) |
7 | cversion | long | 节点的所拥有子节点被修改的版本号(基于CAS理论保证分布式数据原子性操作) |
8 | aversion | long | 节点的ACL被修改的版本号(基于CAS理论保证分布式数据原子性操作) |
9 | emphemeralOwner | long | 如果此节点为临时节点,那么它的值为这个节点拥有者的会话ID;否则,它的值为0 |
10 | dataLength | int | 节点数据域的长度 |
11 | numChildren | int | 节点拥有的子节点个数 |
3.4 ACL保障数据的安全
每个节点在创建之初都会有相应的访问权限,而访问权限的机制就是ACL
ACL机制:
表示为scheme:id:permissions,第一个字段表示采用哪一种机制,第二个id表示用户,permissions表示相关权限(如只读,读写,管理等)。zookeeper提供了如下几种机制(scheme):
world: 它下面只有一个id, 叫anyone, world:anyone代表任何人,zookeeper中对所有人有权限的结点就是属于world:anyone的
auth: 它不需要id, 只要是通过authentication的user都有权限(zookeeper支持通过kerberos来进行authencation, 也支持username/password形式的authentication)
digest:它对应的id为username:BASE64(SHA1(password)),它需要先通过username:password形式的authentication
ip:它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如ip:192.168.1.0/16, 表示匹配前16个bit的IP段
5 集群解析
5.1 集群特点
- 顺序一致性
- 原子性
- 单一视图
- 可靠性
- 实时性
- 角色轮换避免单点故障
5.2 集群角色
Leader
集群工作机制中的核心,作用如下:
事务请求的唯一调度和处理者,保证集群事务处理的顺序性
集群内部个服务器的调度者(管理follower,数据同步)
Follower
集群工作机制中的跟随者,作用如下:
处理非事务请求,转发事务请求给Leader
参与事务请求proposal投票
参与leader选举投票
PS:proposal见paxos算法
Observer
3.30以上版本提供,和follower功能相同,但不参与任何形式投票,作用:
处理非事务请求,转发事务请求给Leader
提高集群非事务处理能力
配置:
peerType=observer
server.3=192.168.0.102:2888:3888:observer
5.2 集群配置
- 1 配置文件zoo.cfg
clientPort=2181
initLimit=5
syncLimit=2
peerType=observer
server.ID1=IP1:2888:3888
server.ID2=IP2:2888:3888
server.ID3=IP3:nnnn:mmmm:observer
IDn: server id,集群中机器序号
IPn: 机器ip地址
nnnn: 同步端口
mmmm: 选举端口
observer: 是否为观察者
PS:集群机器的zoo.cfg文件是一致的
2 创建myid文件
在dataDir所配置的目录下,创建一个名为myid的文件,在该文件的第一行写上一个数字,和zoo.cfg中当前机器的编号对应上3 配置集群其他机器zoo.cfg和myid文件
启动服务器4验证服务器
使用stat命令
5.2 Zookeeper集群一致性协议ZAB解析
一致性算法细节详见“05 一致性算法”
5.2.1 消息广播
- 1 Leader 接收到消息请求后,将消息赋予一个全局唯一的 64 位自增 id,叫做:zxid,通过 zxid 的大小比较即可实现因果有序这一特性。
- 2 Leader 通过先进先出队列(通过 TCP 协议来实现,以此实现了全局有序这一特性)将带有 zxid 的消息作为一个提案(proposal)分发给所有 follower。
- 3 当 follower 接收到 proposal,先将 proposal 写到硬盘,写硬盘成功后再向 leader 回一个 ACK。
- 4 当 leader 接收到合法数量的 ACKs 后,leader 就向所有 follower 发送 COMMIT 命令,会在本地执行该消息。
- 5 当 follower 收到消息的 COMMIT 命令时,就会执行该消息
5.2.2 崩溃恢复
- 1 每个Server会发出一个投票,第一次都是投自己。投票信息:(myid,ZXID)
- 2 收集来自各个服务器的投票
- 3 处理投票并重新投票,处理逻辑:优先比较ZXID,然后比较myid
- 4 统计投票,只要超过半数的机器接收到同样的投票信息,就可以确定leader
- 5 改变服务器状态
6 事件监听机制
7 Zookeeper使用注意事项
-
Zk数据与日志清理
dataDir目录、dataLogDir两个目录会随着时间推移变得庞大,容易造成硬盘满了,清理办法:
自己编写shell脚本,保留最新的n个文件
使用zk自带的zkClient.sh保留最新的n个文件,zkClient.sh –n 15
配置autopurge.snapRetainCount和autopurge.purgeInterval两个参数配合使用; -
Too many connections
配置maxClientCnxns参数,配置单个客户端机器创建的最大连接数; -
磁盘管理
磁盘的I/O性能直接制约zookeeper更新操作速度,为了提高zk的写性能建议:
使用单独的磁盘
Jvm堆内存设置要小心 -
磁盘管理集群数量
集群中机器的数量并不是越多越好,一个写操作需要半数以上的节点ack,所以集群节点数越多,整个集群可以抗挂点的节点数越多(越可靠),但是吞吐量越差。集群的数量必须为奇数; -
磁盘管理数据存储
zk是基于内存进行读写操作的,有时候会进行消息广播,因此不建议在节点存取容量比较大的数据;