Zookeeper

功能

1.为客户端管理少量数据,key=value形式,key是路径(节点),values是字符串,
例子:

/a "helloworld"

2.为客户端监听指定节点的状态,就是上述的key

使用场景

1.多台服务器,共有相同配置文件,可以将配置文件放在zookeeper中,更改zookeeper中的配置文件,zookeeper就可以自动通知多台服务器
2.服务器的上线和下线感知.服务器启动时向zoo注册ip,port等信息,客户端启动向zoo请求服务器的信息,如果某台服务器挂掉,zoo会发消息给客户端

安装zookeeper

删除安装包里的srcdocs文件夹

1.修改配置文件
conf/zoo_sample.cfg 改为conf/zoo.cfg

# 修改
dataDir=/root/zkdata # 修改数据存储路径,要自己新建,生成文件myid,内容为对应服务器编号(1,2,3)
# 添加
server.1=ip1:2888:3888  # 最好是奇数台
server.2=ip2:2888:3888  # 端口3888是投票选leader,2888是投票后用来通信的
server.3=ip3:2888:3888

到ip1上新建目录/root/zkdata,并新建文件myid内容为1
到ip2上新建目录/root/zkdata,并新建文件myid内容为2
到ip3上新建目录/root/zkdata,并新建文件myid内容为3

配置文件修改完后,将安装包拷贝给ip2 和ip3

2.建立存储文件
到ip1上,新建数据目录/root/zkdata,生成一个文件myid,内容为1
到ip2上,新建数据目录/root/zkdata,生成一个文件myid,内容为2
到ip3上,新建数据目录/root/zkdata,生成一个文件myid,内容为3

3.启动zookeeper
bin/zkServer.sh start 会有QuorumPeerMain进程启动
bin/zkServer.sh status 查看状态,会有mod指明是leader还是flower

我们杀死任何一台机器的zookeeper,就会重新生成新的leader

一键启动脚本

for host in ip1 ip2 ip3
do
echo "${host}:${1}ing...."
ssh $host "source /etc/profile;/root/usr/local/zookeeper/bin/zkServer.sh ${1}" # ssh非正常登陆,不会加载profile文件,所以要手动加载
done

命令行客户端

ZooKeeper -server host:port cmd args
        stat path [watch]
        set path data [version]
        ls path [watch]
        delquota [-n|-b] path
        ls2 path [watch]
        setAcl path acl
        setquota -n|-b val path
        history
        redo cmdno
        printwatches on|off
        delete path [version]
        sync path
        listquota path
        rmr path
        get path [watch]
        create [-s] [-e] path data acl
        addauth scheme auth
        quit
        getAcl path
        close
        connect host:port
方法描述
lsls / 查看节点
getget /zookeeper 获得节点数据
createcreate /a "hellozoo" 创建节点(key) 和数据(value)
rmrrmr /a 删除节点
setset /a "hizoo" 更改节点内容
watchget /a watch 监听a节点内容,只起到一次作用

ls /a watch 监听节点变化

例子:

  1. 数据一致性
[zk: localhost:2181(CONNECTED) 2] create /a "hellozoo"
Created /a
[zk: localhost:2181(CONNECTED) 3] get /a
"hellozoo"
cZxid = 0x100000002
ctime = Thu Nov 07 22:15:19 EST 2019
mZxid = 0x100000002
mtime = Thu Nov 07 22:15:19 EST 2019
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 0
[zk: localhost:2181(CONNECTED) 4] set /a "hellohaddoop"
cZxid = 0x100000002
ctime = Thu Nov 07 22:15:19 EST 2019
mZxid = 0x100000003
mtime = Thu Nov 07 22:15:50 EST 2019
pZxid = 0x100000002
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 14
numChildren = 0

dataVersion 每更改一次都会计数
dataLength 数据的长度
numChildren 子节点数量

2.监听

`ls /a watch` 监听节点变化,其他端口更改了节点,会受到消息,一次性
`get /a watch` 监听节点变化,其他端口更改了节点内容,会受到消息,一次性

node多种类型

create [-s] [-e] path data acl

1、PERSISTENT 持久的:创建者就算跟集群断开联系,该类节点也会持久存在与zk集群中
2、EPHEMERAL 短暂的:创建者一旦跟集群断开联系,zk就会将这个节点删除
3、SEQUENTIAL 带序号的:这类节点,zk会自动拼接上一个序号,而且序号是递增的

组合类型:
PERSISTENT :持久不带序号
EPHEMERAL :短暂不带序号
PERSISTENT 且 SEQUENTIAL :持久且带序号
EPHEMERAL 且 SEQUENTIAL :短暂且带序号

javaAPI

依赖:

zookeeper-3.4.6.jar
/lib/jline-xxx.jar
/lib/log4j-xxx.jar
/lib/netty-xxx.jar
/lib/slf4j-api-xxx.jar
/lib/slf4j-log4j12-xxx.jar

增删改查

package demo;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;

public class ZookeeperClientDemo {
	ZooKeeper zk = null;
	@Before
	public void init()  throws Exception{
		// 构造zookeeper的客户端对象,第一个参数传入多个值,以防某个几点挂掉
		zk = new ZooKeeper("ip1:2181,ip2:2181,ip3:2181", 2000, null);
	}
	
	@Test //增
	public void testCreate() throws Exception{
		// 要创建的节点路径  ;数据  ;访问权限  ;节点类型
		String create = zk.create("/zoo", "hello zoo".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		System.out.println(create);
		zk.close();
	}
	
	@Test  //改
	public void testUpdate() throws Exception {
		// 节点路径  ;数据   ;所要修改的版本,-1代表任何版本
		zk.setData("/zoo", "hello".getBytes("UTF-8"), -1);
		zk.close();
	}
	
	
	@Test	//查
	public void testGet() throws Exception {
		// ;节点路径    ;是否要监听    ;所要获取的数据的版本,null表示最新版本
		byte[] data = zk.getData("/zoo", false, null);
		System.out.println(new String(data,"UTF-8"));
		zk.close();
	}
	
	@Test	//查
	public void testListChildren() throws Exception {
		// 节点路径    ;是否要监听   
		List<String> children = zk.getChildren("/zoo", false);
		for (String child : children) {
			System.out.println(child);
		}
		zk.close();
	}
	
	@Test //删
	public void testRm() throws InterruptedException, KeeperException{
		zk.delete("/zoo", -1);
		zk.close();
	}
}

监听

package demo;
import java.util.List;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;

public class ZookeeperWatchDemo {
	ZooKeeper zk = null;
	@Before
	public void init() throws Exception {
		// 构造一个连接zookeeper的客户端对象
		zk = new ZooKeeper("ip1:2181,ip2:2181,ip3:2181", 2000, new Watcher() {
			@Override
			public void process(WatchedEvent event) {
				//先判断是否是新建,如果是新建状态则不回调
				if (event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeDataChanged) {
					System.out.println(event.getPath()); // 收到的事件所发生的节点路径
					System.out.println(event.getType()); // 收到的事件的类型
					System.out.println("内容更改了"); // 收到事件后,我们的处理逻辑
		
					try {
						zk.getData("/zoo", true, null);

					} catch (KeeperException | InterruptedException e) {
						e.printStackTrace();
					}
					//判断子节点发生变化的回调
				}else if(event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeChildrenChanged){
					System.out.println("子节点变化了..");
				}
			}
		});
	}

	@Test
	public void testGetWatch() throws Exception {
		byte[] data = zk.getData("/zoo", true, null); // 监听节点数据变化
		List<String> children = zk.getChildren("/zoo", true); //监听节点的子节点变化事件
		System.out.println(new String(data, "UTF-8"));
		Thread.sleep(Long.MAX_VALUE);//不能zk.close(),关闭后不能监听,也不能什么也没有,运行完会自动关闭,所以要sleep,如果有消息来回zk会再启动一个线程
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值