1.应用场景
(1)维护配置信息 (2)分布式锁服务 (3)集群管理 (4)生成分布式唯一ID
2.常见命令
去到安装Zookeeper的安装路径的bin目录下,
启动Zookeepeer:
./zkServer.sh start
查看状态:
./zkServer.sh status
关闭Zookeeper:
./zkServer.sh stop
本地登陆:
./zkCli.sh
远程登陆:
./zkCli.sh -server ip
新增节点:
create [-s] [-e] path data #其中-s 为有序节点,-e 临时节点,path为路径,如/node1,data为节点名称,带双引号
ps:临时节点会在会话过期后被删除。删除节点的话就把create改成delete
更新节点:
set path "xxx"
ps:也基于版本号进行更改,类似于悲观锁,当你传入的数据版本号 (dataVersion) 和当前节点的数据版本号不符合时,zookeeper 会拒绝本次修改。
删除节点:
delete path [version]
查看节点:
get path
查看节点状态:
stat path
查看节点列表:
ls path 和 ls2 path //后者是前者的增强版,不仅可以查看指定路径下的所有节点,还可以查看当前节点的信息。
监听器:
get/stat path watch //能够在节点内容发生改变的时候,向客户端发出通知。
ps: zookeeper 的触发器是一次性的,即触发一次后就会立即失效。
ls/ls2 path watch //监听该节点下所有子节点的增加和删除操作。
3.权限
四种授权模式:world(默认)、ip、auth和digest。除此之外,其实还有一种权限管理模式就是超级管理员,即super。
五种权限:create、delete、read、writer、admin,即增、删、改、查、管理权限,简写为cdrwa。此外,超级管理员访问任何权限的节点。
getAcl path //读取ACL权限
setAcl parh //设置ACL权限
addauth //添加认证用户
ps:这五种权限只有delete具有删除子节点,其它4种只能操作对自身节点。
eg:
world模式: setAcl /node1 world anyone:dwa
ip模式: setAcl /node2 ip:39.108.xxx.xxx:cdrda //若授权多个ip地址,则用在后面加上逗号
auth授权模式: 1.先添加授权用户:addauth digest Jackson:123456
2.授权:setAcl /node1 auth:Jackson:cdrda
digest授权模式:1.获取密文:echo -n Jackson:123456 | openssl dgst -binary -sha1 | openssl base64
2.授权:setAcl /node1 digest:Jackson:密文:cdrda
多种授权模式: 1.先添加授权用户:addauth digest Jackson:123456
2.授权:setAcl /node2 ip:39.108.xxx.xxx:cdrd,auth:Jackson:cdr, digest:Jackson:密文:cd
超级管理员权限:
1.获取密文
echo -n admin:123456 | openssl dgst -binary -sha1 | openssl base64
2.进入安装Zookeeper的安装目录下的zkServer.sh,在
nohup $JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}"
后面加上
"-Dzookeeper.DigestAuthenticationProvider.superDigest=super:密文"
3.保存文件,重启Zookeeper
4.授权
addauth digest super:admin
4.Zookeeper API
连接Zookeeper:
public class ZookeeperConnection {
public static void main(String[] args) {
try {
// 计数器对象
CountDownLatch countDownLatch=new CountDownLatch(1);
// arg1:服务器的ip和端口,arg2:客户端与服务器之间的会话超时时间单位为毫秒,arg3:监视器对象
ZooKeeper zooKeeper=new ZooKeeper("服务器地址:2181", 5000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if(event.getState()==Event.KeeperState.SyncConnected) {
System.out.println("连接创建成功!");
countDownLatch.countDown();
}
}
});
countDownLatch.await();// 主线程阻塞等待连接对象的创建成功
System.out.println(zooKeeper.getSessionId()); // 会话编号
zooKeeper.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
(1)新增节点:
1.同步方式: create(String path, byte[] data, List<ACL> acl, CreateMode createMode)
2.异步方式: create(String path, byte[] data, List<ACL> acl, CreateMode createMode,AsyncCallback.StringCallback callBack, Object ctx)
eg:
1.默认模式:
// arg1:节点的路径,arg2:节点的数据, arg3:权限列表 world:anyone:cdrwa,arg4:节点类型,此处为持久化节点
zooKeeper.create("/create/node1","node1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
List<ACL> acls = new ArrayList<ACL>();// 权限列表
Id id = new Id("world", "anyone");// 授权模式和授权对象
// 权限设置
acls.add(new ACL(ZooDefs.Perms.READ, id));
acls.add(new ACL(ZooDefs.Perms.WRITE, id));
zooKeeper.create("/create/node3", "node3".getBytes(), acls, CreateMode.PERSISTENT);
2.ip授权模式:
// 权限列表
List<ACL> acls = new ArrayList<ACL>();
Id id = new Id("ip", "服务器地址");// 授权模式和授权对象
acls.add(new ACL(ZooDefs.Perms.ALL, id));// 权限设置
zooKeeper.create("/create/node4", "node4".getBytes(), acls, CreateMode.PERSISTENT);
3. auth授权模式:
zooKeeper.addAuthInfo("digest", "Jackson:123456".getBytes());// 添加授权用户
zooKeeper.create("/create/node5", "node5".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
4.digest授权模式:
List<ACL> acls = new ArrayList<ACL>(); // 权限列表
Id id = new Id("digest", "Jackson:密钥");// 授权模式和授权对象
acls.add(new ACL(ZooDefs.Perms.ALL, id));// 权限设置
zooKeeper.create("/create/node7", "node7".getBytes(), acls, CreateMode.PERSISTENT);
(2)删除节点:
1.同步方式:
//arg1:删除节点的节点路径,arg2:数据版本信息,-1代表删除节点时不考虑版本信息
zooKeeper.delete("/delete/node1",-1);
2.异步方式:
zooKeeper.delete("/delete/node2", -1, new AsyncCallback.VoidCallback() {
@Override
public void processResult(int rc, String path, Object ctx) {
// arg1为0,代表删除成功,arg2为节点的路径,arg3为上下文参数对象
}
},"This is Context");
Thread.sleep(10000);//异步传输要休眠
System.out.println("结束");
(3)更新节点:
(4)查看节点:
1.同步方式:
getData(String path, boolean b, Stat stat)// arg3:读取节点属性的对象
2.异步方式:
getData(String path, boolean b,AsyncCallback.DataCallback callBack,Object ctx)//arg2:是否使用连接对象中注册的监视器
(5)查看子节点:
1.同步方式
getChildren(String path, boolean b)
2. 异步方式
getChildren(String path, boolean b,AsyncCallback.ChildrenCallback callBack,Object ctx)
(6)查看节点是否存在:
1.同步方法:
exists(String path, boolean b)
2.异步方法:
exists(String path, boolean b,AsyncCallback.StatCallback callBack,Object ctx)
zookeeperAPI连接集群:
//arg1为zooKeeper集合主机,IP地址+端口号,arg2为服务器和客户端会话超时的时间(以毫秒为单位),arg3为 实现“监视器”界面的对象
ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher)
ps: 若需要连接多个服务器则在上一个服务器后面加上逗号
5.Watcher事件监听机制:
四种通知状态(KeeperState):
1.SyncConnected:客户端与服务器正常连接
2.Disconnected:客户端与服务器断开连接
3.Expired:会话session失效
4.AuthFailed:身份认证失败
1.检查节点是否存在:
使用连接对象的监视器:
exists(String path, boolean b)
自定义监视器:
exists(String path, Watcher w)
ps: NodeCreated: 节点创建; NodeDeleted: 节点删除; NodeDataChanged: 节点内容发生变化
2.查看节点:
使用连接对象的监视器:
getData(String path, boolean b, Stat stat)
自定义监视器:
getData(String path, Watcher w, Stat stat) // NodeDeleted:节点删除; NodeDataChanged:节点内容发生变化
3.查看子节点:
使用连接对象的监视器:
getChildren(String path, boolean b)
自定义监视器:
getChildren(String path, Watcher w)
ps: NodeChildrenChanged:子节点发生变化; NodeDeleted:节点删除
6.zab协议:
zab广播模式工作原理图:
ps: leader是主,follower是从,前者是老大,后者是小弟。
步骤:1. leader从客户端收到一个写请求。
2. leader生成一个新的事务并为这个事务生成一个唯一的ZXID。
3. leader将这个事务提议(propose)发送给所有的follows节点。
4. follower节点将收到的事务请求加入到历史队列(history queue)中,并发送ack给leader。
5. 当leader收到大多数follower(半数以上节点)的ack消息,leader会发送commit请求。
6. 当follower收到commit请求时,从历史队列中将事务请求commit。
集群中服务器的四种状态:
1. looking(寻找leader状态):当当前集群中没有leader时,需要进入leader选举状态。
2.l eading(领导者状态):当前服务器角色是leader。
3. following(跟随者状态):当前服务器角色是follower。
4. observing:观察者状态:当前服务器角色是observer。
ps: observer不参与集群的leader选举,也不参与集群中写数据时的ack反馈。
7.curator:
优势:1.解决session会话超时重连问题。
2.可以反复注册watcher。
3.简化开发API,并遵循Fluent风格的API。
4.提供了分布式锁服务、共享计数器、缓存机制等机制。
导入maven依赖:
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.6.0</version>
<type>jar</type>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.6.0</version>
<type>jar</type>
</dependency>
连接Zookeeper:
// 创建连接对象
CuratorFramework client= CuratorFrameworkFactory.builder()
.connectString("IP地址:端口号(集群也行)")
.sessionTimeoutMs(5000) // 会话超时时间
.retryPolicy(retryPolicy) // 重连机制
.namespace("create") // 命名空间
.build(); // 构建连接对象
client.start(); // 打开连接
System.out.println(client.isStarted());
client.close(); // 关闭连接
1. 新增节点:
client.create()
.withMode(CreateMode.PERSISTENT) // 节点的类型,此处为持久化节点
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE) // 节点的权限列表 world:anyone:cdrwa
.forPath("/node1", "node1".getBytes());// arg1:节点的路径,arg2:节点的数据
client.create()
.creatingParentsIfNeeded()// 递归节点的创建
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath("/node3/node31", "node31".getBytes());
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
// 异步回调接口
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework
curatorFramework, CuratorEvent curatorEvent) throws Exception {
System.out.println(curatorEvent.getPath());// 节点的路径
System.out.println(curatorEvent.getType());// 时间类型
}})
.forPath("/node4","node4".getBytes());
Thread.sleep(5000);
2.更新节点:
client.setData()
.forPath("/node1", "node11".getBytes());
ps: 需要更新版本号就加上.withVersion(x)
3.删除节点:
client.delete()
// 节点的路径 .forPath("/node1");
ps: 需要删除版本号就加上.withVersion(x)
删除包含字节点的节点:
client.delete()
.deletingChildrenIfNeeded()
.withVersion(-1)
.forPath("/node1");
4.查看节点:
Stat stat=new Stat(); // 读取数据时读取节点的属性
byte [] bys=client.getData() // 读取属性
.storingStatIn(stat) .forPath("/node1");
5.查看子节点:
// 读取子节点数据
List<String> list = client.getChildren()
.forPath("/get"); for (String str : list)
{ System.out.println(str); }
6.查看节点是否存在:
Stat stat= client.checkExists()
.forPath("/node2"); // 节点路径
System.out.println(stat.getVersion());
8.图形化工具
ZooInspector、ZooViewer