Zookeeper基础入门
ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
# Zookeeper数据模型
Zookeeper提供了基于类似于文件系统的目录节点树方式的数据存,通过监控这些数据状态的变化,从而达到基于数据的集群管理,简单的说,zookeeper=文件系统+通知机制。
zookeeper中每一个节点被称为znode,和文件系统一样的树形结构, 可以自由增删znode, znode可以存储数据。
Zookeeper的节点分两类:持久节点和临时节点。
我们可以在新建节点时,可以通过flag
来标记临时节点/顺序节点
create -s znodepath znodevalue # 创建顺序节点
create -e znodepath znodevalue # 创建临时节点
2
# 持久节点
持久节点指一旦被创建,除非主动对树节点进行移除操作,否则,节点将一直保存在zookeeper上
# 临时节点
临时节点的生命周期和客户端会话绑定,一旦客户端会话失败,那么这个客户端创建的所有临时节点都会被移除
# 顺序节点
Zookeeper将序列号和10位填充添加到znode路径。例如,znode路径 /myapp 将转换为/ myapp0000000001,下一个序列号将为/myapp0000000002
# Zookeeper集群角色划分
组成 ZooKeeper 服务的服务器都会在内存中维护当前的服务器状态,并且每台服务器之间都互相保持着通信。集群间通过 Zab 协议(Zookeeper Atomic Broadcast)来保持数据的一致性。
Zookeeper集群的角色有两种:
- Leader: 负责客户端的write类型请求
- Follower: 负责客户端的read类型请求,参与Leader的选举
# Zookeeper会话
ZooKeeper 对外的服务端口默认是2181,客户端启动时,首先会与服务器建立一个TCP长连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通过心跳检测和服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同时还能通过该连接接收来自服务器的 Watch事件通知。
Session的SessionTimeout值用来设置一个客户端会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在 SessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。
客户端在配置Zookeeper节点时,一般是设置一个ZooKeeper集合。
zk=new ZooKeeper("hdp-01:2181,hdp-02:2181,hdp-03:2181", 2000, null);
客户端只会连接到ZooKeeper集合中的一个节点, 它可以是领导者或跟随者节点。 一旦客户端被连接,该节点向该特定客户端分配会话ID并向该客户端发送确认。 如果客户端没有得到确认,它会尝试连接ZooKeeper集合中的另一个节点。 一旦连接到节点,客户端将以定期间隔向节点发送心跳,以确保连接不会丢失。
如果客户端想要读取特定的znode,会向具有znode路径的节点发送读取请求,并且节点通过从其自己的数据库获取它来返回所请求的znode , 为此,在ZooKeeper集合中读取速度快。
如果客户端想要将数据存储在ZooKeeper集合中,它会将znode路径和数据发送到服务器。 连接的服务器将该请求转发给领导者,然后领导者将向所有的跟随者重新发出写入请求。 如果只有大多数节点成功响应,则写请求将成功,并且成功的返回码将被发送到客户端。 否则,写入请求将失败。
# Zookeeper领导选举
考虑一个集群中有N个节点。leader 选举的过程如下:
- 所有节点创建具有相同路径,例如:/app/leader_election/guid_的顺序、临时znode,ZooKeeper集合将附加10位序列号到路径,创建的znode将是/app/leader_election /guid_0000000001,/app/ leader_election/guid_0000000002等。
- 对于给定的实例,在znode中创建最小数量的节点成为leader ,而所有其他节点是followers。
- 每个从节点监视具有次最小编号的znode。例如, /app/leader_election/guid_0000000008的节点将观察/app/leader_election/guid_0000000007,创建/app/leader_election/guid_0000000007的节点将观察/app/leader_election/guid_0000000006。
- 如果领导断开,则其相应的/app/leader_election/guid_N被删除。
- 下一个在线从节点将通过观察者获得关于leader移除的通知,下一个在线跟随器节点将检查是否存在具有最小编号的其他znode。如果没有,那么它将承担领导者的角色。否则,它找到创建具有最小编号的znode的节点作为leader。
- 类似地,所有其他跟随节点选择创建具有最小编号的znode作为followers的节点。
为什么最好使用奇数台服务器构成 ZooKeeper 集群?
我们知道在Zookeeper中 Leader 选举算法采用了Zab协议。Zab核心思想是当多数 Server 写成功,则任务数据写成功。
①如果有3个Server,则最多允许1个Server 挂掉。
②如果有4个Server,则同样最多允许1个Server挂掉。
既然3个或者4个Server,同样最多允许1个Server挂掉,那么它们的可靠性是一样的,所以选择奇数个ZooKeeper Server即可。
# Zookeeper事务
在ZooKeeper中,能改变ZooKeeper服务器状态的操作称为事务操作。一般包括数据节点创建与删除、数据内容更新和客户端会话创建与失效等操作。对应每一个事务请求,ZooKeeper都会为其分配一个全局唯一的递增编号,用ZXID表示,通常是一个64位的数字。每一个 ZXID对应一次更新操作,从这些 ZXID 中可以间接地识别出 ZooKeeper 处理这些事务操作请求的全局顺序。
# Zookeeper Watcher事件监听器
事件监听器是ZooKeeper 中一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。
# Zookeeper可以做什么
# 命名服务
不同机器/服务之间,可以通过约定好path,通过path实现互相探索发现
# 配置管理
程序总是需要配置的,如果程序分散部署在多台机器上,要逐个改变配置就变的苦难。如果把这些配置全部放到zookeeper上去,保存在zookeeper的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会受到zookeeper的通知,然后从zookeeper获取新的配置信息应用到系统中就好。
# 集群管理
集群管理有两个核心点: 是否有机器退出/加入 、选举master
对于第一点,所有机器约定在父目录GroupMembers下创建临时目录节点,然后监听父目录节点的子节点变化消息。一点有机器挂掉,该机器与zookeeper的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知。对于第二点,在第一点的基础上,即在创建临时目录接电视,按照加入顺序进行编号,每次选取编号最小的机器作为master就好。
# 分布式锁
有了zookeeper的一致性文件系统,锁的问题变得容易,我们可以讲zookeeper上的一个znode看做一把锁,通过createznode的方式来实现,所有客户端都去创建/distribute_lock节点,最终成功创建的那个客户端也即拥有了这把锁,用完删掉自己创建的distribute_lock节点就释放出锁。
# 总结
Zookeeper具备以下特性:
- ZooKeeper是有一个leader,多个follower组成的集群,只要半数以上节点存活,ZooKeeper 就能正常服务
- ZooKeeper 将数据保存在内存中,这也就保证了 高吞吐量和低延迟,同样由于内存限制了能够存储的容量不太大,此限制也是保持znode中存储的数据量较小的进一步原因
- 全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的 分布式读写,更新请求转发,由leader实施更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
- 数据更新原子性,一次数据更新要么成功,要么失败
- 实时性,在一定时间范围内,client能读到最新数据