深入了解Zookeeper系列
1.zookeeper安装(单机环境)
1.1下载zookeeper的安装包、虚拟机、Centos7.0
https://pan.baidu.com/s/17q50LFPGSyP7d3iN3G4nsA
密码(554y)
1.2 用SecureCRT 上传文件
-
Alt+p 进入sftp
-
lpwd 查看硬盘共享文件目录
-
lcd 修改硬盘共享文件目录
-
put 上传文件
sftp> lpwd
D:/Worke Software/SecureCRT/SecureCRT
sftp> lcd E:/
sftp> lpwd
E:/
sftp> put zookeeper-3.4.10.tar.gz
1.3解压zookeeper
tar -zxvf
zookeeper-3.4.10.tar.gz
1.4复制修改配置文件
cd到zookeeper-3.4.10/conf 目录下,copy一份zoo.cfg
cp
zoo_sample.cfg zoo.cfg
1.5启动zookeeper
- cd到zookeeper-3.4.10/bin目录下:
- sh zkServer.sh start 启动
- sh zkServer.sh stop 关闭
- sh zkServer.sh restart 重启
- sh zkServer.sh status 查看当前服务状态
- tail -f zookeeper.out 查看日志
- sh zkCli.sh 打开zookeeper客户端(进行节点维护)
2..zookeeper安装(集群环境)
本文用的是三台虚拟服务器:ip分别为192.168.255.128;192.168.255.129;192.168.255.130.
三台服务器的配置方法相同1.zookeeper安装(单机环境),之后的配置也相同如下:
2.1 配置三台服务器的zoo.cfg文件(在文件后加)
server.1=192.168.255.128:2888:3888
server.2=192.168.255.129:2888:3888
server.3=192.168.255.130:2888:3888
解释:
server.id=ip:port:port
id的取值范围: 1~255;
用id来标识该机器在集群中的机器序号
ip:三台服务器的ip
2888是zookeeper的端口;
3888表示leader选举的端口
2.2配置myid(服务器对应的id)
在根目录tmp目录下建立zookeeper文件夹 在zookeeper文件夹下创建myid文件
vi myid 并且写入1
解释:写入的1是上配置zoo.cfg对应的id所以
192.168.255.128服务器配置 vi myid 并且写入1
192.168.255.129服务器配置 vi myid 并且写入2
192.168.255.130服务器配置 vi myid 并且写入3
2.3关闭防火墙
centos6.0
查看防火墙状态:service iptables status
关闭防火墙:chkconfig iptables off #开机不启动防火墙服务
centos7.0
(默认是使用firewall作为防火墙,如若未改为iptables防火墙,使用以下命令查看和关闭防火墙)
查看防火墙状态:firewall-cmd –state
关闭防火墙:systemctl stop firewalld.service
2.4分配启动服务
3.配置文件讲解
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
-
- tickTime=2000 zookeeper中最小的时间单位长度 (ms)
- initLimit=10 follower节点启动后与leader节点完成数据同步的时间
- syncLimit=5 leader节点和follower节点进行心跳检测的最大延时时间
- dataDir=/tmp/zookeeper 表示zookeeper服务器存储快照文件的目录
- dataLogDir 表示配置 zookeeper事务日志的存储路径,默认指定在dataDir目录下
- clientPort 表示客户端和服务端建立连接的端口号: 2181
4.
客户端脚本
a.执行命令
sh zkCli.sh
b.输出如下信息表示成功链接
WatchedEventstate:SyncConnected type:None path:null
[zk:localhost:2181(CONNECTED) 0]
c.链接指定的
zookeeper
服务请可以用如下命令
sh zkCli.sh –server ip
:
port
4.
1
zookeeper
的命令操作
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
注意:因为
zookeeper
没有
cd
命令,这里的
path
指的是节点的全路径,
1.新增(
create
)
create [-s] [-e] path dataacl
-s
表示节点是否有序
-e
表示是否为临时节点
默认情况下,是持久化节点
2.删除(
delete
)
delete path [version]
注意:删除父节点一定要先删除子节点
3.修改(
set
)
set path data [version]
修改节点
path
对应的
data
注意:修改后
stat
中的版本信息会改变
4.查看(
ls
和
get
)
ls path [watch]
注意
zookeeper
没有
cd
命令所以需要查看子目录需要子目录的全路径
ls /father/son
get path [watch]
获得指定
path
的信息
4.2 stat
信息(
zookeeper
维护节点的数据结构)
[zk: localhost:2181(CONNECTED) 18] stat /father
cZxid = 0x100000018 节点被创建时的事务ID
ctime = Mon Jun 04 17:50:32 CST 2018
mZxid = 0x100000018 节点最后一次被更新的事务ID
mtime = Mon Jun 04 17:50:32 CST 2018
pZxid = 0x400000005 当前节点下的子节点最后一次被修改时的事务ID
cversion = 1 子节点的版本号
dataVersion = 0表示的是当前节点数据的版本号
aclVersion = 0 表示acl的版本号,修改节点权限
ephemeralOwner = 0x0创建临时节点的时候,会有一个sessionId 。 该值存储的就是这个sessionid
dataLength = 3 数据值长度
numChildren = 1 子节点数
5.java API
的使用
5.1导入jar包
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
5.2用java api实现zookeeper的基本操作,并建立监听事件
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
/**
* @author zpoison
* @data 2018/6/6/006 15:39
*/
public class Exist_API_sync_Usage implements Watcher {
private final static String CONNECTSTRING ="192.168.255.128:2181,192.168.255.129:2181,"
+"192.168.255.130:2181";
private static CountDownLatch countDownLatch=new CountDownLatch(1);
private static ZooKeeper zk;
private static Stat stat=new Stat();
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
String path = "/zk-book";
zk=new ZooKeeper(CONNECTSTRING, 5000, new Exist_API_sync_Usage());
//确保链接成功
countDownLatch.await();
//判断path节点是否存在并开启Watcher(监听事件)
zk.exists(path,true);
//创建节点
zk.create(path,"1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
//修改节点数据
zk.setData(path,"2".getBytes(),-1);
//创建子节点
zk.create(path+"/c1","3".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
//删除子节点
zk.delete(path+"/c1",-1);
//删除节点
zk.delete(path,-1);
Thread.sleep(Integer.MAX_VALUE);
}
@Override
public void process(WatchedEvent watchedEvent) {
//如果当前的连接状态是连接成功的,那么通过计数器去控制
if( watchedEvent.getState() == Event.KeeperState.SyncConnected ){
System.out.println("watched状态-->"+watchedEvent.getType());
if(Event.EventType.None==watchedEvent.getType()&&null==watchedEvent.getPath()){
countDownLatch.countDown();
System.out.println(watchedEvent.getState()+"-->"+watchedEvent.getType());
}else if(watchedEvent.getType()== Event.EventType.NodeDataChanged){
try {
System.out.println("数据变更触发路径:"+watchedEvent.getPath()+"->改变后的值:"+
new String(zk.getData(watchedEvent.getPath(),true,stat)));
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else if(watchedEvent.getType()== Event.EventType.NodeChildrenChanged){//子节点的数据变化会触发
try {
System.out.println("子节点数据变更路径:"+watchedEvent.getPath()+"->节点的值:"+
new String(zk.getData(watchedEvent.getPath(),true,stat)));
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else if(watchedEvent.getType()== Event.EventType.NodeCreated){//创建节点的时候会触发
try {
System.out.println("节点创建路径:"+watchedEvent.getPath()+"->节点的值:"+
new String(zk.getData(watchedEvent.getPath(),true,stat)));
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else if(watchedEvent.getType()== Event.EventType.NodeDeleted){//节点删除会触发
System.out.println("节点删除路径:"+watchedEvent.getPath());
}
}
}
}
输出结果:
watched状态-->None
SyncConnected-->None
watched状态-->NodeCreated
节点创建路径:/zk-book->节点的值:1
watched状态-->NodeDataChanged
数据变更触发路径:/zk-book->改变后的值:2
watched状态-->NodeDeleted
节点删除路径:/zk-book
通过上面的案例的到如下结论:
无论子点节点是否存在,通过调用exists接口都可以注册Watcher。
exists接口中注册的Watcher,能够对节点创建、节点删除和节点数据更新事件进行监听
对于指定子节点的各种变化,都不会通知客户端
6.权限控制
在zookeeper的实际应用中,我的做法往往是搭建一个公用的集群,统一为若干个应用提供服务。在这种情况下,不同的应用之间 往往是不会存在共享数据的使用场景的,因此需要权限解决不同应用的问题。
参考《从Paxos到Zookeeper 分布式一致性原理与实践》