zk可以对多少个节点添加监听

zk可以对多少个节点添加监听,第1张

在ZooKeeper中,可以对非常多的节点添加监听器,实际上是没有数量限制的。ZooKeeper是一个分布式的协调服务,可以用于管理、维护分布式系统中的配置信息、命名服务、状态同步等,因此,它需要支持大规模的节点注册和监听。但是需要注意,如果你在ZooKeeper上注册了大量的监听器,会导致ZooKeeper的负载增加,所以应该合理利用监听机制,而不是过度使用。同时,如果要同时监听大量节点,建议使用ZooKeeper提供的批量注册监听器的方式,可以减少网络传输,提高效率。

 系统在很早之前就实现了一层对zookeeper的cache,目的是减少运行过程对zk集群的访问压力。

  大体流程是:启动时

     1.对zk上某个目录节点A添加CHILD的watch事件,以监听A的子节点数量变更,及时更新cache;

     2. 对A的所有子节点进行一次get,并添加每个子节点的变更watch事件,当节点内容变更或者节点删除时会收到回调。

    这套系统运行很长时间,整体跑得很ok。但最近做了一个新功能,线下验证过程中出现了各种奇奇怪怪的问题,比如两个节点直接出现了请求的无限转发,导致cpu持续打满;或者某个任务被分配到了某个节点负责(映射关系在zk上记录),但是该节点始终不启动这个任务。

    根据debug日志定位了2天,才发现是一个典型的ABA问题,导致cache不对了。

    为啥之前系统跑得好好的呢?因为是去中心化的设计,某些实例节点对某些zk节点的cache不对也不影响整体运行,只有当所有实例节点的zcache都不对,才会work不了。(去中心化的设计有一定优势,但也有一些问题,不同场景需求不同,没有绝对的孰好孰坏)。

接下来具体说一下问题:

假设zk上有目录 A,A下面有节点b,即目录结构为 /A/b

某一时刻节点b被删除了,并且马上重建,则根据前文所述我们加上的watch,zk会给我们发送2个事件

1. 目录A的子节点发生变更(加在A上的watch)

2. 节点b发生删除(加在b上的watch)

    此时根据我们实现的(有问题)逻辑,直接忽略事件2,然后对A进行一次get children请求,根据拿到的最新子节点列表,跟内存的节点做diff,来删除或者增加cache中的节点。 但是此时节点b又被创建了,所以本次 *** 作不会对cache中的b进行修改。 注意,由于b节点的watch已经触发了,所以b节点的变更将不会再次发送事件通知,即我们内存中所看到的b节点内容永远是错的,除非下一次节点b再被删除,并且我们正确地从cache中删掉他,然后b再创建,我们再次get并加上watch。

    对于这种典型的ABA问题,我们直接想到的就是在get children拿到的最新子节点列表,与内存cache做diff时,带上版本信息,就能搞定了。但是zk的get children接口只能拿到父节点的stat(包含版本、修改时间等),没有返回所有子节点的stat,故此时我们拿不到版本信息。

    我们的解决办法是,在收到事件2后,直接对节点b再发送一次get请求,若返回NO NODE,说明b确实被删除了,将内存cache中节点b删除;若返回ok,说明节点b又被创建了,则用最新的内容更新内存cache中的b信息,并且此时还是带着节点b的watch的。

掌握zookeeper事件监听机制,非常重要,可以说是跨入了进阶的门槛,只有掌握了如何监听某个节点或路径,我们才能在节点变化后,做一些我们想做的事,包括:

1,配置文件同步

2,主从切换

3,分布式队列

4,分布式锁

5,其他

首先,在以前的文章里面有写过使用zookeeper原生的api,监听zk节点变化,那么本篇我们就来看下,如何使用curator来完成监听,代码如下:

<pre name="code" class="java">package com.qin.curator.zk

import javax.sound.midi.Patch

import org.apache.curator.RetryPolicy

import org.apache.curator.framework.CuratorFramework

import org.apache.curator.framework.CuratorFrameworkFactory

import org.apache.curator.framework.CuratorFrameworkFactory.Builder

import org.apache.curator.framework.api.CuratorWatcher

import org.apache.curator.framework.recipes.cache.NodeCache

import org.apache.curator.framework.recipes.cache.NodeCacheListener

import org.apache.curator.framework.recipes.cache.PathChildrenCache

import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent

import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener

import org.apache.curator.retry.ExponentialBackoffRetry

import org.apache.curator.utils.ZKPaths

import org.apache.zookeeper.WatchedEvent

/**

*

* 使用curator监听zookeeper节点

* @author qindongliang

* **/

public class CuratorWatch {

static CuratorFramework zkclient=null

static String nameSpace="php"

static {

String zkhost="192.168.46.22:2181"//zk的host

RetryPolicy rp=new ExponentialBackoffRetry(1000, 3)//重试机制

Builder builder = CuratorFrameworkFactory.builder().connectString(zkhost)

.connectionTimeoutMs(5000)

.sessionTimeoutMs(5000)

.retryPolicy(rp)

builder.namespace(nameSpace)

CuratorFramework zclient = builder.build()

zkclient=zclient

zkclient.start()// 放在这前面执行

zkclient.newNamespaceAwareEnsurePath(nameSpace)

}

public static void main(String[] args) throws Exception{

watch()

Thread.sleep(Long.MAX_VALUE)

}

/**

*

* 监听节点变化

*

* */

public static void watch()throws Exception{

PathChildrenCache cache = new PathChildrenCache(zkclient, "/zk", false)

cache.start()

System.out.println("监听开始/zk........")

PathChildrenCacheListener plis=new PathChildrenCacheListener() {

@Override

public void childEvent(CuratorFramework client, PathChildrenCacheEvent event)

throws Exception {

switch ( event.getType() )

{

case CHILD_ADDED:

{

System.out.println("Node added: " + ZKPaths.getNodeFromPath(event.getData().getPath()))

break

}

case CHILD_UPDATED:

{

System.out.println("Node changed: " + ZKPaths.getNodeFromPath(event.getData().getPath()))

break

}

case CHILD_REMOVED:

{

System.out.println("Node removed: " + ZKPaths.getNodeFromPath(event.getData().getPath()))

break

}

}

}

}

//注册监听

cache.getListenable().addListener(plis)

}

}

</pre>

运行后的控制台打印:

<pre name="code" class="java">18:33:07.722 [main] INFO o.a.c.f.imps.CuratorFrameworkImpl - Starting

18:33:07.727 [main] DEBUG o.a.curator.CuratorZookeeperClient - Starting

18:33:07.727 [main] DEBUG org.apache.curator.ConnectionState - Starting

18:33:07.727 [main] DEBUG org.apache.curator.ConnectionState - reset

18:33:07.734

[main] INFO org.apache.zookeeper.ZooKeeper - Client

environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09

GMT

18:33:07.734 [main] INFO org.apache.zookeeper.ZooKeeper - Client environment:host.name=QINDONGLIANG.dhgatecn.msf

18:33:07.734 [main] INFO org.apache.zookeeper.ZooKeeper - Client environment:java.version=1.7.0_04

18:33:07.734 [main] INFO org.apache.zookeeper.ZooKeeper - Client environment:java.vendor=Oracle Corporation

18:33:07.734 [main] INFO org.apache.zookeeper.ZooKeeper - Client environment:java.home=D:\Java\jdk1.7.0_04\jre

18:33:07.734

[main] INFO org.apache.zookeeper.ZooKeeper - Client

environment:java.class.path=D:\eclipseworkspace2yw\opzk\binD:\eclipseworkspace2yw\opzk\lib\curator-client-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\curator-examples-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\curator-framework-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\curator-recipes-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\curator-test-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\curator-x-discovery-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\curator-x-discovery-server-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\curator-x-rpc-2.6.0.jarD:\eclipseworkspace2yw\opzk\lib\log4j-1.2.15.jarD:\eclipseworkspace2yw\opzk\lib\zookeeper-3.4.5.jarD:\eclipseworkspace2yw\opzk\lib\commons-io-2.1.jar


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11581190.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-17
下一篇2023-05-17

发表评论

登录后才能评论

评论列表(0条)

    保存