前提:需在集群中运行,这里准备了三台机器node1,node2,node3
第一步:一键启动zookeeper的shell脚本(onekey_zk.sh)
#!/bin/bash
echo "你要进行什么zk操作?"
PS3="你选择的操作是:"
select var in "start" "stop" "status"
do
for i in 1 2 3
do
echo "----------------------node$i---------------------------------"
ssh root@node$i "source /etc/profile;zkServer.sh $var"
done
break
done
echo "--------------提示:Zookeeper集群 $var 操作成功!-----------------"
注:需要将集群中的机器全部开启才能查看状态
第二步:直接zkCli.sh,进入本机zookeeper,加上-sever node1/node2/node3,可以连接指定主机,quit退出
#查看节点
ls / #查看根目录节点
ls /app1 #查看app1目录下的节点
#创建永久节点,永久存在,需要手动删除
create /app1 null
#创建永久顺序节点,可以重复创建,因为会自动加上编号,永久存在,需要手动删除
create -s /app1 null
#创建临时节点,依赖当前会话,会话结束,节点会被删除
create -e /app1 null
#创建临时顺序节点,依赖当前会话,会话结束,节点会被删除
create -s -e /app1 null
#创建子节点
create /app1/app2 null
create -s /app1/app2 null
#注:临时节点不存在子节点
#获得节点数据
get /app1
get /app1/app2
#修改节点数据
set /app1
set /app1/app2
#删除叶子节点,被删的节点下没有子节点
delete /app1
#递归删除节点,被删的节点下有子节点
rmr /app1
zookeeper的watch机制
#在第一个zk的客户端执行命令
get /app1 watch #回车之后zk会自动监控/app1节点
#在第二个zk客户端执行命令
set /app1 hello #修改节点数据
zookeeper的JavaAPI操作
pom.xml
<dependencies>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
代码
package pack01_zookeeper;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class Demo1Zookeeper {
public CuratorFramework client;
@Before
public void init(){
//制定一个重试策略
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 3);
//获取一个客户端对象
client = CuratorFrameworkFactory.newClient("node1:2181,node2:2181,node3:2181", retryPolicy);
//开启客户端
client.start();
}
@After
public void close(){
//关闭客户端
client.close();
}
//watch机制
@Test
public void watchDemo() throws Exception {
//将要监听的节点树存入缓存中
TreeCache treeCache = new TreeCache(client, "/master");
//自定义监听
treeCache.getListenable().addListener(new TreeCacheListener() {
//childEvent方法是自动调用,只要你的/app1节点有状态变化,则就会自动执行该方法
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
//因为不管是:增加/删除/修改节点,都会执行该方法,但是具体是因为哪一种才执行该方法,则需要进一步确认
switch (treeCacheEvent.getType()) {
case NODE_ADDED:
System.out.println("监控到增加节点事件!");
System.out.println("有客户端上线了!");
break;
case NODE_REMOVED:
System.out.println("监控到节点移除事件!");
System.out.println("主节点挂掉了!");
System.out.println("让备用节点称为新的主节点!");
break;
case NODE_UPDATED:
System.out.println("监控到节点修改事件!");
//重新读取配置文件
break;
case CONNECTION_SUSPENDED:
break;
case CONNECTION_RECONNECTED:
break;
case CONNECTION_LOST:
break;
case INITIALIZED:
break;
}
}
});
//开启监听
treeCache.start();
//让程序挂起
while (true);
//Thread.sleep(100000000);
}
//删除节点
@Test
public void deleteZnode() throws Exception {
client.delete().forPath("/app4"); //只能删除叶子节点
client.delete().deletingChildrenIfNeeded().forPath("/app1"); //递归删除
}
//获取节点属性
/*@Test
public void getZnodeAttr(){
client.getState()
}*/
//获取节点数据
@Test
public void getZnode() throws Exception {
byte[] bytes = client.getData().forPath("/app1");
String str = new String(bytes);
System.out.println(str);
}
//修改节点数据
@Test
public void setZnode() throws Exception {
//修改节点数据
client.setData().forPath("/app1","xxxxxx".getBytes());
}
//创建节点
@Test
public void createZnode() throws Exception {
//创建节点
//client.create().forPath("/app1"); //情况1:没有数据,没有节点类型,默认创建永久节点
//client.create().creatingParentsIfNeeded().forPath("/app1/app1_1"); //情况2:创建多级节点
//client.create().creatingParentsIfNeeded().forPath("/app1/app1_2","hello".getBytes()); //情况3:创建多级节点,并且携带数据
client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/app3","hello".getBytes()); //创建制定类型节点,并携带数据
//Thread.sleep(10000000L);
}
}
zookeeper的应用场景
1、主机状态监控
通过创建临时节点和会话关系,来判断主机的健康状态
2、发布和订阅
3、分布式锁
4、注册中心
服务提供者 服务消费者
5、分布式数据共享
zookeeper的选举机制
1、场景1: 启动ZK,需要选举Leader
node1启动 投自己1票 和其他主机交换投票信息,系统判断投票数是否过半,否
node2启动 投自己1票 和其他主机交换投票信息,系统判断投票数是否过半,是,谁的myid最大,就是Leader node3启动 投自己1票 和其他主机交换投票信息,发现已经有Leader了,直接成为Follower
启动顺序: node3 ndoe2 node1 ----》node3就是leader
2、场景2:ZK运行的过程中,Leader挂掉,需要选举Leader
2.1 当Leader挂掉之后,系统会判断剩余的主机是否过半,是,则开始选举新Leader,否,则直接终止整个集群
2.2 如果剩余的主机过半,则开始选举新Leader
a:比较哪台主机的数据最新,如果某台主机的数据最新,则直接当选Leader
b:如果所有主机的数据都是一样新的,则谁的myid最大,谁就是Leader