第三节 zookeeper基础应用与实战2

目录

1. Watch事件监听

1.1 一次性监听方式:Watcher

1.2 Curator事件监听机制

2. 事务&异步操作演示

2.1 事务演示

2.2 异步操作

3. Zookeeper权限控制

3.1 zk权限控制介绍

3.2 Scheme 权限模式

3.3 ID 授权对象

3.4 Permission权限类型

3.5 在控制台实现操作

3.6 Curator演示ACL的使用

4. Zookeeper集群搭建

4.1 搭建要求

4.2 Zookeeper集群角色

4.2 准备工作

4.3 配置集群

4.4 启动集群

5.Zookeeper集群操作

5.1 客户端操作zk集群

5.2 模拟集群异常操作

5.3 curate客户端连接zookeeper集群


1. Watch事件监听

1.1 一次性监听方式:Watcher

利用 Watcher 来对节点进行监听操作,可以典型业务场景需要使用可考虑,但一般情况不推荐使用。

public class CuratorWatchTest {
​private CuratorFramework client;
​/*** 建立连接*/@Beforepublic void testConnect(){
​/*** String connectString,  连接字符串 zk地址 端口: "192.168.58.100:2181,,,,"* int sessionTimeoutMs,  会话超时时间* int connectionTimeoutMs,  连接超时时间* RetryPolicy retryPolicy   重试策略*///1. 第一种方式RetryPolicy retryPolicy =new ExponentialBackoffRetry(3000,10);
​//2. 第二种方式client = CuratorFrameworkFactory.builder().connectString("192.168.58.100:2181").sessionTimeoutMs(60*1000).connectionTimeoutMs(15*1000).retryPolicy(retryPolicy).namespace("mashibing")  //当前程序创建目录的根目录.build();
​client.start();}
​/*** 演示一次性监听*/@Testpublic  void testOneListener() throws Exception {
​byte[] data = client.getData().usingWatcher(new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {System.out.println("监听器 watchedEvent: " + watchedEvent);}}).forPath("/test");
​System.out.println("监听节点内容:" + new String(data));
​while(true){
​}}@Afterpublic void close(){client.close();}
}

上面这段代码对 /test 节点注册了一个 Watcher 监听事件,并且返回当前节点的内容。后面进行两次数据变更,实际上第二次变更时,监听已经失效,无法再次获得节点变动事件了。测试中控制台输出的信息如下:

image.png

1.2 Curator事件监听机制

ZooKeeper 原生支持通过注册Watcher来进行事件监听,但是其使用并不是特别方便需要开发人员自己反复注册Watcher,比较繁琐。

Curator引入了 Cache 来实现对 ZooKeeper 服务端事件的监听。

ZooKeeper提供了三种Watcher:

  • NodeCache : 只是监听某一个特定的节点

  • PathChildrenCache : 监控一个ZNode的子节点.

  • TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合

1)watch监听 NodeCache

监听数据节点本身的变化。NodeCacheListener 来完成后续处理。

public class CuratorWatchTest {/*** 演示 NodeCache : 给指定一个节点注册监听*/@Testpublic void testNodeCache() throws Exception {
​//1. 创建NodeCache对象NodeCache nodeCache = new NodeCache(client, "/app1");  //监听的是 /mashibing和其子目录app1
​//2. 注册监听nodeCache.getListenable().addListener(new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {System.out.println("节点变化了。。。。。。");
​//获取修改节点后的数据byte[] data = nodeCache.getCurrentData().getData();System.out.println(new String(data));}});
​//3. 设置为true,开启监听nodeCache.start(true);
​while(true){
​}} 
}

image.png

NodeCache不仅可以监听节点内容变化,还可以监听指定节点是否存在。如果原本节点不存在,那么Cache就会在节点被创建时触发监听事件,如果该节点被删除,就无法再触发监听事件。

2)watch监听 PathChildrenCache

    /*** 演示 PathChildrenCache: 监听某个节点的所有子节点*/@Testpublic void testPathChildrenCache() throws Exception {
​//1.创建监听器对象 (第三个参数表示缓存每次节点更新后的数据)PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app2", true);
​//2.绑定监听器pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {System.out.println("子节点发生变化了。。。。。。");System.out.println(pathChildrenCacheEvent);
​if(PathChildrenCacheEvent.Type.CHILD_UPDATED == pathChildrenCacheEvent.getType()){//更新子节点System.out.println("子节点更新了!");//在一个getData中有很多数据,我们只拿data部分byte[] data = pathChildrenCacheEvent.getData().getData();System.out.println("更新后的值为:" + new String(data));
​}else if(PathChildrenCacheEvent.Type.CHILD_ADDED == pathChildrenCacheEvent.getType()){//添加子节点System.out.println("添加子节点!");String path = pathChildrenCacheEvent.getData().getPath();System.out.println("子节点路径为: " + path);
​}else if(PathChildrenCacheEvent.Type.CHILD_REMOVED == pathChildrenCacheEvent.getType()){//删除子节点System.out.println("删除了子节点");String path = pathChildrenCacheEvent.getData().getPath();System.out.println("子节点路径为: " + path);}}});
​//3. 开启pathChildrenCache.start();
​while(true){
​}}

image.png

  • 事件对象信息分析

PathChildrenCacheEvent{type=CHILD_UPDATED, data=ChildData{path='/app2/m1', stat=164,166,1670114647087,1670114698259,1,0,0,0,3,0,164, data=[49, 50, 51]}
}

3)watch监听 TreeCache

TreeCache相当于NodeCache(只监听当前结点)+ PathChildrenCache(只监听子结点)的结合版,即监听当前和子结点。

  /*** 演示 TreeCache: 监听某个节点的所有子节点*/@Testpublic void testCache() throws Exception {
​//1.创建监听器对象TreeCache treeCache = new TreeCache(client, "/app2");
​//2.绑定监听器treeCache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {System.out.println("节点变化了");System.out.println(treeCacheEvent);
​if(TreeCacheEvent.Type.NODE_UPDATED == treeCacheEvent.getType()){//更新节点System.out.println("节点更新了!");//在一个getData中有很多数据,我们只拿data部分byte[] data = treeCacheEvent.getData().getData();System.out.println("更新后的值为:" + new String(data));
​}else if(TreeCacheEvent.Type.NODE_ADDED == treeCacheEvent.getType()){//添加子节点System.out.println("添加节点!");String path = treeCacheEvent.getData().getPath();System.out.println("子节点路径为: " + path);
​}else if(TreeCacheEvent.Type.NODE_REMOVED == treeCacheEvent.getType()){//删除子节点System.out.println("删除节点");String path = treeCacheEvent.getData().getPath();System.out.println("删除节点路径为: " + path);}}});
​//3. 开启treeCache.start();
​while(true){
​}}

image.png

2. 事务&异步操作演示

2.1 事务演示

CuratorFramework 的实例包含 inTransaction( ) 接口方法,调用此方法开启一个 ZooKeeper 事务。

可以复合create、 setData、 check、and/or delete 等操作然后调用 commit() 作为一个原子操作提交。

/*** 事务操作*/
@Test
public void TestTransaction() throws Exception {
​//1. 创建Curator对象,用于定义事务操作CuratorOp createOp = client.transactionOp().create().forPath("/app3", "app1-data".getBytes());CuratorOp setDataOp = client.transactionOp().setData().forPath("/app2", "app2-data".getBytes());CuratorOp deleteOp = client.transactionOp().delete().forPath("/app2");
​//2. 添加事务操Collection<CuratorTransactionResult> results = client.transaction().forOperations(createOp, setDataOp, deleteOp);
​//3. 遍历事务操作结果for (CuratorTransactionResult result : results) {System.out.println(result.getForPath() + " - " + result.getType());}
}

2.2 异步操作

前面提到的增删改查都是同步的,但是 Curator 也提供了异步接口,引入了 BackgroundCallback 接口用于处理异步接口调用之后服务端返回的结果信息。

BackgroundCallback 接口中一个重要的回调值为 CuratorEvent,里面包含事件类型、响应码和节点的详细信息。

​// 异步操作@Testpublic void TestAsync() throws Exception {
​while(true){
​// 异步获取子节点列表GetChildrenBuilder builder = client.getChildren();builder.inBackground(new BackgroundCallback() {@Overridepublic void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {System.out.println("子节点列表:" + curatorEvent.getChildren());}}).forPath("/");
​TimeUnit.SECONDS.sleep(5);}
​}

3. Zookeeper权限控制

3.1 zk权限控制介绍

Zookeeper作为一个分布式协调框架,内部存储了一些分布式系统运行时的状态的数据,比如master选举、比如分布式锁。对这些数据的操作会直接影响到分布式系统的运行状态。因此,为了保证zookeeper中的数据的安全性,避免误操作带来的影响。Zookeeper提供了一套ACL权限控制机制来保证数据的安全。

ACL权限控制,使用:scheme:id:perm来标识。

  • Scheme(权限模式),标识授权策略

  • ID(授权对象)

  • Permission:授予的权限

ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限,每个znode支持设置多种权限控制方案和多个权限,子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点。

3.2 Scheme 权限模式

Zookeeper提供以下权限模式,所谓权限模式,就是使用什么样的方式来进行授权。

  • world: 默认方式,相当于全部都能访问。

  • auth:代表已经认证通过的用户

    cli中可以通过 addauth digest user:pwd 来添加当前上下文中的授权用户

  • digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。

    username:password 字符串来产生一个MD5串,然后该串被用来作为ACL ID。认证是通过明文发送username:password 来进行的,当用在ACL时,表达式为username:base64 ,base64是password的SHA1摘要的编码。

  • ip:通过ip地址来做权限控制

    比如 ip:192.168.1.1 表示权限控制都是针对这个ip地址的。也可以针对网段 ip:192.168.1.1/24,此时addr中的有效位与客户端addr中的有效位进行比对。

3.3 ID 授权对象

指权限赋予的用户或一个指定的实体,不同的权限模式下,授权对象不同。

Id ipId = new Id("ip", "192.168.58.100");
Id ANYONE_ID_UNSAFE = new Id("world", "anyone");

3.4 Permission权限类型

指通过权限检查后可以被允许的操作,create /delete/write/read/admin

  • Create 允许对子节点Create 操作

  • Delete 允许对子节点Delete 操作

  • Write 允许对本节点SetData 操作

  • Read 允许对本节点GetChildren 和GetData 操作

  • Admin 允许对本节点setAcl 操作

权限模式(Schema)和授权对象主要用来确认权限验证过程中使用的验证策略:

比如ip地址、digest:username:password,匹配到验证策略并验证成功后,再根据权限操作类型来决定当前客户端的访问权限。

3.5 在控制台实现操作

在Zookeeper中提供了ACL相关的命令

getAcl        getAcl <path>     读取ACL权限
setAcl        setAcl <path> <acl>     设置ACL权限
addauth      addauth <scheme> <auth>     添加认证用户

1)word方式

创建一个节点后默认就是world模式

[zk: localhost:2181(CONNECTED) 6] create /auth
Created /auth[zk: localhost:2181(CONNECTED) 7] getAcl /auth
'world,'anyone
: cdrwa[zk: localhost:2181(CONNECTED) 8] create /auth2
Created /auth2[zk: localhost:2181(CONNECTED) 9] getAcl /auth2
'world,'anyone
: cdrwa[zk: localhost:2181(CONNECTED) 10] 

其中, cdrwa,分别对应 create . delete read write admin

2)IP方式

在ip模式中,首先连接到zkServer的命令需要使用如下方式

zkCli.sh -server 127.0.0.1:2181 

接着按照IP的方式操作如下

[zk: 127.0.0.1:2181(CONNECTED) 0] create /ip-model
Created /ip-model[zk: 127.0.0.1:2181(CONNECTED) 1] setAcl /ip-model ip:127.0.0.1:cdrwa[zk: 127.0.0.1:2181(CONNECTED) 3] getAcl /ip-model
'ip,'127.0.0.1
: cdrwa

3) Auth模式

auth模式的操作如下。

[zk: 127.0.0.1:2181(CONNECTED) 5] create /spike
Created /spike[zk: 127.0.0.1:2181(CONNECTED) 6] addauth digest spike:123456[zk: 127.0.0.1:2181(CONNECTED) 9] setAcl /spike auth:spike:cdrwa[zk: 127.0.0.1:2181(CONNECTED) 10] getAcl /spike
'digest,'spike:pPeKgz2N9Xc8Um6wwnzFUMteLxk=
: cdrwa

当我们退出当前的会话后,再次连接,执行如下操作,会提示没有权限

[zk: localhost:2181(CONNECTED) 0] get /spike
Insufficient permission : /spike 

这时候,我们需要重新授权。

[zk: localhost:2181(CONNECTED) 1] addauth digest spike:123456
[zk: localhost:2181(CONNECTED) 2] get /spike
null 

4) Digest模式

使用语法,会发现使用方式和Auth模式相同

setAcl /digest digest:用户名:密码:权限

但是有一个不一样的点,密码需要用加密后的,否则无法被识别。

密码: 用户名和密码加密后的字符串。

使用下面程序生成密码

public class TestAcl {@Testpublic void createPw() throws NoSuchAlgorithmException {String up = "msb:msb";byte[] digest = MessageDigest.getInstance("SHA1").digest(up.getBytes());String encodeStr = Base64.getEncoder().encodeToString(digest);System.out.println(encodeStr);}
}

得到: 5FAC7McRhLdx0QUWsfEbK8pqwxc=

再回到client上进行如下操作

[zk: localhost:2181(CONNECTED) 14] create /digest
Created /digest[zk: localhost:2181(CONNECTED) 15] setAcl /digest digest:msb:5FAC7McRhLdx0QUWsfEbK8pqwxc=:cdrwa[zk: localhost:2181(CONNECTED) 16] getAcl /digest
'digest,'msb:5FAC7McRhLdx0QUWsfEbK8pqwxc=
: cdrwa

当退出当前会话后,需要再次授权才能访问/digest节点

[zk: localhost:2181(CONNECTED) 0] get /digest
Insufficient permission : /digest[zk: localhost:2181(CONNECTED) 1] addauth digest msb:msb[zk: localhost:2181(CONNECTED) 2] get /digest
null

3.6 Curator演示ACL的使用

接下来我们使用Curator简单演示一下ACL权限的访问操作。

public class TestAcl {private CuratorFramework client;@Testpublic void createPw() throws NoSuchAlgorithmException {String up = "msb:msb";byte[] digest = MessageDigest.getInstance("SHA1").digest(up.getBytes());String encodeStr = Base64.getEncoder().encodeToString(digest);System.out.println(encodeStr);}//1.创建连接@Beforepublic void createConnect(){client = CuratorFrameworkFactory.builder().connectString("192.168.58.100:2181").sessionTimeoutMs(5000).connectionTimeoutMs(20000).retryPolicy(new ExponentialBackoffRetry(1000, 3)).namespace("msbAcl").build();client.start();}@Testpublic void testCuratorAcl() throws Exception {//创建ID,以Digest方式认证,用户名和密码为 msb:msbId id = new Id("digest", DigestAuthenticationProvider.generateDigest("msb:msb"));//为ID对象指定权限List<ACL> acls = new ArrayList<>();acls.add(new ACL(ZooDefs.Perms.ALL,id));//创建节点 "auth",设置节点数据,并设置ACL权限String node = client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)  // 设置节点类型是持久节点.withACL(acls,false)    //设置节点的ACL权限.forPath("/auth","hello".getBytes());   //设置节点的路径和数据System.out.println("成功创建带权限的节点: " + node);//获取刚刚创建的节点的数据byte[] bytes = client.getData().forPath(node);System.out.println("获取数据结果: " + new String(bytes));}}

上述代码执行后会报错

image.png

先删除节点

[zk: localhost:2181(CONNECTED) 6] deleteall /msbAcl

修改代码, 连接时增加授权

image.png

4. Zookeeper集群搭建

4.1 搭建要求

真实的集群是需要部署在不同的服务器上的,但是在我们测试时同时启动很多个虚拟机内存会吃不消,所以我们通常会搭建伪集群,也就是把所有的服务都搭建在一台虚拟机上,用端口进行区分。

我们这里要求搭建一个三个节点的Zookeeper集群(伪集群)。

4.2 Zookeeper集群角色

zookeeper集群中的节点有三种角色

  • Leader:处理集群的所有事务请求(增删改),集群中只有一个Leader。

  • Follower:只能处理读请求,参与Leader选举。

  • Observer:只能处理读请求,提升集群读的性能,但不能参与Leader选举。

image.png

4.2 准备工作

重新部署一台虚拟机作为我们搭建集群的测试服务器。

(1)安装JDK 【此步骤省略】。

(2)Zookeeper压缩包上传到服务器 (3)将Zookeeper解压 ,建立/usr/local/zookeeper-cluster目录,将解压后的Zookeeper复制到以下三个目录。

[root@localhost ~]# mkdir /usr/local/zookeeper-cluster[root@localhost software]# cp -r apache-zookeeper-3.7.1-bin /usr/local/zookeeper-cluster/zookeeper-1[root@localhost software]# cp -r apache-zookeeper-3.7.1-bin /usr/local/zookeeper-cluster/zookeeper-2[root@localhost software]# cp -r apache-zookeeper-3.7.1-bin /usr/local/zookeeper-cluster/zookeeper-3

(4)创建data目录 ,并且将 conf下zoo_sample.cfg 文件改名为 zoo.cfg

mkdir /usr/local/zookeeper-cluster/zookeeper-1/data
mkdir /usr/local/zookeeper-cluster/zookeeper-2/data
mkdir /usr/local/zookeeper-cluster/zookeeper-3/datamv  /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo_sample.cfg  /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg
mv  /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo_sample.cfg  /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg
mv  /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo_sample.cfg  /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

(5) 配置每一个Zookeeper 的dataDir 和 clientPort 分别为:2181 2182 2183

修改/usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg

vim /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfgclientPort=2181
dataDir=/usr/local/zookeeper-cluster/zookeeper-1/data

修改/usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg

vim /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfgclientPort=2182
dataDir=/usr/local/zookeeper-cluster/zookeeper-2/data

修改/usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

vim /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfgclientPort=2183
dataDir=/usr/local/zookeeper-cluster/zookeeper-3/data

4.3 配置集群

(1)在每个zookeeper的 data 目录下创建一个 myid 文件,内容分别是1、2、3 。这个文件就是记录每个服务器的ID

[root@localhost software]# echo 1 > /usr/local/zookeeper-cluster/zookeeper-1/data/myid
[root@localhost software]# echo 2 > /usr/local/zookeeper-cluster/zookeeper-2/data/myid
[root@localhost software]# echo 3 > /usr/local/zookeeper-cluster/zookeeper-3/data/myid   

(2)在每一个zookeeper 的 zoo.cfg配置客户端访问端口(clientPort)和集群服务器IP列表。

集群服务器IP列表如下

vim /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg
vim /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg
vim /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfgserver.1=192.168.58.200:2881:3881
server.2=192.168.58.200:2882:3882
server.3=192.168.58.200:2883:3883   

解释:server.服务器ID=服务器IP地址:服务器之间通信端口:服务器之间投票选举端口

4.4 启动集群

启动集群就是分别启动每个实例。

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh start
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh start
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh start

启动后我们查询一下每个实例的运行状态

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

查询第一个服务,Mode为follower表示是跟随者(从)

image.png

再查询第二个服务Mode 为leader表示是领导者(主)

image.png

查询第三个为跟随者(从)

image.png

5.Zookeeper集群操作

5.1 客户端操作zk集群

1) 第一步启动集群,启动后查看Zookeeper进程。

image.png

jps命令 作用是显示当前所有java 进程的pid 的命令,QuorumPeerMain是zookeeper集群的启动入口类

2) 客户端连接

  • 连接集群所有客户端

[root@localhost zookeeper-1]# ./bin/zkCli.sh -server 192.168.58.200:2181,192.168.58.200:2182,192.168.58.200:2183                        

image.png

  • 连接集群单个客户端

# 连接2181
[root@localhost zookeeper-1]# ./bin/zkCli.sh -server 192.168.58.200:2181 # 连接2182
[root@localhost zookeeper-1]# ./bin/zkCli.sh -server 192.168.58.200:2182# 在2181中创建节点
[zk: 192.168.58.200:2181(CONNECTED) 0] create /test2# 在2182中查询,发现数据已同步
[zk: 192.168.58.200:2182(CONNECTED) 0] ls /
[test1, test2, zookeeper]

以上两种方式的区别在于:

  • 如果只连接单个客户端,如果当前连接的服务器挂掉,当前客户端连接也会挂掉,连接失败。

  • 如果是连接所有客户端的形式,则允许集群中半数以下的服务挂掉!当半数以上服务挂掉才会停止服务,可用性更高一点!

3)集群节点信息查看

集群中的节点信息被存放在每一个节点/zookeeper/config/目录下

image.png

5.2 模拟集群异常操作

(1)首先我们先测试如果是从服务器挂掉,会怎么样

把3号服务器停掉,观察1号和2号,发现状态并没有变化

/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh stop/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

image.png

由此得出结论,3个节点的集群,从服务器挂掉,集群正常

(2)我们再把1号服务器(从服务器)也停掉,查看2号(主服务器)的状态,发现已经停止运行了。

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh stop/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

image.png

由此得出结论,3个节点的集群,2个从服务器都挂掉,主服务器也无法运行。因为可运行的机器没有超过集群总数量的半数。

(3)我们再次把1号服务器启动起来,发现2号服务器又开始正常工作了。而且依然是领导者。

image.png

(4)我们把3号服务器也启动起来,把2号服务器停掉,停掉后观察1号和3号的状态。

/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh start
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh stop/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

image.png

发现新的leader产生了~

由此我们得出结论,当集群中的主服务器挂了,集群中的其他服务器会自动进行选举状态,然后产生新得leader 。

(5)我们再次测试,当我们把2号服务器重新启动起来启动后,会发生什么?2号服务器会再次成为新的领导吗?我们看结果

/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh start/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

我们会发现,2号服务器启动后依然是跟随者(从服务器),3号服务器依然是领导者(主服务器),没有撼动3号服务器的领导地位。

由此我们得出结论,当领导者产生后,再次有新服务器加入集群,不会影响到现任领导者。

image.png

5.3 curate客户端连接zookeeper集群

public class CuratorCluster {//zookeeper连接private final static String CLUSTER_CONNECT = "192.168.58.200:2181,192.168.58.200:2182,192.168.58.200:2183";//session超时时间private static final int sessionTimeoutMs = 60 * 1000;//连接超时时间private static final int connectionTimeoutMs = 5000;private static CuratorFramework client;public static String getClusterConnect() {return CLUSTER_CONNECT;}@Beforepublic void init(){// 重试策略RetryPolicy retryPolicy =new ExponentialBackoffRetry(3000,10);// zookeeper连接client = CuratorFrameworkFactory.builder().connectString(getClusterConnect()).sessionTimeoutMs(60*1000).connectionTimeoutMs(15*1000).retryPolicy(retryPolicy).namespace("mashibing")  //当前程序创建目录的根目录.build();// 添加监听器client.getConnectionStateListenable().addListener(new ConnectionStateListener() {@Overridepublic void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {System.out.println("连接成功!");}});client.start();}//创建节点public void createIfNeed(String path) throws Exception {Stat stat = client.checkExists().forPath(path);if(stat == null){String s = client.create().forPath(path);System.out.println("创建节点: " + s);}}//从集群中获取数据@Testpublic void testCluster() throws Exception {createIfNeed("/test");//每隔一段时间 获取一次数据while(true){byte[] data = client.getData().forPath("/test");System.out.println(new String(data));TimeUnit.SECONDS.sleep(5);}}
}

在集群中的任意服务器节点,为test设置数据

[zk: 192.168.58.200:2181,192.168.58.200:2182,192.168.58.200:2183(CONNECTED) 2] set /mashibing/test 12345

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2780325.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【大数据】Flink on Kubernetes 原理剖析

Flink on Kubernetes 原理剖析 1.基本概念2.架构图3.核心概念4.架构5.JobManager6.TaskManager7.交互8.实践8.1 Session Cluster8.2 Job Cluster 9.问题解答 Kubernetes 是 Google 开源的 容器集群管理系统&#xff0c;其提供应用部署、维护、扩展机制等功能&#xff0c;利用 K…

fast.ai 机器学习笔记(三)

机器学习 1&#xff1a;第 8 课 原文&#xff1a;medium.com/hiromi_suenaga/machine-learning-1-lesson-8-fa1a87064a53 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;这些笔记将继续更…

leetcode——滑动窗口题目汇总

本章总结一下滑动窗口的解题思路&#xff1a; 在字符串中使用双指针 left 和 right 围成的一个左闭右开的区域作为一个窗口。不断将 right 向右滑动&#xff0c;直到窗口中的字符串符合条件。此时将 left 向右滑动&#xff0c;直到窗口中的字符串不符合条件&#xff0c;期间需…

【转载】原生社区交友婚恋视频即时通讯双端APP源码 ONE兔2.0版

原生社区交友婚恋视频即时通讯双端APP源码下载ONE兔2.0版 包含后端、H5源码源码&#xff0c;Android源码&#xff0c;IOS源码

麒麟操作系统选型适配:经验与策略分享

一、麒麟操作系统概况 麒麟V10是一款商业版本服务器操作系统&#xff0c;其作为承载业务系统的基础底座&#xff0c;能满足大部分企业的产品需求&#xff0c;各类软硬件适配也都较好。麒麟V10的SP1/SP2/SP3版本内核都是基于OpenEuler 20.03 LTS研发的&#xff0c;其支持X86、A…

Oracle的学习心得和知识总结(三十二)|Oracle数据库数据库回放功能之论文四翻译及学习

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《Oracle Database SQL Language Reference》 2、参考书籍&#xff1a;《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Gui…

【洛谷题解】P1029[普及组]最大公约数和最小公倍数问题

题目链接&#xff1a;[NOIP2001 普及组] 最大公约数和最小公倍数问题 - 洛谷 题目难度&#xff1a;普及- 涉及知识点&#xff1a;stl函数&#xff0c;最大公因数&#xff0c;最小公倍数 题意&#xff1a; 输入输出样例&#xff1a; 分析&#xff1a;直接套用公式优化累加即…

UI自动刷新大法:DataBinding数据绑定

之前我们讲了DataBinding在Activity、Fragment、RecyclerView中的基础使用&#xff0c;而那些常规使用方法里&#xff0c;每当绑定的变量发生数据变化时&#xff0c;都需要ViewDataBinding重新设值才会刷新对应UI。而DataBinding通过内部实现的观察者模式来进行自动刷新UI&…

第六篇【传奇开心果系列】Vant of Vue 开发移动应用示例:深度解析响应式布局支持

传奇开心果系列 系列博文目录Vant开发移动应用示例系列 博文目录前言一、Vant响应式布局介绍二、媒体查询实现响应式布局示例代码三、短点设置实现响应式布局示例代码四、响应式工具类实现响应式布局示例代码五、栅格系统实现响应式布局示例代码六、响应式组件实现响应式布局示…

软件测试风险管理

1 软件测试风险管理 软件测试风险管理是识别、评估和控制测试过程中可能出现的风险&#xff0c;以确保测试活动能够按计划进行并达到预期目标的过程。软件测试风险管理是软件测试过程中的一个关键组成部分&#xff0c;它涉及到识别、评估和控制可能影响软件测试项目成功的不确…

图解密码技术——第六章 混合密码系统

一、混合密码系统 1.介绍 混合密码系统将对称密码和公钥密码的优势结合在一起。使用对称密码对信息进行加密&#xff0c;使用公钥密码对加密信息的对称密码的秘钥进行加密。这样&#xff0c;解决了对称密码的密钥配送问题&#xff0c;由于秘钥较短&#xff0c;所以公钥密码处…

【前端web入门第五天】03 清除默认样式与外边距问题【附综合案例产品卡片与新闻列表】

文章目录: 1.清除默认样式 1.1清除内外边距1.2清除列表圆点(项目符号) 3.外边距问题-合并现象4.外边距问题–塌陷问题5.行内元素垂直内外边距6.圆角与盒子阴影 6.1圆角 6.2 盒子模型-阴影(拓展) 综合案例一 产品卡片 综合案例二 新闻列表 1.清除默认样式 在实际设计开发中,要…

寒假9-蓝桥杯训练

//轨道炮 #include<iostream> using namespace std; #include<algorithm> int logs[100010]; int main() {int n;cin >> n;for (int i 1;i < n;i){cin >> logs[i];}sort(logs 1, logs n 1);int ans 1000000000;for (int i 2;i < n;i){if (…

【Jenkins】Jenkins关闭Jenkins关闭、重启

目录 一、Jenkins关闭、重启 二、Jenkins服务的启动、停止方法。 一、Jenkins关闭、重启 1.关闭Jenkins 只需要在访问jenkins服务器的网址url地址后加上exit&#xff0c;关闭Jenkins服务。 例如&#xff1a;http://localhost:8081/exit 2.重启Jenkies 只有在Jenkins服务启动…

Matplotlib初探:认识数据可视化与Matplotlib

Matplotlib初探&#xff1a;认识数据可视化与Matplotlib Fig.1 利用Matplotlib进行数据可视化( 可视化代码见文末) &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;一、数据可视化简介&#x1f333;&#x1f333;二、Matplotlib库简介&#x…

为什么说 2023 年是 AI 视频生成的突破年?2024 年的 AI 视频生成有哪些值得期待的地方?

Diffusion Models视频生成-博客汇总 前言&#xff1a;2023年是 AI 视频生成的突破年&#xff0c;AI视频已经达到GPT-2级别了。去年我们取得了长足的进步&#xff0c;但距离普通消费者每天使用这些产品还有很长的路要走。视频的“ChatGPT时刻”何时到来&#xff1f; 目录 前言 …

小程序-上传图片功能

技术前置&#xff1a; 1.框架采用colorUI 2.原生开发 功能&#xff1a; 上传图片 1.上传已经拍摄的图片 2.实时拍摄上传 3.设置上传图片数量&#xff0c;每次上传数量 4.上传等待 ChooseImage() {if(this.data.imgList.length>4){_this.ErrorEvent("最多上传4…

网络安全检查表

《网络攻击检查表》 1.应用安全漏洞 2.弱口令&#xff0c;默认口令 3.服务器互联网暴露 4.操作系统&#xff0c;中间件安全漏洞 5.研发服务器&#xff0c;邮件服务器等安全检查

Linux中FIFO管道

介绍&#xff1a; FIFO被称为命名管道&#xff0c;pipe只能用于有血缘关系的进程间通信&#xff0c;但通过FIFO&#xff0c;不相关的进程也可以进程间通信。 FIFO是linux基础文件类型的一种&#xff08;文件类型为p&#xff09;&#xff0c;FIFO文件在磁盘上没有数据块&#…

用code去探索理解Llama架构的简单又实用的方法

除了白月光我们也需要朱砂痣 我最近也在反思&#xff0c;可能有时候算法和论文也不是每个读者都爱看&#xff0c;我也会在今后的文章中加点code或者debug模型的内容&#xff0c;也许还有一些好玩的应用demo&#xff0c;会提升这部分在文章类型中的比例 今天带着大家通过代码角度…