安装比较简单,请参考之前的文章: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;
@Before
public void init() throws IOException {
this.zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@SneakyThrows
@Override
public void process(WatchedEvent event) {
getChildrenAndWatch();
}
});
}
/**
* 创建节点
*
* @throws KeeperException
* @throws InterruptedException 中断异常
*/
@Test
public void createNode() throws KeeperException, InterruptedException {
String path = this.zooKeeper.create("/alvin",
"为学者日益".getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
System.out.println(path);
}
@Test
public void getChildrenAndWatch() throws KeeperException, InterruptedException {
System.out.println("---start---");
List<String> children = zooKeeper.getChildren("/", true);
children.forEach(System.out::println);
System.out.println("---end---");
}
@Test
public void longSleep() throws InterruptedException, KeeperException {
getChildrenAndWatch();
Thread.sleep(Long.MAX_VALUE);
}
/**
* 节点是否存在
*
* @throws KeeperException
* @throws InterruptedException 中断异常
*/
@Test
public 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() {
@Override
public 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() {
@Override
public 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]