目录
一、Zookeeper概念
配置中心的作用:注意在这里,如果我们没有使用配置中心,当我们需要获取数据库资源的时候,A\B\C需要分别获取,这样的话一旦数据库发生改变,我们就需要分别给A\B\C进行修改,如果我们当前的服务器更多的话,要修改的岂不是更多!
分布式锁的使用:当我们当前有个服务A获取到了资源,这个时候多个线程访问服务A的时候,我们怎么保证数据的正确性?----加锁。但是如果当前除了服务A还有服务B也获得了资源,那么加锁就没用了,因为当前的资源可以在服务A上也可以在服务B上被修改,那么这个时候就需要加分布式锁了,当服务A需要访问的时候,就先找分布式锁要,如果当前空闲,就可以分配给A,不空闲A就只可以等待!
二、Zookeeper下载与安装
zookeeper下载与安装详解【linux单机】一定会安装_young_man2的博客-CSDN博客
三、Zookeeper的操作
1. 命令操作
1.1 Zookeeper的数据模型
1.2 Zookeeper服务端常用命令
1.3 zookeeper客户端常用命令
./zkCli.sh localhost:2181 #连接本地
quit #退出
ls / #进入客户端之后使用此命令查看下面的子包
create /app1 +数据 #创建子节点app1
get /app1 #获取子节点
set /app1 +数据 #设置数据
delete /app1 #删除子节点,只可以删除空节点
deleteall /app1 #删除所有节点,可以不为空
help #帮助命令
create -e /app1 #创建一个临时节点app1 当前退出之后,临时节点被关闭
create -s /app1 #创建一个顺序节点app1,有编号的
create -es /app1 #创建一个临时的顺序节点
ls -s /app1 #查看节点app1的详细信息
2. API操作
2.1 Curator的介绍
●Curator 是Apache ZooKeeper的Java客户端库.
●常见的ZooKeeper Java API :
原生Java API
ZkClient
Curator
●Curator项目的目标是简化ooKeeper客户端的使用。
●Curator最初是Netfix研发的,后来捐献了Apache基金会,目前是Apache的顶级项目。
2.2 Curator API的常用操作
1. 建立连接
package com.wxy.curator;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.Test;
public class CuratorTest {
/*
* 建立连接
* */
@Test
public void testConnect(){
/*
* 这里我们需要将curator和zk进行连接,我们就需要要使用CuratorFramework,但是他是接口,所以我们只能使用
* 它的工厂方法CuratorFrameworkFactory
* */
//第一种方式
/*
* 四个参数
* 1. 连接字符串 zk server地址和端口
* 2. 会话超时时间 单位是毫秒
* 3. 连接超时时间
* 4. 超市策略
* */
RetryPolicy retryPolicy=new ExponentialBackoffRetry(3000,10);
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.122.1", 60 * 1000, 15 * 1000, retryPolicy);
//开启链接
client.start();
//第二种方式
//CuratorFrameworkFactory.builder()
/* CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("192.168.122.1").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy);
CuratorFramework build = builder.build();
build.start();*/
CuratorFramework client1 = CuratorFrameworkFactory.builder().connectString("192.168.122.1").
sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy).namespace("wxy").build();
//这里添加namespace就会默认下次创建会在这个目录(节点)下进行创建,可以简化代码
client1.start();
}
}
连接成功后如下显示
2. 添加节点
package com.wxy.curator;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
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 CuratorTest {
private CuratorFramework client;
/*
* 建立连接
* */
@Before
public void testConnect(){
/*
* 这里我们需要将curator和zk进行连接,我们就需要要使用CuratorFramework,但是他是接口,所以我们只能使用
* 它的工厂方法CuratorFrameworkFactory
* */
//第一种方式
/*
* 四个参数
* 1. 连接字符串 zk server地址和端口
* 2. 会话超时时间 单位是毫秒
* 3. 连接超时时间
* 4. 超市策略
* */
RetryPolicy retryPolicy=new ExponentialBackoffRetry(3000,10);
client = CuratorFrameworkFactory.newClient("192.168.122.1", 60 * 1000, 15 * 1000, retryPolicy);
//开启链接
client.start();
//第二种方式
//CuratorFrameworkFactory.builder()
/* CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("192.168.122.1").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy);
CuratorFramework build = builder.build();
build.start();*/
CuratorFramework client1 = CuratorFrameworkFactory.builder().connectString("192.168.122.1").
sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy).namespace("wxy").build();
//这里添加namespace就会默认下次创建会在这个目录(节点)下进行创建,可以简化代码
client1.start();
}
@Test
public void testCreate1() throws Exception {
//1. 创建节点,带有数据
String path = client.create().forPath("app2","hello".getBytes());
System.out.println(path);
}
@Test
public void testCreate2() throws Exception {
//2. 基本创建
//如果创建节点的时候没有传输数据,默认将ip数据传输进来
String path = client.create().forPath("/app1");
System.out.println(path);
}
@Test
public void testCreate3() throws Exception {
//3. 设置节点的类型
String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("app2","hello".getBytes());
System.out.println(path);
}
@Test
public void testCreate4() throws Exception {
//4. 设置多级节点
//平常是不允许直接创建多级节点的,因为此时app3不存在,需要使用creatingParentsIfNeeded()
String path = client.create().creatingParentsIfNeeded().forPath("/app3/s1");
System.out.println(path);
}
@After
public void close(){ //释放资源
if(client!=null){
client.close();
}
}
}
3. 删除节点
/*******************************delete****************************************/
/*
* 删除节点 delete deleteall
*1. 删除单个节点
*2. 删除带有子节点的节点
*3. 必须成功的删除
*4. 回调
* */
@Test
public void testDelete1() throws Exception {
//1. 删除单个节点
client.delete().forPath("/app1");
}
@Test
public void testDelete2() throws Exception {
//2. 删除带有子节点的节点
client.delete().deletingChildrenIfNeeded().forPath("/app1");
}
public void testDelete3() throws Exception {
//3. 必须成功的删除
client.delete().guaranteed().forPath("/app1");
}
public void testDelete4() throws Exception {
//4. 回调
client.delete().guaranteed().inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
}
}).forPath("/app1");
}
4. 修改节点
@Test
public void testSet() throws Exception {
//修改数据
client.setData().forPath("/app1","hahha".getBytes());
}
@Test
public void testSetForVersion() throws Exception {
//根据版本修改
Stat stat=new Stat();
client.getData().storingStatIn(stat).forPath("/app1");
int version=stat.getVersion();
client.setData().withVersion(version).forPath("/app1","hahha".getBytes());
}
5. 查找节点
/**************************************Get****************************************************/
/*
* 查询节点
* 1. 查询子节点
* 2. 查询数据
* 3. 查询节点状态信息 *
* */
@Test
public void testGet1() throws Exception {
//1. 查询数据
byte[] bytes = client.getData().forPath("/app1");
}
@Test
public void testGet2() throws Exception {
//2. 查询子节点
List<String> strings = client.getChildren().forPath("/app4");
System.out.println(strings);
}
@Test
public void testGet3() throws Exception {
//2. 查询节点状态信息
Stat stat=new Stat();
client.getData().storingStatIn(stat).forPath("/app1");
}
6. watch事件监听
6.1 NodeCache监听某一个特定的节点
package com.wxy.curator;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
public class CuratorTest {
private CuratorFramework client;
/*
* 建立连接
* */
@Before
public void testConnect() {
/*
* 这里我们需要将curator和zk进行连接,我们就需要要使用CuratorFramework,但是他是接口,所以我们只能使用
* 它的工厂方法CuratorFrameworkFactory
* */
//第一种方式
/*
* 四个参数
* 1. 连接字符串 zk server地址和端口
* 2. 会话超时时间 单位是毫秒
* 3. 连接超时时间
* 4. 超市策略
* */
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
client = CuratorFrameworkFactory.newClient("192.168.122.1", 60 * 1000, 15 * 1000, retryPolicy);
//开启链接
client.start();
//第二种方式
//CuratorFrameworkFactory.builder()
/* CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("192.168.122.1").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy);
CuratorFramework build = builder.build();
build.start();*/
CuratorFramework client1 = CuratorFrameworkFactory.builder().connectString("192.168.122.1").
sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy).namespace("wxy").build();
//这里添加namespace就会默认下次创建会在这个目录(节点)下进行创建,可以简化代码
client1.start();
}
@After
public void close(){ //释放资源
if(client!=null){
client.close();
}
}
@Test
public void testCacheNode() throws Exception {
//创建NodeCache对象
NodeCache nodeCache=new NodeCache(client,"/app1");
//注册监听
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("节点变化了");
}
});
//开启监听,如果设置为true则开启监听时加载缓存数据
nodeCache.start(true);
}
}
6.2 PathChildrenCache 监控一个ZNode的子节点
package com.wxy.curator;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
public class CuratorTest {
private CuratorFramework client;
/*
* 建立连接
* */
@Before
public void testConnect() {
/*
* 这里我们需要将curator和zk进行连接,我们就需要要使用CuratorFramework,但是他是接口,所以我们只能使用
* 它的工厂方法CuratorFrameworkFactory
* */
//第一种方式
/*
* 四个参数
* 1. 连接字符串 zk server地址和端口
* 2. 会话超时时间 单位是毫秒
* 3. 连接超时时间
* 4. 超市策略
* */
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
client = CuratorFrameworkFactory.newClient("192.168.122.1", 60 * 1000, 15 * 1000, retryPolicy);
//开启链接
client.start();
//第二种方式
//CuratorFrameworkFactory.builder()
/* CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("192.168.122.1").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy);
CuratorFramework build = builder.build();
build.start();*/
CuratorFramework client1 = CuratorFrameworkFactory.builder().connectString("192.168.122.1").
sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy).namespace("wxy").build();
//这里添加namespace就会默认下次创建会在这个目录(节点)下进行创建,可以简化代码
client1.start();
}
@After
public void close(){ //释放资源
if(client!=null){
client.close();
}
}
@Test
public void testPathChildrenNode() throws Exception {
//1. 创建监听对象
PathChildrenCache pathChildrenCache=new PathChildrenCache(client,"/app2",true);
//2. 绑定监听器
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
System.out.println("子节点变化了");
//1. 获取类型
PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
//2. 判断类型是不是update
if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
byte[] data = pathChildrenCacheEvent.getData().getData(); //这里才是我们真正的数据
System.out.println(new String(data));
}
}
});
//3. 开启监听
pathChildrenCache.start();
}
}
3. TreeCache(可以监听整个树上的所有节点)
package com.wxy.curator;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
public class CuratorTest {
private CuratorFramework client;
/*
* 建立连接
* */
@Before
public void testConnect() {
/*
* 这里我们需要将curator和zk进行连接,我们就需要要使用CuratorFramework,但是他是接口,所以我们只能使用
* 它的工厂方法CuratorFrameworkFactory
* */
//第一种方式
/*
* 四个参数
* 1. 连接字符串 zk server地址和端口
* 2. 会话超时时间 单位是毫秒
* 3. 连接超时时间
* 4. 超市策略
* */
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
client = CuratorFrameworkFactory.newClient("192.168.122.1", 60 * 1000, 15 * 1000, retryPolicy);
//开启链接
client.start();
//第二种方式
//CuratorFrameworkFactory.builder()
/* CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("192.168.122.1").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy);
CuratorFramework build = builder.build();
build.start();*/
CuratorFramework client1 = CuratorFrameworkFactory.builder().connectString("192.168.122.1").
sessionTimeoutMs(60 * 1000).connectionTimeoutMs(60 * 1000).retryPolicy(retryPolicy).namespace("wxy").build();
//这里添加namespace就会默认下次创建会在这个目录(节点)下进行创建,可以简化代码
client1.start();
}
@After
public void close(){ //释放资源
if(client!=null){
client.close();
}
}
@Test
public void testTreeCache() throws Exception {
TreeCache treeCache=new TreeCache(client,"/app1");
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
System.out.println("节点变化了");
System.out.println(treeCacheEvent);
}
});
}
}
2.3 分布式锁
为什么创建临时的?
因为如果是持久的,一旦发生宕机,节点就无法删除,锁就不能释放,但是是临时的就可以自己释放
为什么要是顺序的?
因为要找最小的节点
2.4 模拟12306售票
3. 集群
3.1 zookeeper集群搭建
集群搭建请看下面的链接
链接:https://pan.baidu.com/s/12oOu5HOQdwB1Lnc_9lhRvA
提取码:dzdz
3.2 zookeeper集群角色