053:Zookeeper快速入门
1 基于Zookeeper实现动态负载均衡课程介绍
课程内容
1.Zookeeper的应用场景有那些
2.Zookeeper基本特性与数据模型
3.ZookeeperACL访问控制列表
4.Zookeeper实现动态负载均衡
2 Zookeeper实际案例中的应用场景
什么是Zookeeper
zookeeper是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
简单来说zookeeper(简称zk)=文件系统+监听通知机制。
Zookeeper应用场景
1.分布式锁
2.Dubbo服务注册(zk)
3.分布式配置中心disconfig
4.分布式消息中间件
5.发布订阅(事件通知)
3 Zookeeper基本的实现的特征
Zookeeper类似文件系统,基本特征:
- 定义的节点包含节点名称和节点内容,节点路径必须保证是唯一,不允许重复
- 每个节点都会有事件通知,当节点发生任何变化都可以获取到对应的信息;
4 基于linux环境安装Zookeeper
安装jdk环境1.8
1.安装jdk
cd /usr/local
上传jdk1.8安装包并解压tar -zxvf jdkxxxx
mv jdkxxxx jdk1.8
2.修改jdk1.8环境变量vi /etc/profile,文件末尾添加以下内容
export JAVA_HOME=/usr/local/jdk1.8
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
刷新profile文件 source /etc/profile
查看java是否安装成功 java -version
Linux环境安装Zookeeper
1.解压zk压缩包
cd /usr/local
上传zk安装包并解压tar -zxvf zookeeperxxxx
tar -zxvf zookeeperxxxx
mv zookeeperxxxx zookeeper
2. 进入到zk目录,在zk目录中创建data和logs文件夹
cd zookeeper
mkdir data
mkdir logs
3.进入到conf目录,修改配置文件
cd conf
mv zoo_sample.cfg zoo.cfg
vi zoo.cfg
dataDir =/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/logs
4.进入bin目录启动zk
./zkServer.sh start
./zkServer.sh status
单机启动成功
关闭防火墙systemctl stop firewalld
使用工具zktools连接
5 Java语言客户端连接Zookeeper
引入依赖
<dependencies>
<!-- java语言连接zk -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.8</version>
</dependency>
</dependencies>
创建节点
public class Test001 {
// 连接地址
private static final String CONNECTIONS = "192.168.0.53:2181";
// 超时时间
private static final int TIMEOUT = 5000;
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
// zk核心:节点+事件通知
// 1.创建zk连接
ZooKeeper zk = new ZooKeeper(CONNECTIONS, TIMEOUT, watchedEvent -> {
Watcher.Event.KeeperState state = watchedEvent.getState();
if (state == Watcher.Event.KeeperState.SyncConnected) {
System.out.println("zk连接成功");
}
});
// 2.创建节点
// 参数1:路径名称
// 参数2:节点value
// 参数3:节点权限acl
// 参数4:节点类型 临时和持久
String s = zk.create("/mayikt", "mayikt".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(s);
zk.close();;
}
}
运行结果:
6 Countdown计算器优化ZK代码
以上代码存在缺陷,如果zk创建失败执行create方法异常
使用CountDownLatch优化代码
public class Test002 {
// 连接地址
private static final String CONNECTIONS = "192.168.0.53:2181";
// 超时时间
private static final int TIMEOUT = 5000;
// 计数器
private static CountDownLatch countDownLatch = new CountDownLatch(1);
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
// zk核心:节点+事件通知
// 1.创建zk连接
ZooKeeper zk = new ZooKeeper(CONNECTIONS, TIMEOUT, watchedEvent -> {
Watcher.Event.KeeperState state = watchedEvent.getState();
if (state == Watcher.Event.KeeperState.SyncConnected) {
System.out.println("zk连接成功");
// 计数器-1
countDownLatch.countDown();
}
});
// 计数器结果为0的情况才能继续执行
System.out.println("zk正在连接等待...");
countDownLatch.await();
System.out.println("开始创建节点");
// 2.创建节点
// 参数1:路径名称
// 参数2:节点value
// 参数3:节点权限acl
// 参数4:节点类型 临时和持久
String s = zk.create("/mayikt2", "mayikt2".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(s);
zk.close();
}
}
只有当zk创建成功,countDownLatch-1变为0,才能继续执行后面的代码,否则情况阻塞等待。
运行结果:
7 Zookeeper四种节点类型
zk节点分为四种类型:
1.临时节点CreateMode.EPHEMERAL
2.持久节点CreateMode.PERSISTENT
3.临时有序号节点(对名字自动做序列自增)CreateMode.EPHEMERAL_SEQUENTIAL
4.持久有序号节点(对名字自动做序列自增)CreateMode.PERSISTENT_SEQUENTIAL
创建节点必须先创建父节点,再创建子节点
8 Zookeeper节点ACL权限控制
ACL权限控制
ACL权限模型,实际上就是对每个节点实现控制
身份的认证有4种方式:
world:默认方式,相当于全世界都能访问
auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)
digest:即用户名:密码这种方式认证,这也是业务系统中最常用的
ip:使用ip地址认证
1.给节点设置权限
public class Test003 {
public static void main(String[] args) throws Exception {
// 1.创建zooKeeper连接
ZooKeeper zooKeeper = new ZooKeeper("192.168.0.53", 500, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println(watchedEvent.getState().name());
}
});
// 2.创建账号权限 admin可以实现读写操作
Id id1 = new Id("digest", DigestAuthenticationProvider.generateDigest("admin:admin123"));
ACL acl1 = new ACL(ZooDefs.Perms.ALL, id1);
// 3.创建权限guest 只允许做读操作
Id id2 = new Id("digest", DigestAuthenticationProvider.generateDigest("guest:guest123"));
ACL acl2 = new ACL(ZooDefs.Perms.READ, id2);
// 4.添加该账号
ArrayList<ACL> aces = new ArrayList<ACL>();
aces.add(acl1);
aces.add(acl2);
// 5.创建该节点
String s1 = zooKeeper.create("/mayikt3", "mayikt3".getBytes(), aces, CreateMode.PERSISTENT);
System.out.println("s1:" + s1);
}
}
运行结果:
此时通过ZooInspector查询不到/mayikt3节点的值。
2.查询该节点必须授权账号
public class Test004 {
public static void main(String[] args) throws Exception {
// 1.创建zooKeeper连接
ZooKeeper zooKeeper = new ZooKeeper("192.168.0.53", 500, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println(watchedEvent.getState().name());//SyncConnected
}
});
// 2.设置zk连接账号
zooKeeper.addAuthInfo("digest", "guest:guest123".getBytes());
byte[] bytes = zooKeeper.getData("/mayikt3", null, new Stat());
String string = new String(bytes);
System.out.println(string);//mayikt3
}
}
9 使用Zookeeper实现服务注册
服务注册
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
// SpringBoot启动成功之后,执行的回调方法
//参数1 连接地址
private static final String ADDRES = "192.168.0.53:2181";
// 参数2 zk超时时间
private static final int TIMEOUT = 50000;
// 计数器
private static CountDownLatch countDownLatch = new CountDownLatch(1);
@Value("${server.port}")
private String serverPort;
@Override
public void run(ApplicationArguments args) throws Exception {
ZooKeeper zooKeeper = new ZooKeeper(ADDRES, TIMEOUT, watchedEvent -> {
Watcher.Event.KeeperState state = watchedEvent.getState();
if (state == Watcher.Event.KeeperState.SyncConnected) {
System.out.println("zk连接成功");
countDownLatch.countDown();
}
});
countDownLatch.await();
// 1. 判断父节点是否存在
String parentPath = "/mayikt-service";
Stat exists = zooKeeper.exists(parentPath, null);
// 2. 创建子节点
if (exists == null) {
// 父节点不存在
zooKeeper.create(parentPath, "mayikt".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
// 3.实现服务注册
String pathValue = "http://127.0.0.1:" + serverPort;
zooKeeper.create(parentPath + "/" + serverPort, pathValue.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL);
System.out.println("服务注册成功" + parentPath);
}
}
运行效果:
10 使用Zookeeper实现服务发现
public class ServiceDiscovery {
private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
ZooKeeper zooKeeper = new ZooKeeper("192.168.0.53:2181", 50000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
Event.KeeperState state = watchedEvent.getState();
// 如果当前连接成功,则开始放心
if (state == Event.KeeperState.SyncConnected) {
System.out.println("zk连接成功~~");
countDownLatch.countDown();
}
}
});
countDownLatch.await();
String path = "/mayikt-service";
// 获取该节点下子集
List<String> children = zooKeeper.getChildren(path, null, new Stat());
for (String c : children) {
String pathChildren = path + "/" + c;
byte[] data = zooKeeper.getData(pathChildren, null, new Stat());
System.out.println("服务接口地址:" + new String(data));
}
/**
* 运行结果:
* zk连接成功~~
* 服务接口地址:http://127.0.0.1:8080
* 服务接口地址:http://127.0.0.1:8081
*/
}
}