Zookeeper
第一章 Zookeeper入门
概述
zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目
工作机制
zookeeper从设计模式角度来理解:是一个基于观察者模式,它负责和管理大家都关心的数据,然后接受观察者注册,一旦这些数据状态发生变化,zookeeper就将负责通知已经在zookeeper上注册的那些观察者做出响应的反应.
zookeeper=文件系统+通知机制.
特点
1.Zookeeper:一个领导者(Leader),多个跟随着(Follower),组成集群
2.集群中只要有半数以上节点存货,zookeeper集群就能正常的服务
3…全局的数据是一致的:每个server保存一份相同的数据副本,Client无论连接到哪个Server数据都是一致的.
4.更新 请求顺序进行,来自同一个Client的更新请求按其发送顺序进行
5.数据更新原子性,一次数据更新要么成功,要么失败
6.实时性,在一定时间范围内,client能读到最新的数据
数据结构
Zookeeper的数据结构与unix非常相似,整体上可以看作一棵树,每个节点称作一个znode.每个znode默认能够存储1MB数据.每个znode都可以通过其路径唯一标识
应用场景
提供的服务:统一命名服务,统一配置管理,统一集群管理,服务器节点动态上下线,软负载均衡
统一命名服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于识别.
例如:IP不容易记住,而域名容易记住
统一配置管理
1.分布式环境下,配置文件同步是非常常见的
A.一般要求一个集群中,所有的节点的配置信息是一致的
b.对配置的文件修改后,希望能够快速的同步到各个节点上
2.配置文件可以交给zookeeper来做
A.可以将配置的信息写入Zookeeper上的一个Znode
B.各个客户端服务器监听这个znode(监听机制)
对上面的图进行解释:就是我的配置文件信息交给zookeeper管理,我的多个客户端进行读取并且监听这个文件信息的变换,一旦这个配置信息发生变化,客户端就会得到一个通知,然后就是process().写自己的逻辑代码,来处理这个变化.
统一集群管理
1.分布式环境下,实时掌握每个节点的变化是非常有必要的
A.可根据节点的实时状态做出一些响应的调整
2.Zookeeper可以实现实时监控节点状态的变化
A.可将节点信息写入Zookeeper上的一个Znode
B.监听这个Znode可以获取到它的实施状态的变化.
服务器动态上下线
客户端实时观察服务器上下线的变化
软负载均衡
zookeeper的下载
Zookeeper集群的安装
第二章 Zookeeper内部原理
选举机制
1.半数机制:集群中半数以上的集群存货,集群可用,所以zookeeper适合安装奇数
台服务器.
2.zookeeper虽然在配置文件中没有指定master和slave,但是,zookeeper工作时,但是有一个节点为leader的,其他的为follower,Leadder是通过内部选举机制临时产生的
3.简单的例子
假如有五台服务器组成的zookeeper集群,他们的id是从1–5,同时他们都是最新启动的,也就是没有历史数据,在存数量这一点上,都是一样的,假设这些服务器一次启动,来看看会怎么样
过程
1>server1启动,此时只有它一台启动,它发出去的报文没有回应,所以它的选举一直处在LOOKING状态
2>server2启动,此时它与最开始启动的server1进行通信,相互交换自己的选举结果,由于两者都没有历史数据,所以id值较大的server2胜出,但是由于没有达到半数以上,所以它的选举也处在LOOKING状态
3>server3启动,此时它与server1和server2分别交换选举结果,超过半数,称为Leader’
4>server4启动,但是此时分别于server1,2,3交换选举信息,但是发现server3已经成为Leader,所以只能成为Follower
5>和server4一样
节点的类型
持久:持久目录节点
客户端于服务器断开连接,创建的节点不会删除.
1.持久化目录节点
客户端与zookeeper断开连接,该节点依旧存在
2.持久化顺序编号目录节点
客户端与zookeeper断开连接,该节点依旧存在,只是zookeeper给该节点进行顺序编号.
命令
create -s /sanguo/weiguo
结果
Created /sanguo/weiguo0000000005
注意**:创建znode时设置顺序标识,znode名称后会附加一个值,顺序编号是一个单调递增的计数器,有父节点维持
在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端就可以通过顺序号推断事件的顺序.
短暂:临时目录节点
客户端与服务器断开节点,创建的节点自己删除.
1.临时化目录节点
客户端与zookeeper断开连接,该节点依旧不存在
2.临时顺序编号目录节点
客户端与zookeeper断开连接,该节点不存在,只是zookeeper给该节点进行顺序编号.
验证
create -s -e /sanguo/weiguo
结果
Created /sanguo/weiguo0000000006
退出重新进来
quit
./zkCli.sh
ls /sanguo
结果
[shuguo, weiguo0000000002, weiguo0000000003, weiguo0000000005]
发现并不存在 /sanguo/weiguo0000000006节点
注意:顺序号是从临时节点,持久节点顺序号一块使用的.
第三章 zookeeper实际操作
集群的搭建
命令操作
1.启动服务端
./zkserver start
2.启动客户端
./zkCli.sh
3.显示所有操作命令
help
4.查看节点信息
ls path
//节点的详细信息
ls2 path
5.创建两个节点
create path 数据
注意:如果节点上没有数据就会创建失败,还有就是上面创建的是持久节点
6.获得数据
get path
7.创建短暂的数据节点
create -e path 数据
所谓的短暂节点,就是quit之后重新客户端连接服务端,节点就自动删除了.
8.创建带有序号的节点
create -s path 数据
sequence : 顺序
9.监听节点数据(信息)变化,指的是至少两台服务器之间的数据监听
//这个过时了
get path watch
//新的为
get -w path
//例如
get -w /sanguo/shuguo
在另一台服务器上
set path 数据
结果
WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo/shuguo
10.监听路径,即子节点的变化
ls -w path
例如
在zoo_node1上
ls -w /sanguo
在zoo_node2上
create /sanguo/weiguo "caocao"
在zoo_node1上显示的结果是
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/sanguo
注意:监听只有一次有效,下次要想再监听得重新创建.
11.递归删除
rmr path
12.删除节点
delete path
13.help所有的最新命令
addauth scheme auth
close
config [-c] [-w] [-s]
connect host:port
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
delete [-v version] path
deleteall path
delquota [-n|-b] path
get [-s] [-w] path
getAcl [-s] path
history
listquota path
ls [-s] [-w] [-R] path
ls2 path [watch]
printwatches on|off
quit
reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
redo cmdno
removewatches path [-c|-d|-a] [-l]
rmr path
set [-s] [-v version] path data
setAcl [-s] [-v version] [-R] path acl
setquota -n|-b val path
stat [-w] path
sync path
stat结构体
常用的:dataLength-znode的数据长度
numChildren-zndoe子节点的数量
监听器的原理
1.原理详解
1>首先要有一个main()线程
2>在main()线程中创建Zookeeper客户端,这是就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener)
3>t通过connect线程将注册的监听事件发给zookeeper
4>在zookeeper的注册监听器列表中将注册的监听事件添加到列表中
5>zookeeper监听到的数据或路径发生变化,就会将这个消息发送给listener线程
6>listner线程调用内部的process()方法.
2.常见的监听
1>监听节点数据的变化
get -w /path
2>监听子节点增减的变化
ls -w /path
写数据的流程
第四章 实际操作
加依赖
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
创建zkClient
@SpringBootApplication
public class ZookeeperApplication {
private String connecStr = "39.97.252.228:2181,39.97.252.228:2182,39.97.252.228:2183";
private int sessionTimeout = 5000;
private ZooKeeper zkCli;
@Bean
public ZooKeeper zooKeeper(){
ZooKeeper zkClient = null;
try {
zkClient = new ZooKeeper(connecStr, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
} catch (IOException e) {
e.printStackTrace();
}
return zkClient;
}
public static void main(String[] args) {
SpringApplication.run(ZookeeperApplication.class,args);
}
}
添加节点
@SpringBootTest
public class MyTest {
@Autowired
private ZooKeeper zkClient;
/**
* 本测试用于向zookeeper添加节点
* @throws KeeperException
* @throws InterruptedException
* @throws IOException
*/
@Test
public void create() throws KeeperException, InterruptedException, IOException {
String path = zkClient.create("/sanguo/wangguo", "你好世界".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(path);
}
}
总结:上面的参数的意思是:
1.第一个是创建节点的固定格式
create path 数据
2.第二个是数据利String中的getBytes(),把字符串转换成byte[]数组
3.ZooDefs.Ids.OPEN_ACL_UNSAFE:节点权限问题,这里设置为谁都可以读
4CreateMode.PERSISTENT:节点得类型,四种短暂得两种:带序号和不带序号的,持久得两种:带序号和不带序号的.
CreateMode.EPHEMERAL
CreateMode.EPHEMERAL_SEQUENTIAL
CreateMode.PERSISTENT
CreateMode.PERSISTENT_SEQUENTIAL
ephemeral :短暂的
sequential:有序的
persistent:持久的
获取子节点并监视子节点
1.获取子节点
/**
* 本测试用于测试子节点的获得
* @throws KeeperException
* @throws InterruptedException
*/
@Test
public void getChildren() throws KeeperException, InterruptedException {
List<String> nodes = zkClient.getChildren("/", false);
for(String str : nodes){
System.out.println(str);
}
}
结果是
dubbo
zookeeper
sanguo
2.获取并且监视
public class ZkClientLession {
private String connectStr = "39.97.252.228:2181,39.97.252.228:2182,39.97.252.228:2183";
private int sessionTimeout = 5000;
private ZooKeeper zkCli;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
ZkClientLession client = new ZkClientLession();
/**
* 获取zookeeper连接
*/
client.createZkCli();
/**
* 注册监听
*/
client.getChildrenNodes();
/**
* 业务逻辑处理
*/
client.buiness();
}
private void buiness() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
public void getChildrenNodes() throws KeeperException, InterruptedException {
List<String> nodes = zkCli.getChildren("/", true);
for(String str : nodes){
System.out.println(str);
}
}
public void createZkCli() throws IOException {
zkCli = new ZooKeeper(connectStr, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
try {
getChildrenNodes();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
测试
/**
* zookeeper的监听机制
*1>首先要有一个main()线程
* 2>在main()线程中创建Zookeeper客户端,这是就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener)
* 3>t通过connect线程将注册的监听事件发给zookeeper
* 4>在zookeeper的注册监听器列表中将注册的监听事件添加到列表中
* 5>zookeeper监听到的数据或路径发生变化,就会将这个消息发送给listener线程
* 6>listner线程调用内部的process()方法.
*/
@Test
public void getChildrenAndWatch() throws KeeperException, InterruptedException {
List<String> nodes = zkClient.getChildren("/", true);
}
节点是否存在
@Test
public void zkClientExit() throws KeeperException, InterruptedException {
Stat exists = zkClient.exists("/sanguo", false);
System.out.println(exists);
}
服务上下线
服务的注册
三步:
1.连接zookeeper,上面有
2.注册服务,用到的是
create path 数据
java中用到的是create节点,需要注意的是create创建的是临时节点.
3.业务逻辑的处理
服务的使用
三步,简单的网上搜搜看看