1、zookeeper简介
zookeeper(以下简称ZK)是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop、Hbase、Kafka、Jstorm等开源软件的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。ZK的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
2、zk集群安装(集群安装是奇数台)
ZK既可单节点运行,也可以多节点集群运行。生产环境都采用集群的方式,避免单节点故障。ZK需要java环境,要确保系统有jdk 1.7或更高版本。安装JDK这里就不演示了,我自己在虚拟机上安装,就安装了3个节点
https://zookeeper.apache.org/releases.html
我安装的版本是zookeeper-3.4.10,我解压到/app/soft目录下了
3、配置
zookeeper conf目录下有zoo_sample.cfg实例配置文件,复制这个文件,重命名为zoo.cfg,开始配置zoo.cfg的内容:
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg
tickTime=2000 ##Client-Server通信心跳时间,单位是毫秒
initLimit=10 ##集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数
syncLimit=5 ##集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数
clientPort=2181 ## 监听端口
maxClientCnxns=100 ## 最大连接数
dataDir=/app/soft/zookeeper-3.4.10/data ## 数据目录
dataLogDir=/app/soft/zookeeper-3.4.10/log ## 日志目录
server.1=192.168.34.128:2888:3888 ## zk节点1
server.2=192.168.34.129:2888:3888 ## zk节点2
server.3=192.168.34.130:2888:3888 ## zk节点3
在/app/soft/zookeeper-3.4.10/下创建两个文件夹,分别是data和log
然后分别在zk节点,/app/soft/zookeeper-3.4.10/data目录下,创建文本myid,内容分别是1、2、3序号
192.168.34.128 对应的是1
192.168.34.129 对应的是2
192.168.34.130 对应的是3
4、启动zk
启动之前,jdk7以上的版本一定要安装合适,然后在环境变量里配置ZK_HOME
然后在SecureCRT里同时打开三个节点
执行命令:zkServer.sh start,这里的zkServer.sh是zookeeper bin目录下的脚本
看到这个结果不一定启动成功了,然后执行zkServer.sh status 查看各个zk节点的状态,如果看到一个leader,其它两个节点都是follower说明启动成功了。
还可以通过查看jps命令去查看是否启动了zk
zkServer.sh stop是停掉zk节点服务的,到这里zk的启动就没有问题了!!!
5、zk选举leader
前面说到搭建zk集群节点是奇数台,因为只有是奇数它,它才能选举出谁是leader,谁是follwer,是通过前面配置的myid决定的,三个节点依次配置了1、2、3,服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是等待状态, 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它,所以服务器1,2还是继续保持等待状态,服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader。
6、zk使用
启动zk之后,在任意一台服务上,运行:zkCli.sh进入zk的命令行模式
zk创建的节点叫znode,znode四种节点类型:持久节点、持久序列节点、暂时节点、暂时序列节点。
create -e /app 111 创建一个暂时的znode节点
create -s /app/test1 222 创建一个持久的,带有序列号的znode节点
get /app/test 得到创建的节点中的数据
执行ls /可以看到根节点下面所有子节点
ls /app/test watch 监听这个节点下的变化,我在另一个服务器下也打开了zk的命令行,
然后我在其它服务上,在这个节点下做创建节点的操作
会发现监听的服务器上会弹出下面消息,是对这个节点做出改变的通知
7、通过java代码来创建节点、修改节点内容、监听等
创建一个maven项目
pom.xml引入zk的jar包
4.0.0
zookeeperDemo
zookeeperDemo
1.0
org.apache.zookeeper
zookeeper
3.4.10
junit
junit
4.12
然后创建一个类
package cn.dl.zookeeper;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Tiger on 2018/7/5.
*/
public class ZookeeperClient {
//连接的zk服务
private static final String CONNECTION_HOSTS = "192.168.34.128:2181,192.168.34.128:2181,192.168.34.128:2181";
//超时连接的时间
private static final int SESSION_TIMEOUT = 2000;
private static ZooKeeper zooKeeper = null;
//servers根目录
private volatile static String serviceRootNode = "/services";
//服务器列表
/**使用volatile的意义
* 1、通过在总线加LOCK#锁的方式
* 2、通过缓存一致性协议
* 1.volatile关键字的两层语义
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2)禁止进行指令重排序。
* */
private static volatile List serviceList = new ArrayList();
static {
try {
zooKeeper = new ZooKeeper(CONNECTION_HOSTS, SESSION_TIMEOUT, new Watcher() {
/**
* 监听服务器列表的变化
* */
public void process(WatchedEvent watchedEvent) {
try {
getServerList();
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取服务器列表
* */
public static void getServerList() throws Exception {
List nodes = zooKeeper.getChildren(serviceRootNode,true);
//清空服务器列表信息list集合
serviceList.clear();
for(String node : nodes){
/**
* 这里的第二个参数:false,意思是已经获到了连接,不需要重新获取连接
* */
byte[] data = zooKeeper.getData(serviceRootNode + "/"+ node,false,null);
serviceList.add(new String(data));
}
System.out.println(serviceList);
}
public static void main(String[] args) throws Exception {
ZookeeperClient zookeeperClient = new ZookeeperClient();
zookeeperClient.getServerList();
Thread.sleep(Long.MAX_VALUE);
}
}
package cn.dl.zookeeper;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Tiger on 2018/6/30.
*/
public class ZookeeperDemo {
//连接的zk服务
private static final String CONNECTION_HOSTS = "192.168.34.128:2181,192.168.34.128:2181,192.168.34.128:2181";
//超时连接的时间
private static final int SESSION_TIMEOUT = 2000;
private static ZooKeeper zooKeeper = null;
static {
try {
zooKeeper = new ZooKeeper(CONNECTION_HOSTS, SESSION_TIMEOUT, new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println(watchedEvent.getPath()+";"+watchedEvent.getState());
try {
//获取对根目录节点数据的监控
zooKeeper.getChildren("/",true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/*
判断当前节点是否存在
*/
public Stat isExistZnode(String path) throws Exception{
Stat stat = zooKeeper.exists(path,true);
return stat;
}
/*
创建节点
*/
@Test
public String createZnode(String path, Object object, ArrayList zooDefs, CreateMode createMode) throws Exception {
return zooKeeper.create(path,object.toString().getBytes(),zooDefs,createMode);
}
/*
修改节点
*/
@Test
public Stat updateZnode(String path, Object object, int version) throws Exception {
return zooKeeper.setData(path,object.toString().getBytes(),version);
}
/*
删除节点
*/
@Test
public void deleteZnode(String path,int version) throws Exception {
zooKeeper.delete(path,version);
}
@Test
public static void main(String[] args) throws Exception{
ZookeeperDemo zookeeperDemo = new ZookeeperDemo();
//创建节点
if(zookeeperDemo.isExistZnode("/Tiger") == null){
zookeeperDemo.createZnode("/Tiger","oh,my sky", ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
}else {
System.out.println("znode exist!!!");
}
//更新节点内容
Stat stat = zookeeperDemo.isExistZnode("/Tiger");
if(stat != null){
System.out.println(stat.getVersion());
zookeeperDemo.updateZnode("/Tiger","oh,my sky",stat.getVersion());
}else{
System.out.println("znode not exist !!!");
}
//删除节点
Stat deleteStat = zookeeperDemo.isExistZnode("/Tiger1");
if(deleteStat != null){
zookeeperDemo.deleteZnode("/Tiger1",deleteStat.getVersion());
}
//获取根节点下所有子节点,遍历获取对应节点的数据
List znodes = zooKeeper.getChildren("/",true);
for(String path : znodes){
System.out.println(path+">>>"+new String(zooKeeper.getData("/"+path,true,new Stat())));
}
}
}
zk的安装、简单使用就这些了,这是本人自己的理解,有什么不对的地方欢迎来吐槽!!!