Zookeeper 集群搭建
部署环境
操作系统 Debian 11.5.0
运行环境 OpenJDK-1.8.0_332 64-Bit Server VM
Zookeeper版本:3.8.0
官方介绍
Zookeeper官方文档地址(下载的zip压缩包中\docs目录也自带文档):ZooKeeper: Because Coordinating Distributed Systems is a Zoo (apache.org)
ZooKeeper 是一种用于分布式应用程序的分布式开源协调服务。它公开了一组简单的基元,分布式应用程序可以基于这些基元来实现更高级别的同步、配置维护以及组和命名服务。它被设计为易于编程,并使用根据文件系统熟悉的目录树结构设置样式的数据模型。它以 Java 运行,并具有 Java 和 C 的绑定。
ZooKeeper 的实施非常重视高性能、高可用性、严格有序的访问。ZooKeeper 的性能方面意味着它可以在大型分布式系统中使用。可靠性方面使其不会成为单点故障。严格的排序意味着可以在客户端上实现复杂的同步基元。
从官方的介绍中可以得出结论,Zookeeper其实主要是作用于 meta 信息存储,配置信息同步,高性能,高可用,没有单点故障应用服务。
个人理解
中文翻译:动物园管理员。原因是 Apache 的项目都是一些动物的 Logo 设计与命名,所以 Zookeeper的 Logo 像一个铲屎官,还拿着一把铲子(doge)。Zookeeper本身架构设计得也很简单,容易上手。
首先 Apache-Zookeeper 也是 Apache Hadoop整个架构中的一员,在Hadoop架构中担任统一配置管理,域名服务,重点数据存储等功能的中间件。
Zookeeper=文件系统+通知机制。
Zookeeper (以下简称ZK) 本身存储数据的方式就类似于Key-Value形式,只不过ZK中数据是以Znode方式存储,类似于Linux中的文件系统管理,Key都是文件路径的方式表达,有多级目录。其实就和Redis中的Key是一样的,只不过redis中的Key用:符号进行分级,ZK完全使用Linux中的/符号进行分级。ZK的数据是存储在内存中,并持久化了在硬盘中,在内存中维护这个Znode的树状数据结构(文件系统)。
数据结构
但是ZK的Value则没有提供丰富的数据结构(不像Redis提供了很多的数据结构,list,set,hashmap,zset,string),ZK的 Value只有 String 类型,并且ZK的定位本来就不是数据库,它设计出来只是为了存储架构中的关键配置信息与通知,同步,所以每个Znode最大存储数据为1M。
Znode类型
1、持久节点
持久节点创建后,只要不人为执行Delete命令删除,则一直存在。
2、临时节点
临时节点依赖连接客户端的会话,创建后,如果客户端一直保持连接,则临时节点一直存在,如果客户端连接断开,则清除临时节点(有没有感觉到它的作用?是不是特别适合做注册中心的功能,Dubbo启动则连接,宕机则删除Znode节点,并通知其他客户端)
3、顺序节点
创建顺序节点则会自动在节点路径后面添加10位的数字作为计时器。
例如我创建 /node 顺序节点
则 file path 则是:/node0000000001
下次再次创建 /node 节点会继续在计算器后面 +1 并创建新的Znode节点(旧的/node0000000001不会删除也保留)
则 file path 则是:/node0000000002
但当计数器的大小超过2147483647时,将会发生溢出。
4、临时顺序节点
临时节点的特性+顺序节点特性。
ZK特性
- 顺序一致性 - 来自客户端的更新将按其发送顺序应用。
- 原子性 - 更新成功或失败。无部分结果。
- 单个系统映像 - (全局数据一致)集群中每个Service都保存着相同的数据副本,无论Client连接到哪个Service,数据都是一致的【虽然理论上是一致的,但是在数据同步过程中还是会出现某些时刻不一致,不过可以通过sync命令解决】。
- 可靠性 - 应用更新后,它将从该时间开始一直存在,直到客户端覆盖更新。
- 及时性 - 保证系统的客户端视图在特定时间范围内是最新的。
其中原子性是通过ZAB协议进行保证的,Zab协议的全称是 Zookeeper Atomic Broadcast (Zookeeper原子广播)
ZAB 协议
ZAB有两种模式:一种是消息广播模式,另一种是崩溃恢复模式。
消息广播模式:
在 Zookeeper 集群中数据副本的传递策略就是采用消息广播模式,Zookeeper 中的数据副本同步方式与2PC方式相似但却不同,2PC是要求协调者必须等待所有参与者全部反馈ACK确认消息后,再发送 commit 消息,要求所有参与者要么全成功要么全失败,2PC方式会产生严重的阻塞问题。
而 Zookeeper 中 Leader 等待 Follower 的 ACK 反馈是指:只要半数以上的 Follower 成功反馈即可,不需要收到全部的 Follower 反馈,这样可以减少等待时间。
崩溃恢复模式:
一旦 Leader 服务器出现崩溃或者由于网络原因导致 Leader 服务器失去了与过半 Follower 的联系,那么就会进入崩溃恢复模式。
集群搭建(5节点)
ZK的集群最少需要3节点,并且ZK的集群节点需要是奇数节点个数,可以容忍宕机的数量是 节点数/2 。3台则可以容忍一台宕机继续提供服务,5台可以容忍2台宕机继续提供服务,遵循的是过半节点正常,整个集群则继续可以对外提供服务。
ZK集群中的三种角色:
Leader (领导者):
整个集群中只有一个节点可以选举为Leader,并且只有Leader可以进行写操作。(这样的设计注定ZK的写入性能将会成为瓶颈,不过大部分都是内存操作,且每个Znode节点数据量很小,仍然可以保存较高的写入性能。)
Follow (跟随者):
Follow 在集群中可以有多个,并且要和Leader保持心跳连接,该节点不能写只能读,在Leader节点宕机时需要参与新的Leader选举投票。
Observer(观察者):
Observer节点在整个集群中是最边缘的存在,只能读。不能参与Leader选举。为什么需要Observer这样的角色呢,因为ZK集群的写入操作需要半数以上的Follow同步确认才能够写入成功,那么当ZK集群中节点越多时,ZK集群的写入性能越低。为了在提升ZK集群的读能力的同时不影响写入性能,故此设计了Observer这样的节点存在。Observer只负责同步Leader中的数据,并提供读操作。
根据官方给出的ZK集群数量性能图,我们可以看到,随着节点数量增加,ZK集群处理的请求数也有上升。但个人觉得准确点的话应该是读能力有上升,写能力应该会下降。毕竟节点越多Leader写入数据时需要通过ZAB协议同步其他Follow节点确认,只有半数Follow节点同步数据成功才能算写入成功,这样节点数量增加必然写能力下降(这种设计也说明ZK不适合大量写入场景,官方给出的读写比例最好为7:3或8:2)。
配置 zoo.cfg (教程跳过了下载和解压)
解压zip压缩包后,进入conf文件下 修改 zoo_sample.cfg 名称为 zoo.cfg 或 copy 一份出来命名为 zoo.cfg 文件。
修改zoo.cfg 中得部分默认配置,最重要的是修改 dataDir 文件夹路径。ZK默认存放是tmp路径下,但Linux系统会不定时清空该临时目录。所以我们需要改到其他文件夹路径下。
修改完成之后记得保存。我设置的地址为 /opt/zookeeper/data ,后续几个节点都要设置。
创建 myid 文件
在修改的 dataDir 路径文件夹下创建 myid 文件。
并在文件夹中写入当前节点的唯一标识ID。
并且后续几个节点都设置自身节点对应的标识ID,不能重复。
配置 zoo.cfg
在每个节点的 zoo.cfg 中加入 server 节点的地址:
service.1 中 1代表着myid中的标识,后续的值可以写节点ip也可以写hostname,其中2888端口用于同步数据,3888端口用于选举投票。
启动所有节点
如果只启动了半数以下节点则集群不会提供任何服务:
抛出异常无法连接ZK,所以需要把所有节点全部启动。
当所有节点都成功启动后:
可以继续通过 zkServer.sh 下的 status 状态命令查看当前节点角色以及启动状态。
通过 zkCli.sh 连接集群,并执行命令测试是否正常:
再到其他节点进行命令测试:
一切正常,至此最简单的ZK集群已经搭建成功,本次搭建集群是基于最简单的搭建流程,后续可以通过修改配置继续调优整个集群细节,并添加ssl通讯与密码加强整个集群的安全性。
风险实验
我们把测试力度继续加深,停掉其中的 Leader 节点,查看集群是否会自动选举出新的 Leader 节点。
找到 Leader 节点后 关闭该节点服务。
当前 Leader 节点为 debian4 服务器, 我们立即执行 zkServer.sh stop 命令关闭其 ZK 服务。
通过 zkServer.sh status 命令查看 debian5 服务器已被选举为新的 Leader 节点。表示集群选举一切正常。