1.概述:分布式服务需要完成:相互感知和time同步。zookeeper是基于内存的速度快。每个zookeeper节点的数据结构是一致的,存放的方式是树形结构类似linux文件结构。一个领导和多个跟班,领导挂掉时在开始选举产生一个领导。最终目的是在集群的服务中做协同服务。提供了java和C的客户端链接,可以链接服务集群中的任何一台机器。支持window部署好linux部署2种方式。
2.安装:zookeeper通过对节点数据的操作提前订阅节点,通过反向调用通知客户端进行对应的操作(订阅发布)。安装需要jdk6.0以上,然后下载zookeeper安装包。解压后在/etc/profile中像java环境变量一下配置zookeeperHome,然后在加入到path中,用source profile马上生效。也可在environment中配置,使用gedit更好编辑文本。默认我们应该在/usr/下创建一个soft文件夹,类似于window中的program,用于存放各种用户需要安装的软件。
3.配置:zookeeper支持独立部署、伪分布和完全分布。在zookeeper安装目录下进入conf目录,找到zoo_sample.cfg这是zookeeper的配置文件,复制一个出来取名为zoo.cfg启动时默认使用这个文件中的参数,如果使用其它名称那么在启动zookeeper时需要指定文件。以下是配置文件信息:
ylt@ylt:/usr/soft/zookeeper-3.4.12/conf$ cat zoo.cfg
# The number of milliseconds of each tick 心跳时间,如果2倍这个时间没有回应则session过期
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take follower初始化链接到leader的超时。tickTime的倍数
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement leader链接到follower消息响应限制,超时后follower会被丢弃。
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.一定要创建这个文件夹,而且还需要在该文件夹下创建一个名字为myid文件,文件中只有一个整数,代表当前启动zookeeper的服务编号
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
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
#此处为关键配置,代表有3个服务启动,server名称后的1,2,3这个和myid文件时一一对应的
#server.n=ip:port1:port2 其中n是myid文件中的值,port1是作为leader时follower链接的端口,port2当leader挂掉后其他follower的选举端口,此处最好配置2n+1台服务器
server.1=192.168.135.132:2888:3888
server.2=192.168.135.133:2888:3888
server.3=192.168.135.134:2888:3888
#配置结束。
zkServer.sh start 默认启动
zkServer.sh start zoo1.cfg 指定配置启动
zkServer.sh stop 停止
zkServer.sh status 状态
zkServer.sh restart 重启
4.nc指令使用
模拟tcp,udp网络通信,实现端口扫描
nc -h 查看帮助信息
常用命令:
网络间2台主机通信
nc -l 端口号 这样设置服务端的监听模式(只能监听有一个客户端)
nc ip 端口 这样链接上了服务端,这样就能实现通信
网络间文件传递
nc -l 端口 > kk.txt 服务端使用输出重定向
nc ip 端口 < zoo.log 客户端输入重定向
端口扫描
nc -v -w 2 ip -z 2000-4000扫描端口2000到4000
-v详细信息
-w 链接超时
-z端口扫描
-u端口类型是UDP
5.netstat -at 查看TCP网络端口号信息
netstat -au 查看UDP网络端口号信息
6.4字指令
conf查看配置文件 例:echo conf|nc 192.168.135.133 2181 查看配置
ruok查看zookeeper状态是否可用 例: echo ruok|nc 192.168.135.133 2181 以下以此类推
envi查看zookeeper环境信息
cons 链接数
dump 未处理会话节点
reqs 未处理请求
stat 统计信息
wchs 服务器watch的详细信息
wchp 指定路径下的服务器
7.客户端命令
提供zkCli.sh链接到服务器进行操作,指令进行操作
zkCli.sh -server ip:端口 例:zkCli.sh -server 192.168.135.133:2181
以下是进入后的指令操作:
stat path [watch] #显示节点信息,但是没有子节点数据
set path data [version] #修改或者设置路径数据
ls path [watch] #查看目录下的节点和linux文件系统类似
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 #重新开始链接
8.zookeeper提供java核心API,查看java项目
create()
delete()
exist()
getdata()/setdata()
getACL()/setACL()
getChildren()
sync()
9.ACL 访问控制权限
10.zookeeper事件触发是一次性触发,也就是watcher需要重新激活它
11.zookeeper实现锁功能是使用创建临时节点实现的,比如创建/lock临时节点,多个进程试图去创建该节点谁先创建就获得资源,如果没有创建成功就开始监听该节点,当原来创建进程的会话结束或者删除该节点后其他进程可以收到通知,进一步创建该锁节点。
12.zookeeper工作模式是先在树中建立一套节点规则,然后其他分布式进程关注这些节点变化来执行一些业务。临时节点有2种情况被删除:创建它的进程超时或者关闭,或者其他进程删除该节点。
13.zookeeper客户端jar包括zookeeper自身提供还有引用的第三方jar。
14.zookeeper应用场景:统一命名服务(默认create中),统一配置管理,集群管理,负载均衡,共享锁,队列管理
15.zookeeper客户端api调用有同步和异步调用,同步调用需要处理异常,尤其是网络异常。异步调用不需要处理异常,异常已经被封装为返回码rc中。推荐使用异步方法进行。以下列出标准的回调处理模板:
AsyncCallback.StringCallback createCallback = new AsyncCallback.StringCallback() {
@Override
public void processResult(int rc, String path, Object ctx, String name) {
switch (KeeperException.Code.get(rc)){
case CONNECTIONLOSS://多关注这个异常,因为这个异常是网络问题没有执行成功,需要重新再调用一次之前的函数
runForMaster();
break;
case NODEEXISTS:
break;
case OK:
break;
default:
LOG.error("Something went wrong when running for master.",
KeeperException.create(KeeperException.Code.get(rc), path));
}
}
};
注意:在zookeeper中api的异步调用不管在什么地方调用什么api只会有一个线程来顺序处理请求,因此不要在回调函数中调用阻塞的方法,这样会影响后续的回调。
11.代码片段
public class App {
public static final String connectionPair="192.168.135.132:2181,192.168.135.133:2181,192.168.135.134:2181";
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
TestWatcher();
}
//获取节点的状态
public static void getNodeStat() throws IOException, KeeperException, InterruptedException
{
//创建zookeeper实例
ZooKeeper zk=new ZooKeeper(connectionPair, 2000, null);
//创建一个stat存储返回的值
Stat stat=new Stat();
//返回节点的data,还有一个状态,但是需要有一个状态对象去接收
byte[] bytes= zk.getData("/root", null, stat);
System.out.println(new String(bytes));
}
//创建路径
public static void creatPath() throws IOException, KeeperException, InterruptedException
{
//创建zookeeper实例
ZooKeeper zk=new ZooKeeper(connectionPair, 2000, null);
//指定路径
String path="/root/s2";
//acl是访问控制权限,下面注释部分编写起来比较麻烦,需要一个acl挨着设置后还有添加到acl列表中,在传给构建节点的函数,因此还有更好的办法Ids接口下已经定义好的枚举:
/*ACL acl=new ACL();
acl.setId(m_);
acl.setPerms(1);*/
//创建路径,最后一个枚举表示创建的节点是永久还是临时并且是否排序,其实排序只是在后面带上一个数字并没有多大意思,如果是临时会话结束后节点将会删除。
//如果添加的节点已经存在或者路径的父路径不存在将会报错,如果创建的是临时节点那么该节点不能有孩子节点
String retPath= zk.create(path, "s1_data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(retPath);
}
//删除路径
public static void deletePath() throws IOException, KeeperException, InterruptedException
{
ZooKeeper zk=new ZooKeeper(connectionPair, 2000, null);
String path="/root/s2";
//删除指定节点,如果给定的版本是-1则会匹配所有版本,如果给定的版本错误将会报错,对于节点中的stat值中ephemeralOwner为0时则表示为永久节点
zk.delete(path, -1);
//zk.delete(path, version, cb, ctx);带回调的删除
}
//设置数据
public static void getdate() throws IOException, KeeperException, InterruptedException
{
ZooKeeper zk=new ZooKeeper(connectionPair, 2000, null);
String path="/root/s1";
Stat stat = zk.setData(path, "8888".getBytes(), -1);
byte[] datas= zk.getData(path, null, null);
System.out.println(stat.getVersion());
System.out.println(new String(datas));
}
//获取孩子节点
public static void getChild() throws IOException, KeeperException, InterruptedException
{
ZooKeeper zk=new ZooKeeper(connectionPair, 2000, null);
String path="/root";
List<String> ls= zk.getChildren(path, null) ;
for(String name : ls)
{
System.out.println(name);
}
}
//监控
public static void TestWatcher() throws IOException, KeeperException, InterruptedException
{
//创建监控类,匿名内部类,此处其实是创建了一个线程在与zookeeper进行交互,有状态变化zookeeper服务端会调用该方法
Watcher watcher=new Watcher()
{
@Override
public void process(WatchedEvent event) {
System.out.println("有事情发生"+event.getPath());
}
};
//创建zk时传入监控对象
ZooKeeper zk=new ZooKeeper(connectionPair, 2000, watcher);
String path="/root/s1";
//由于zookeeper事件监听是一次性触发,所以修改时还需要继续注册监听,对于set方法中没有提供监听对象的传入可以使用get方法重新注册一次
zk.getData(path, watcher, null);//此处又重新注册了一次
zk.setData(path, "kkkkkk".getBytes(), -1);
//避免主程序关闭
while(true)
{
Thread.sleep(5000);
}
}
}