zookeeper中dubboo节点过多导致dubbo-admin启动失败排查

mac2026-01-19  7

1、起因

    新需求开发了一个新接口,在联调环境正常注册,到了测试环境,调用方找不到对应接口;

 

   通过dubbo-admin,查看服务注册情况,发现以下情况:   1、新接口 和 其他旧接口  均未在dubbo管理后台展示;   2、日志输出显示,服务正在被正常调用;   3、在dubbo管理后台操作禁用,启用等操作均不生效。

2、排查

2.1、重启

  由于dubbo服务能正常使用,而dubbo-admin却不能及时的更新数据,怀疑是dubbo-admin服务问题,于是尝试重启dubbo-admin服务。

  结果原先还能看到管理界面的dubbo-admin直接罢工,查看日志发现报了“数据包体过大,终止响应”的异常,从而导致dubbo-admin一直未能拉取到注册到zookeeper的dubbo服务信息,进而启动失败;

 

2.2、查看节点数据

 既然是响应包体过大,于是便打算通过zookeeper的客户端直连查看dubbo节点数据都有啥,发现客户端也因为数据包体响应过大而不能连上

 

2.3、jute.maxbuffer

 转换思路,既然是响应体过大,导致连接失败,那就尝试看能不能调整响应包的大小,于是求助度娘,搜索zoookeeper的相关参数,

 发现通过修改“jute.maxbuffer” 的参数大小,可以调整zookeeper的对外响应包体大小。

 

3、尝试

3.1、发现异常节点

通过在启动命令后添加 “-Djute.maxbuffer=41943040” ;

 

果然没有再报响应包过大的异常,但是查看启动日志,却发现打印出了大量的不符合规范的 dubbo服务节点

 

并且最终由于过多的异常节点,导致内存溢出,宣导服务还是启动失败。

 

3.2、删除异常节点

        既然发现了大量的异常节点,那么自然的就是通过遍历将其删除。

        删除规则也相对简单,因为项目注册的服务均是以 com 开始的,因此一旦发现不是以 com开始的就直接将之删除。

PS:链接zookeeper的代码也需要设置参数“”,否则一样会包报“响应包”过大的异常。

 

 

运行代码后,发现在zookeeper中,一旦子节点有数据(官方解释为:不允许删除非叶子节点),是不允许直接对其进行删除动作的。通过递归函数将所有的不符合规范的节点删除。

public class BaseZookeeper implements Watcher { private ZooKeeper zookeeper; /** * 超时时间 */ private static final int SESSION_TIME_OUT = 20000; private CountDownLatch countDownLatch = new CountDownLatch(1); @Override public void process(WatchedEvent event) { if (event.getState() == KeeperState.SyncConnected) { System.out.println("Watch received event"); countDownLatch.countDown(); } } /** * 连接zookeeper * * @param host * @throws Exception */ public void connectZookeeper(String host) throws Exception { zookeeper = new ZooKeeper(host, SESSION_TIME_OUT, this); countDownLatch.await(); System.out.println("zookeeper connection success"); } /** * 创建节点 * * @param path * @param data * @throws Exception */ public String createNode(String path, String data) throws Exception { return this.zookeeper.create(path, data.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } /** * 获取路径下所有子节点 * * @param path * @return * @throws KeeperException * @throws InterruptedException */ public List<String> getChildren(String path) throws KeeperException, InterruptedException { List<String> children = zookeeper.getChildren(path, false); return children; } /** * 获取节点上面的数据 * * @param path * 路径 * @return * @throws KeeperException * @throws InterruptedException */ public String getData(String path) throws KeeperException, InterruptedException { byte[] data = zookeeper.getData(path, false, null); if (data == null) { return ""; } return new String(data); } /** * 设置节点信息 * * @param path * 路径 * @param data * 数据 * @return * @throws KeeperException * @throws InterruptedException */ public Stat setData(String path, String data) throws KeeperException, InterruptedException { Stat stat = zookeeper.setData(path, data.getBytes(), -1); return stat; } /** * 删除节点 * * @param path * @throws InterruptedException * @throws KeeperException */ public void deleteNode(String path) throws InterruptedException, KeeperException { zookeeper.delete(path, -1); } /** * 获取创建时间 * * @param path * @return * @throws KeeperException * @throws InterruptedException */ public String getCTime(String path) throws KeeperException, InterruptedException { Stat stat = zookeeper.exists(path, false); return String.valueOf(stat.getCtime()); } /** * 获取某个路径下孩子的数量 * * @param path * @return * @throws KeeperException * @throws InterruptedException */ public Integer getChildrenNum(String path) throws KeeperException, InterruptedException { int childenNum = zookeeper.getChildren(path, false).size(); return childenNum; } /** * 关闭连接 * * @throws InterruptedException */ public void closeConnection() throws InterruptedException { if (zookeeper != null) { zookeeper.close(); } } } public static void main(String[] args) { BaseZookeeper zookeeper = new BaseZookeeper(); try { // 链接zookeeper zookeeper.connectZookeeper("zookeeper.szy.com:2181"); String path = "/dubbo"; // 查询dubbo节点下的所有子节点 List<String> children = zookeeper.getChildren(path); // 输出节点总长度 System.out.println(children.size()); // 遍历dubbo节点下的子节点 for (int i = 0; i < children.size(); i++) { String childPath = children.get(i); System.out.println("遍历第"+i+"个"); // 如果不是符合规范的dubbo节点则直接删除 if(childPath.startsWith("com")){ continue; }else{ // 删除异常的dubbo子节点 childDel(zookeeper,path+"/"+childPath); } } } catch (Exception e) { e.printStackTrace(); }finally{ try { // 关闭连接 zookeeper.closeConnection(); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 方法描述:遍历删除子节点 * @param zookeeper * @param childPath * @throws Exception */ private static void childDel(BaseZookeeper zookeeper,String childPath)throws Exception{ // 获取当前节点路径下的所有子节点 List<String> childs = zookeeper.getChildren(childPath); // 如果还有子节点,则继续遍历这些子节点 if(childs.size()>0){ for (String child : childs) { childDel(zookeeper, childPath+"/"+child); } }else{ // 如果当前子节点(叶子节点),则执行删除动作 zookeeper.deleteNode(childPath); System.out.println("删除节点-->"+childPath); } }

再次启动dubbo-admin项目,恢复正常。

4、关键

4.1、可以通过参数  jute.maxbuffer 来调整 zookeeper的写入和响应包大小

4.2、zookeeper不能直接删除父节点,需要将其子节点均删干净后才能删除父节点

4.3、jute.maxbuffer 的值不能被设置成过大,会影响zookeeper的数据写入和同步性能

 

5、待解决

  由于没能及时打印异常dubbo接口的详细数据,无法准确分析其来源,只能等待后续再次出现类似数据时加以分析解决。

最新回复(0)