1.Zookeeper功能和特性
2.节点类型四种!四种!四种!
3.命令简单介绍
3.1 服务端命令
3.2 客户端命令
4.Curator --Zookeeper的api
4.1 创建连接
4.2 增删改查
4.3 Watch 监听事件
4.4 分布式锁
5.Zookeeper 集群介绍
5.1 leader选举
5.2 伪集群部署经验
5.3 集群发生问题的时候节点变化(集群数量为3台的情况)
5.4 zookeeper中的角色(3种)
1.Zookeeper功能和特性
特点:分布式、开源、树形目录
功能:配置管理、分布式锁、集群管理
这边就不介绍安装,安装很简单没什么特别的步骤,配置一个zoo.cfg
2.节点类型四种!四种!四种!
命令看不懂看下面基本命令的介绍
节点类型 | 命令操作 |
持久节点 | create 节点路径 不可以一直执行因为节点路径是唯一的 |
临时节点 | create -e 节点路径 不可以一直执行因为节点路径是唯一的 但是quit之后这个节点就没了 |
持久话顺序节点 | create -s 节点路径 这个命令是可以一直执行的,因为这个节点后面是有数字再自增 |
临时顺序节点 | create -es 节点路径 这个命令是可以一直执行的,因为这个节点后面是有数字再自增 但是quit之后这个节点就没了 |
3.命令简单介绍
3.1 服务端命令
./zkServer.sh status | 查看Zookeeper状态 |
./zkServer.sh start | 开启 |
./zkServer.sh stop | 关闭 |
./zkServer.sh restart | 重启 |
3.2 客户端命令
./zkCli.sh -server localhost:2181 | 连接zookeeper服务器 |
quit | 断开服务器 |
ls | 查看某个节点的信息 |
create 你的节点路径 你的节点值 create 你的节点路径 | 创建节点注意前面都是有空格的 例如create /yasuo hasai 可以不写值后面再set |
get 你的节点路径 | 获取节点信息 |
set 你的节点路径 | 给节点设置值 |
delete 你的节点路径 | 删除节点,如果有子节点删不了 |
deleteall 你的节点路径 | 如果有子节点,也删除 |
help | 帮助 |
ls -s 节点路径 | 可以查看该节点的属性,这个非常关键,后面会用到这些值。 |
4.Curator --Zookeeper的api
当然还有其他api这边只介绍Curator
4.1 创建连接
private CuratorFramework curatorFramework1;
public void testconConnect(){
/**
* Create a new client
*
* @param connectString 地址和端口
* @param sessionTimeoutMs 会话超时
* @param connectionTimeoutMs 连接超时
* @param retryPolicy 重试策略
* @return client
*/
String connectString="localhost:2181";
int sessionTimeoutMs = 60*1000;//这个是默认值
int connectionTimeoutMs = 15*1000;
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);
//第一种连接方式
// CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connectString, sessionTimeoutMs, connectionTimeoutMs, retryPolicy);
// curatorFramework.start();
//第二种连接方式
curatorFramework1 = CuratorFrameworkFactory.builder()
.connectString(connectString)
.sessionTimeoutMs(sessionTimeoutMs)
.sessionTimeoutMs(connectionTimeoutMs)
.retryPolicy(retryPolicy).namespace("yxlm").build();
//这边的namespace是命名空间,以后操作这个节点下面的子节点不用加这个空间节点
curatorFramework1.start();
}
4.2 增删改查
这边比较重要的可以看一下,修改逻辑的version还有删除逻辑的回调的的用法。
//增加节点,注意这边会加上namepace的路径
String yasuo = curatorFramework1.create().forPath("/yasuo");
//增加并设置值
String laoba = curatorFramework1.create().forPath("/laoba","嗨嗨嗨".getBytes());
//这边的withmode 就是-e -s -es 的枚举类型
String laoba2 = curatorFramework1.create().withMode(CreateMode.EPHEMERAL).forPath("/laoba2");
//创建多级节点必须这样搞
String shitouren = curatorFramework1.create().creatingParentsIfNeeded().forPath("/yxlm/shitouren");
//查询节点
byte[] bytes = curatorFramework1.getData().forPath("/yasuo");
//这边查询的是根节点,但是我们前面设置的namespace
List<String> strings = curatorFramework1.getChildren().forPath("/");
//节点状态信息
Stat stat = new Stat();
//创建多级节点
curatorFramework1.getData().storingStatIn(stat).forPath("/app4/zhangxin");
//获取里面的一个属性
System.out.println(stat.getVersion());
//修改数据
curatorFramework1.setData().forPath("/yasuo","哈撒ki".getBytes());
//带着版本改,因为怕多个线程同时改一笔数据,就不好管控
Stat stat = new Stat();
//创建多级节点
curatorFramework1.getData().storingStatIn(stat).forPath("/yasuo");
//withversion会带看现在是第几个版本,改完会自动加一,修改带版本
curatorFramework1.setData().withVersion(6).forPath("/yasuo","哈撒ki1111".getBytes());
System.out.println(stat.getVersion());
//删除的时候,可能会出现删不掉的情况,比如网络问题啊啥的,但是加上guaranteed就一定会删掉
curatorFramework1.delete().guaranteed().forPath("/");
curatorFramework1.delete().guaranteed().inBackground((CuratorFramework client, CuratorEvent event)->{
System.out.println("被删除了,我需要做点什么");
//这边可以根据client和event的值进行相关的逻辑操作
}).forPath("/");
4.3 Watch 监听事件
例如发布订阅啥的功能,都是根据这个功能实现的 三种监听的方法
//监听某个节点的变化
public void testNodeCach() throws Exception {
//监听客户端和路径
NodeCache nodeCache = new NodeCache(curatorFramework1,"/");
nodeCache.getListenable().addListener(()->{
//变化了,监听
System.out.println("变化了");
byte[] data = nodeCache.getCurrentData().getData();
//获取数据
System.out.println(new String(data));
});
//这边开启线程
nodeCache.start();
while(true){
}
}
//监听子节点的变化,自身的变化无感知
public void testPathChildrenCache() throws Exception {
//监听客户端和路径
PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework1,"/",true);
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
System.out.println(pathChildrenCacheEvent);
//可以根据这个里面的信息进行相关操作
}
});
//这边开启线程
pathChildrenCache.start();
while(true){
}
}
//监听自己和子节点
public void testTreeCache() throws Exception {
//监听客户端和路径
TreeCache treeCache = new TreeCache(curatorFramework1,"/");
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
System.out.println(treeCacheEvent);
}
}
);
//这边开启线程
treeCache.start();
while(true){
}
}
4.4 分布式锁
概念:跨机器线程之间的数据同步问题
一般做分布式锁有三种,数据库层面,redis,zookeeper。
zookeeper分布式锁原理
分布式锁案例 --卖票
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import java.util.concurrent.TimeUnit;
//这边肯定是要加上一个锁对象,
// 这边直接用分布式锁,但是锁对象是现成的
public class SellTicket {
private static int num = 20;
private static String connectString="ip:2181";
private static int sessionTimeoutMs = 60*1000;//这个是默认值
private static int connectionTimeoutMs = 15*1000;
private static RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);
private static InterProcessMutex lock = null;
static {
CuratorFramework yxlm = CuratorFrameworkFactory.builder()
.connectString(connectString)
.sessionTimeoutMs(sessionTimeoutMs)
.sessionTimeoutMs(connectionTimeoutMs)
.retryPolicy(retryPolicy).namespace("yxlm").build();
//这边必须要启动如果不启动,会报错!
yxlm.start();
lock= new InterProcessMutex(yxlm,"/yasuo");
}
public static void main(String[] args) {
new Thread(()->{
while (true){
try {
lock.acquire(3, TimeUnit.SECONDS);
if(num>0)
{
num--;
System.out.println(Thread.currentThread().getName()+num);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
//释放
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(()->{
try {
lock.acquire(30, TimeUnit.SECONDS);
if(num>0)
{
num--;
System.out.println(Thread.currentThread().getName()+num);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
//释放
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
5.Zookeeper 集群介绍
5.1 leader选举
zookeeper 自己有独特的算法,影响的参数呢serviceId和zxid 数值越大,那么成为leader的几率越大。成为leader必须投票,zookeeper启动的时候算法就开始计算,第一台启动投给自己,第二台启动的时候会和一比较然后算出中间较大的,成为leader看总数,如果一台机器超过半数的票,就成为leader后面的机器也不会投票或者成为leader。如果有5台机器,那么获得三票的自动成为leader。
5.2 伪集群部署经验
这边主要就是zoo.cfg 文件的配置里面
// 这边我只是拿出一个zookeeper的zoo.cfg 来举例
//不同zookeeper 不一样的clientPort、dataDir
dataDir=/zookeeper-cluster/zk1/data
clientPort=2182
//下面是一样的每个文件都要配置相同数量的事server.xxxx
//我之前一个文件配置一个疯狂有问题
server.1=localhost:2881:3881
server.2=localhost:2882:3882
server.3=localhost:2883:3883
5.3 集群发生问题的时候节点变化(集群数量为3台的情况)
假设有三台机器,那么就会有一个leader和两个follower机器
如果其中一台follower挂了不影响使用,如果两台follower都挂了,那么剩下的一台将会进入休眠模式。如果其中一个follower启动了将会恢复leader的使用
但是如果leader挂了两台follower会重新选举一个leader,如果一主一从都挂了,那么剩下的那一台也会进入休眠状态
5.4 zookeeper中的角色(3种)
角色名称 | 角色功能 |
leader领导者 | 处理事务请求,然后把更改信息的同步到各个follower和observer的节点上 |
follower追随者 | 处理非事务请求,有投票权 |
observer观察者 | 处理事务请求,主要是分担追随者的压力 |