安装比较简单,请参考之前的文章:https://www.yuque.com/tianyunperfect/ygzsw4/igckr3
定义:
- 分布式、开源的协调框架
- 文件系统+通知机制
- Leader+N个Follower
基础
架构图
集群特点

- Zookeeper:一个领导者Leader,多个跟随者Follower组成的集群。
- 集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。
- 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
- 更新请求顺序进行,来自同一个Client的更新请求按其发送顺序依次执行。
- 数据更新原子性,一次数据更新要么成功,要么失败。
- 实时性,在一定时间范围内,Client能读到最新数据。
数据结构
整体上可以看作是一棵树, 每个节点称做一个ZNode。每一个ZNode默认能够存储1MB的数据, 每个ZNode都可以通过其路径唯一标识。
集群配置

命令操作
应用场景
统一命名服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于识别。
例如:IP不容易记住,而域名容易记住。
统一配置管理
可将配置信息写入ZooKeeper上的一个Znode,各个客户端服务器监听这个Znode
一旦Znode中的数据被修改, ZooKeeper将通知各个客户端服务器
统一集群管理
监控每个节点的状态
要点
选举机制
- 半数机制
- 一个Leader和N个Follower,启动的时候先选自己,没有达到半数则选id最大的。

节点类型
- 持久(Persistent):客户端和服务器端断开连接后, 创建的节点不删除
- 短暂(Ephemeral):客户端和服务器端断开连接后, 创建的节点自己删除(-e)
- 还可以多一个选项:是否带编号(-s)
create -s /sanguo "meinv"
监督原理

常见的监听:
ACL(Access Control List)访问控制列表
包括三个方面:
权限模式(Scheme)
(1)IP:从 IP 地址粒度进行权限控制
(2)Digest:最常用,用类似于 username:password 的权限标识来进行权限配置,便于区分不同应用来进行权限控制
(3)World:最开放的权限控制方式,是一种特殊的 digest 模式,只有一个权限标识“world:anyone”
(4)Super:超级用户
授权对象
授权对象指的是权限赋予的用户或一个指定实体,例如 IP 地址或是机器灯。
权限 Permission
(1)CREATE:数据节点创建权限,允许授权对象在该 Znode 下创建子节点
(2)DELETE:子节点删除权限,允许授权对象删除该数据节点的子节点
(3)READ:数据节点的读取权限,允许授权对象访问该数据节点并读取其数据内容或子节点列表等
(4)WRITE:数据节点更新权限,允许授权对象对该数据节点进行更新操作
(5)ADMIN:数据节点管理权限,允许授权对象对该数据节点进行 ACL 相关设置操作
Java操作Zookeeper
简单操作
import lombok.SneakyThrows;import org.apache.zookeeper.*;import org.apache.zookeeper.data.Stat;import org.junit.Before;import org.junit.Test;import org.springframework.test.context.junit.jupiter.EnabledIf;import java.io.IOException;import java.util.List;/*** @Description* @Author 田云* @Date 2020/12/12 19:48* @Version 1.0*/public class BaseTest {private String connectString = "127.0.0.1:2181";private int sessionTimeout = 2000;private ZooKeeper zooKeeper;@Beforepublic void init() throws IOException {this.zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@SneakyThrows@Overridepublic void process(WatchedEvent event) {getChildrenAndWatch();}});}/*** 创建节点** @throws KeeperException* @throws InterruptedException 中断异常*/@Testpublic void createNode() throws KeeperException, InterruptedException {String path = this.zooKeeper.create("/alvin","为学者日益".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);System.out.println(path);}@Testpublic void getChildrenAndWatch() throws KeeperException, InterruptedException {System.out.println("---start---");List<String> children = zooKeeper.getChildren("/", true);children.forEach(System.out::println);System.out.println("---end---");}@Testpublic void longSleep() throws InterruptedException, KeeperException {getChildrenAndWatch();Thread.sleep(Long.MAX_VALUE);}/*** 节点是否存在** @throws KeeperException* @throws InterruptedException 中断异常*/@Testpublic void nodeExist() throws KeeperException, InterruptedException {Stat exists = zooKeeper.exists("/test", false);System.out.println(exists);}}
服务器节点动态上下线的案例
- 服务端:连接、注册 ``` import org.apache.zookeeper.*;
import java.io.IOException; import java.util.concurrent.ThreadLocalRandom;
/**
- 分发服务器 *
- @Description
- @Author 田云
- @Date 2021/3/20 10:44
@Version 1.0 */ public class DistributeServer { private static String connectString = “127.0.0.1:2181”; private static int sessionTimeout = 2000; private ZooKeeper zkClient = null;
private String parentNode = “/servers”;
// 创建到 zk 的客户端连接 public void getConnect() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent event) {}});
}
// 注册服务器 public void registServer(String hostname) throws Exception {
String create = zkClient.create(parentNode + "/server",hostname.getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);System.out.println(hostname + " is online " + create);
}
// 业务功能 public void business(String hostname) throws Exception {
System.out.println(hostname + " is working ...");Thread.sleep(Long.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
// 1 获取 zk 连接DistributeServer server = new DistributeServer();server.getConnect();// 2 利用 zk 连接注册服务器信息server.registServer(args[0]);// 3 启动业务功能server.business(args[0]);
} } ```
- 客户端:连接、监听 ``` import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper;
import java.io.IOException; import java.util.ArrayList; import java.util.List;
/**
- @Description
- @Author 田云
- @Date 2021/3/20 10:50
@Version 1.0 */ public class DistributeClient { private static String connectString = “127.0.0.1:2181”; private static int sessionTimeout = 2000; private ZooKeeper zkClient = null;
private String parentNode = “/servers”;
// 创建到 zkClient 的客户端连接 public void getConnect() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent event) {// 再次启动监听try {getServerList();} catch (Exception e) {e.printStackTrace();}}});
}
// 获取服务器列表信息 public void getServerList() throws Exception {
// 1 获取服务器子节点信息,并且对父节点进行监听List<String> children = zkClient.getChildren(parentNode, true);// 2 存储服务器信息列表ArrayList<String> servers = new ArrayList<>();// 3 遍历所有节点,获取节点中的主机名称信息for (String child : children) {byte[] data = zkClient.getData(parentNode + "/" + child, false, null);servers.add(new String(data));}// 4 打印服务器列表信息System.out.println(servers);
}
// 业务功能,为了让程序存在 public void business() throws Exception {
System.out.println("client is working ...");Thread.sleep(Long.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
// 1 获取 zk 连接DistributeClient client = new DistributeClient();client.getConnect();// 2 获取 servers 的子节点信息,从中获取服务器信息列表client.getServerList();// 3 业务进程启动client.business();
} } ```
dubbo的provider就是一个目录
ls /dubbo/com.alvin.service.UserService/providers
[dubbo://192.168.124.6:20880/com.alvin.service.UserService?anyhost=true&application=xxx-provider&bean.name=ServiceBean:com.alvin.service.UserService&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.alvin.service.UserService&methods=getUser&pid=38490®ister=true&release=2.7.3&side=provider×tamp=1616205719481, dubbo://192.168.124.6:20881/com.alvin.service.UserService?anyhost=true&application=xxx-provider&bean.name=ServiceBean:com.alvin.service.UserService&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.alvin.service.UserService&methods=getUser&pid=38522®ister=true&release=2.7.3&side=provider×tamp=1616205720860]
