【1】Zookeeper基础入门
① Zookeeper是什么
Zookeeper是一个开源的分布式的、为分布式应用提供协调服务的Apache项目。
Zookeeper从设计模式角度来理解,其实是一个基于观察者模式设计的分布式服务管理框架。它负责存储和管理大家都关心的数据,然后接受观察者的注册。一旦这些数据的状态发送变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。从Zookeeper存储数据和通知机制来讲,可以说Zookeeper=文件系统+通知机制。
zookeeper实现服务器节点动态上下线过程描述如下:
- 服务端启动时去注册信息(创建的都是临时节点);
- 客户端获取到当前在线服务器列表,并且注册监听;
- 服务器节点下线;
- 服务器节点上下线事件通知(Zookeeper负责);
- 客户端收到监听通知则做出相应反应,比如重新获取在线服务器列表注册监听。
② Zookeeper集群特点
集群如下图所示:
Zookeeper集群是一个leader和多个follow组成的集群。
集群中只要半数以上节点存活,Zookeeper集群就能正常服务。
全局数据一致,每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的。
更新请求顺序进行,来自同一个Client的更新请求按其发送顺序依次执行。
数据更新原子性,一次数据更新要么成功,要么失败。
实时性,在一定时间范围内,Client能读到最新数据。
③ Zookeeper的数据结构
Zookeeper的数据模型的结构与UNIX文件系统很类似,整体上可以看做是一棵树,每个节点称做一个ZNode。每一个ZNode默认能够存储1MB的数据,每个ZNode可以通过其路径唯一标识。
如下图所示:
④ 应用场景
Zookeeper有诸多应用场景,如统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
- 统一命名服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于区别。例如IP不容易记住而域名容易记住。
- 统一配置管理
分布式环境下,配置文件同步非常常见。一般要求一个集群中,所有节点的配置信息是一致的,比如kafka集群。对配置文件修改后,希望能够快速同步到各个节点上。
配置管理可交由Zookeeper实现:可将配置信息写入Zookeeper上的一个ZNode;每个客户端服务器监听这个ZNode;一旦ZNode中的数据被修改,Zookeeper将通知各个客户端。
- 统一集群管理
分布式环境中,实时掌握每个节点的状态是很必要的,以便可以根据节点实时状态做出一些调整。
Zookeeper可以实现实时监控节点状态的变化:可以将节点信息写入Zookeeper的一个ZNode;监听这个ZNode可获取它的实时状态变化。
- 软负载均衡
在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求。
【2】单击版Zookeeper下载与安装
官网地址:http://zookeeper.apache.org/
下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/
① 本机模式安装Zookeeper
这里下载的是3.5.5版本,将其放到linux某个路径下(这里有个坑,请下载apache-zookeeper-3.5.5-bin.tar.gz,该包可以正常使用。apache-zookeeper-3.5.5.tar.gz是源码包):
注意,安装Zookeeper一定先安装好jdk
安装步骤如下:
- 解压
tar -zxvf apache-zookeeper-3.5.5-bin.tar.gz //或者指定解压目录 tar -zxvf apache-zookeeper-3.5.5-bin.tar.gz -C /home/softinstall
- 修改配置文件(把conf中的zoo_sample.cfg重命名为zoo.cfg)
cd apache-zookeeper-3.5.5/conf mv zoo_sample.cfg zoo.cfg //配置数据路径 mkdir -p /home/softinstall/apache-zookeeper-3.5.5/zkData vim zoo.cfg
② 操作Zookeeper
- 启动Zookeeper服务端
[root@localhost apache-zookeeper-3.5.5-bin]# bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /opt/softinstall/apache-zookeeper-3.5.5-bin/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [root@localhost apache-zookeeper-3.5.5-bin]# jps 27368 QuorumPeerMain 27388 Jps
- 关闭zkserver
bin/zkServer.sh stop
- 查看服务状态
[root@localhost apache-zookeeper-3.5.5-bin]# bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/softinstall/apache-zookeeper-3.5.5-bin/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: standalone //表示单机模式
- 重启Zookeeper服务
//进入目录下 bin/zkServer.sh restart
- 启动客户端
bin/zkCli.sh
- 查看根目录下内容
[zk: localhost:2181(CONNECTED) 2] ls / [zookeeper]
- 退出客户端
[zk: localhost:2181(CONNECTED) 6] quit
【3】Zookeeper配置文件参数解读
配置文件主要参数如下:
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/home/softinstall/apache-zookeeper-3.5.5/zkData # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
① tickTime=2000
该参数含义为通信心跳数 ,Zookeeper服务器端和客户端心跳时间,单位毫秒。2000表示2S一次心跳检测,也就是每个tickTime时间就会发送一个心跳。它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间(session的最小超时时间=2*tickTime)。
② initLimit=10
集群中的follower与leader之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中Zookeeper服务器连接到leader的时限。
10个心跳帧,10*2=20s是最开始通信时leader和follower最大延时时间。如果超过该时间,则认为二者断开通信。
③ syncLimit=5
集群正常启动后集群中leader与follower之间的最大响应时间单位。假如响应时间超过syncLimit*tickTime,leader认为follower死掉,从服务器列表中删除follower。
④ clientPort=2181
客户端与服务端通信的端口号,默认为2181。
⑤ dataDir
zookeeper的数据目录。另外还有日志文件目录默认在../apache-zookeeper-3.5.5-bin/logs下。
【4】利用zookeeper监听服务器动态上下线实例
背景需求如下:某分布式系统中,主节点有多台,可能进行动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线状态。
客户端代码
import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; public class DistributeClient { public static void main(String[] args) throws IOException, KeeperException, InterruptedException { DistributeClient client = new DistributeClient(); // 1 获取zookeeper集群连接 client.getConnect(); // 2 注册监听 client.getChlidren(); // 3 业务逻辑处理 client.business(); } private void business() throws InterruptedException { Thread.sleep(Long.MAX_VALUE); } private void getChlidren() throws KeeperException, InterruptedException { List<String> children = zkClient.getChildren("/servers", true); // 存储服务器节点主机名称集合 ArrayList<String> hosts = new ArrayList<String>(); for (String child : children) { byte[] data = zkClient.getData("/servers/"+child, false, null); hosts.add(new String(data)); } // 将所有在线主机名称打印到控制台 System.out.println(hosts); } private String connectString="127.0.0.1:3181,127.0.0.1:3182,127.0.0.1:3183"; private int sessionTimeout = 2000; private ZooKeeper zkClient; private void getConnect() throws IOException { zkClient = new ZooKeeper(connectString , sessionTimeout , new Watcher() { public void process(WatchedEvent event) { try { getChlidren(); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
服务端代码
import java.io.IOException; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.ZooDefs.Ids; public class DistributeServer { public static void main(String[] args) throws Exception { DistributeServer server = new DistributeServer(); // 1 连接zookeeper集群 server.getConnect(); // 2 注册节点 server.regist(args[0]); // 3 业务逻辑处理 server.business(); } private void business() throws InterruptedException { Thread.sleep(Long.MAX_VALUE); } private void regist(String hostname) throws KeeperException, InterruptedException { //注意,创建的是临时、有序号节点。这样服务器down了节点也就不存在了 String path = zkClient.create("/servers/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println(hostname +"is online "); } private String connectString="127.0.0.1:3181,127.0.0.1:3182,127.0.0.1:3183"; private int sessionTimeout = 2000; private ZooKeeper zkClient; private void getConnect() throws IOException { zkClient = new ZooKeeper(connectString , sessionTimeout , new Watcher() { public void process(WatchedEvent event) { // TODO Auto-generated method stub } }); } }
【5】zookeeper常见命令
① ZK服务端命令
启动ZK服务
sh bin/zkServer.sh start
查看服务状态
sh bin/zkServer.sh status
停止ZK服务
sh bin/zkServer.sh stop
重启ZK服务
sh bin/zkServer.sh restart
② zk客户端命令
ZooKeeper命令行工具类似于Linux的shell环境使用它我们可以简单的对ZooKeeper进行访问,数据创建,数据修改等操作. 使用 zkCli.sh -server 127.0.0.1:2181 连接到 ZooKeeper 服务,连接成功后,系统会输出 ZooKeeper 的相关环境以及配置信息。
命令行工具的一些简单操作如下:
显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
创建文件,并设置初始内容: create /zk “test” 创建一个新的 znode节点“ zk ”以及与它关联的字符串
获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
修改文件内容: set /zk “zkbak” 对 zk 所关联的字符串进行设置
删除文件: delete /zk 将刚才创建的 znode 删除
退出客户端: quit
帮助命令: help
③ ZooKeeper 常用四字命令
ZooKeeper 支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息。用户在客户端可以通过 telnet 或 nc 向 ZooKeeper 提交相应的命令
可以通过命令:echo stat|nc 127.0.0.1 2181 来查看哪个节点被选择作为follower或者leader
使用echo ruok|nc 127.0.0.1 2181 测试是否启动了该Server,若回复imok表示已经启动。
echo dump| nc 127.0.0.1 2181 ,列出未经处理的会话和临时节点。
echo kill | nc 127.0.0.1 2181 ,关掉server
echo conf | nc 127.0.0.1 2181 ,输出相关服务配置的详细信息。
echo cons | nc 127.0.0.1 2181 ,列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。
echo envi |nc 127.0.0.1 2181 ,输出关于服务环境的详细信息(区别于 conf 命令)。
echo reqs | nc 127.0.0.1 2181 ,列出未经处理的请求。
echo wchs | nc 127.0.0.1 2181 ,列出服务器 watch 的详细信息。
echo wchc | nc 127.0.0.1 2181 ,通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。
echo wchp | nc 127.0.0.1 2181 ,通过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路径。