2020年笔者在做微服务部件升级时,Dubbo的注册中心从Zookeeper切换到Nacos碰到个问题,最近刷Github又有网友提到类似的问题,就在这篇文章里做个梳理和总结。

1、问题描述

前几年我在做微服务部件升级时,将Dubbo的注册中心从Zookeeper切换到Nacos。切换的原因是有2点:

  • Zookeeper保障了CP,面对大量服务上下线时,吞吐量和响应有瓶颈。Nacos保障了AP,目前微服务的场景下,业界建议优先保障AP,这样有较好的吞吐量和较快的响应。
  • 本着能少用部件就少用,尽量减少故障点的原则。Nacos既可以做注册中心也可以做配置中心,所以二合一,只采用一个部件。

切换完之后,奇怪的事情发生了,出现2个现象:

  • 有些微服务启动很慢很慢,甚至长达15分钟的时间都无法成功启动,一直在打印大量的nacos请求日志。但是有些微服务启动又较快。
  • 通过VisualVM查看JVM的线程情况,发现有的微服务居然高达4000左右的线程数。但是没切换之前只有几百的线程数。启动了大量的线程,导致CPU飙升不少,同时服务启动也慢。

2、通过现象开始排查

出现这种问题时,刚开始有点抓瞎,但是我们只能从常规的手段一点点排查,急不来。通过表面的现象,我们来逐步分析。

现象一:微服务启动很慢很慢,一直在打印大量的nacos请求日志。日志如下:

现象二:JVM的线程数高达4000左右。线程情况如下:

基于以上现象,我们只能初步判断是nacos的问题(当然结论不是nacos的问题)。

我们先才猜测:可能由于某种原因,产生了大量的nacos线程,每个线程又在不停的发送http请求。

那接下来继续分析Nacos。

3、分析Nacos

回顾Nacos原理

我们知道Nacos客户端注册和订阅服务流程大概如下:

所以,一般nacos-client有4个重要线程:

  • 定时从nacos-server拉取服务的线程
  • 维持心跳的线程
  • 监听服务变更的线程
  • 推送本服务变更信息的线程

分析Nacos

根据以上线程的名称和原理流程图,我们可以在nacos源码里找到对应的位置,代码如下:

翻看每个线程里执行的任务,确实能找到他们都在向nacos-server发送对应的的http的api请求:

既然找到了创建线程和发起http调用的原因,那就继续查看是哪里调用的。

此时会自然想到dubbo了,因为dubbo采用nacos作为注册中心,自然要依赖nacos-client创建出nacos注册中心相关的类,然后从中获取到微服务的元数据信息。

4、Dubbo登场

在翻看Dubbo源码之前,先回顾下Dubbo是怎样基于引用配置文件或者引用配置注解创建Proxy的,大致流程如下:

ReferenceAnnotationBeanPostProcessor#doGetInjectedBean

ReferenceAnnotationBeanPostProcessor#buildReferenceBeanIfAbsent

ReferenceBeanBuilder#build

ReferenceBean#afterPropertiesSet

ReferenceConfig#init

至此完成了referenceProxy的创建。

重点看ReferenceConfig#init方法,方法里有一行代码:ref = createProxy(map);,顺着这行代码往里走,如下:

RegistryProtocol#refer

AbstractRegistryFactory#getRegistry

重点来了重点来了重点来了核心代码和注释见下图

总之是:因为在上面ReferenceConfig#init方法里引入了timestamp参数,同时又因为NacosRegistryFactory又自己实现了一套createRegistryCacheKey方法,这个方法里没有截掉timestamp参数,所有就会导致从缓存里取不到注册中心信息,所有就会不停的去创建,从而又创建了更多的线程,从而发送了很多http请求。

再次查看ReferenceConfig#init方法的源码,确实是加入了timestamp参数:

至此问题的原因已经找到了,接下来就是如何解决了。

5、解决方法

解决方法也很简单,就是在Dubbo的NacosRegistryFactory类里面截掉timestamp参数。

遗憾的是,我当时发现了这个问题时,打算给Dubbo官方发issue的,发现已经有网友抢先一步发了issue,并且已经合并到2.7.9分支里了。

以下是解决方法的代码截图:

两个版本处理URL的结果如下:

2.7.8版本:
nacos://10.20.1.13:8848,10.20.1.14:8848,10.20.1.15:8848/org.apache.dubbo.registry.RegistryService?application=ehome-cloud&application.version=1.0&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&namespace=dev-jzj&owner=ehome-cloud-owner&pid=21335&qos.enable=false&release=2.7.8&timestamp=1712545856489 2.7.9版本:
nacos://10.20.1.13:8848,10.20.1.14:8848,10.20.1.15:8848/org.apache.dubbo.registry.RegistryService?namespace=dev-jzj

这个问题是在dubbo的2.7.8版本出现的,最后通过将2.7.9的修复class替换了2.7.8的NacosRegistryFactoryclass类,然后重新打了dubbo依赖包,问题得以解决。

有朋友会问:为啥不是引用2.7.9呢?因为我担心2.7.9有其他问题,所以做个class替换,然后继续用2.7.8是个较好的方式。

6、总结

本文主要梳理了Dubbo使用Nacos注册中心的坑,同时也讲述了,出现问题时,如何一步一步排查。透过现象结合源码,逐步找到问题的真相。

当然在排查之前,就需要对Dubbo和Nacos有一定的了解。所以各位朋友,在平时还是要多积累,多深入原理,这样遇到问题才能顺利解决。

本篇完结!欢迎点赞 关注 收藏!!!

原文链接:https://mp.weixin.qq.com/s/r4O4d2gAwA8LfJ1Ir98nmg

======>>>>>> 关于我 <<<<<<======

深度剖析:Dubbo使用Nacos注册中心的坑的更多相关文章

  1. Spring Cloud 系列之 Alibaba Nacos 注册中心(一)

    前言 从本章节开始,我们学习 Spring Cloud Alibaba 相关微服务组件. Spring Cloud Alibaba 介绍 Spring Cloud Alibaba 致力于提供微服务开发 ...

  2. SpringCloud Alibaba实战(7:nacos注册中心管理微服务)

    源码地址:https://gitee.com/fighter3/eshop-project.git 持续更新中-- 在上一节我们已经完成了Nacos Server的本地部署,这一节我们学习如何将Nac ...

  3. Nacos注册中心之概要设计

    本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star. 前言 在之前的文章中分析了Nacos配置中心,配置中心的核心是配置的创建.读取.推送. 注册中 ...

  4. Nacos注册中心和配置中心流程原理

    一.Nacos注册中心 1.服务启动后---->服务注册原理 springCloud集成Nacos实现原理: 服务启动时,在spring-cloud-commons包下 spring.facto ...

  5. dubbo支持的注册中心

    dubbo支持的注册中心 Dubbo提供的注册中心有如下几种类型可供选择: Multicast注册中心 Zookeeper注册中心 Redis注册中心 Simple注册中心 ZooKeeper是一个开 ...

  6. 80%面试官不知道的dubbo → 【redis注册中心】

    dubbo的redis注册中心配置和注意事项 配置provider和consumer项目的pom.xml,增加如下2个依赖: org.apache.commons commons-pool2 2.4. ...

  7. Spring Cloud Alibaba 使用nacos 注册中心

    ### 背景 上一文我们讲到了如何去搭建注册中心,这一次我们讲述如何使用nacos作为注册中心 ### spring-cloud-alibaba-basis 创建基础依赖 首先我们创建一个spring ...

  8. Spring Cloud 系列之 Alibaba Nacos 注册中心(二)

    本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Alibaba Nacos 注册中心(一) 本篇文章讲解 Nacos 注册中心集群环境搭建. Nacos 集群环境搭建 ...

  9. 手动造轮子——为Ocelot集成Nacos注册中心

    前言     近期在看博客的时候或者在群里看聊天的时候,发现很多都提到了Ocelot网关的问题.我之前也研究过一点,网关本身是一种通用的解决方案,主要的工作就是拦截请求统一处理,比如认证.授权.熔断. ...

  10. Spring Cloud Alibaba(4)---Nacos(注册中心)

    Nacos(注册中心) 有关Spring Cloud Alibaba之前写过三篇文章. Spring Cloud Alibaba(1)---入门篇 Spring Cloud Alibaba(2)--- ...

随机推荐

  1. 用BootstrapBlazor制作修改订单字段的页面

    1.在Shared文件夹下新增一个razor 2.页面初始化的时候获取订单信息 准备一个名为OrderId的参数 准备重写页面初始化时的方法 改成异步的形式来重写 4.获取数据 就3行代码. 声明这个 ...

  2. 【Azure Developer】使用 Azure VM 上的用户分配托管标识访问 Azure Key Vault 中国区代码示例

    问题描述 在Global版本的Azure Key Vault 文档中,有一节介绍在Azure VM中使用标识获取访问令牌,调用Key Vault中的资源.但是在示例中,只有curl的命令执行,而没有代 ...

  3. Java 常用类 String的常用方法(2)

    1 /** 2 * String 常用方法(2) 3 * boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束 4 * boolean startsWith ...

  4. Python文件操作系统

    [一]文件操作基本流程 # 1. 打开文件,由应用程序向操作系统发起系统调用open(...),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f f=open('a.txt', ...

  5. 超低功耗mcu芯片AMA3B 开发备忘之初串口打印

    一 前言   对于软件工程师来说,没什么比看到一个hello world的打印更让人感觉兴奋了.调试芯片,很多人都知道,hello world这个打印意味着什么.   二 软硬件准备   1 一个AM ...

  6. 使用supervisor后台运行celery

    一.先安装supervisor 1.安装命令: $ pip install supervisor 如果在沙盒环境下安装不上的话使用: $ apt-get install supervisor 二.安装 ...

  7. 四种方式实现点击chrome链接在ie中显示页面

    1.c++ socket通过浏览器在ie中打开指定url github源码:https://github.com/iamzken/cpp-open-ie 2.vb生成exe,url访问exe启动ie并 ...

  8. PAT 甲级【1007 Maximum Subsequence Sum】

    本题是考察动态规划与java的快速输入: max[i]表示第i个结尾的最大的连续子串和.b begin[i]表示第[begin[i],i]为最大和的开始位置 超时代码: import java.io. ...

  9. python基础七(函数名称空间及作用域、函数对象、函数嵌套、闭包函数、装饰器)

    一 名称空间(namespaces):存放名字的地方,是对栈区的划分. 有了名称空间之后,就可以在栈区中存放相同的名字,详细的名称空间.分三种1.1 内建名称空间存放的名字:存放的python解释器内 ...

  10. 上位机连接PLC

    上位机使用Hsl框架连接PLC 顺便讲下策略模式 话不多说,直接上代码 public interface IPlcHost { bool ConnectionPlc(string path); } p ...