当前位置: 首页 > article >正文

同时使用注解和 xml 的方式引用 dubbo 服务产生的异常问题排查实战

文章目录

      • 一、现象
      • 二、问题排查
      • 三、结论
      • 四、解决方案

一、现象

使用 nacos 作注册中心的线上 dubbo 消费端应用每隔 1 分钟就会抛出以下异常(为使描述简单化,文章中使用本地 demo 来复现),该异常表示无法连接到 172.17.0.1:20881 这台提供端

21:11:49.843 [dubbo-client-idleCheck-thread-1] ERROR org.apache.dubbo.remoting.exchange.support.header.ReconnectTimerTask.doTask(51) -  [DUBBO] Fail to connect to HeaderExchangeClient [channel=org.apache.dubbo.remoting.transport.netty4.NettyClient [172.17.0.1:0 -> /172.17.0.1:20881]], dubbo version: 2.7.3, current host: 172.17.0.1
org.apache.dubbo.remoting.RemotingException: client(url: dubbo://172.17.0.1:20881/com.example.dubbo.HelloService?anyhost=true&application=dubbo-consumer-app&bean.name=com.example.dubbo.HelloService&category=providers&check=false&codec=dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&heartbeat=60000&interface=com.example.dubbo.HelloService&lazy=false&methods=sayHello&path=com.example.dubbo.HelloService&pid=56029&protocol=dubbo&register=true&register.ip=172.17.0.1&release=2.7.3&remote.application=dubbo-provider-app&server=netty4&side=consumer&sticky=false&timestamp=1683113373687) failed to connect to server /172.17.0.1:20881, error message is:拒绝连接: /172.17.0.1:20881
	at org.apache.dubbo.remoting.transport.netty4.NettyClient.doConnect(NettyClient.java:166)
	at org.apache.dubbo.remoting.transport.AbstractClient.connect(AbstractClient.java:190)
	at org.apache.dubbo.remoting.transport.AbstractClient.reconnect(AbstractClient.java:246)
	at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeClient.reconnect(HeaderExchangeClient.java:155)
	at org.apache.dubbo.remoting.exchange.support.header.ReconnectTimerTask.doTask(ReconnectTimerTask.java:49)
	at org.apache.dubbo.remoting.exchange.support.header.AbstractTimerTask.run(AbstractTimerTask.java:87)
	at org.apache.dubbo.common.timer.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:648)
	at org.apache.dubbo.common.timer.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:727)
	at org.apache.dubbo.common.timer.HashedWheelTimer$Worker.run(HashedWheelTimer.java:449)
	at java.lang.Thread.run(Thread.java:748)
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: 拒绝连接: /172.17.0.1:20881
	at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
	at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
	at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:325)
	at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:340)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:635)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:582)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:499)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:461)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	... 1 more
Caused by: java.net.ConnectException: 拒绝连接
	... 11 more

二、问题排查

经过确认,172.17.0.1:20881 这台提供端确实已经下线,所以才会无法连接。

通过查询 dubbo 源码得知,ReconnectTimerTask 是一个定时任务,其实例被 DubboInvoker 实例持有,当 DubboInvoker 对应的消费端服务与对端的提供端服务断开连接时,该定时任务就会定时重连提供端。正常情况下不会出现这种异常,因为提供端下线以后,会通过注册中心通知到消费端,消费端对应的 DubboInvoker 实例会被销毁,从而重连定时任务也会被销毁。

找到出问题的 HelloService 在应用中的使用方式,发现既有通过 @Reference 注解的方式使用,又有通过 xml 配置的方式使用。首先,将 arthas 连接到出问题的消费端应用,然后执行以下命令

ognl '#context=@org.apache.dubbo.config.spring.extension.SpringExtensionFactory@CONTEXTS.iterator.next, #context.getBean("helloService").handler.invoker.directory.urlInvokerMap'

得到结果为

在这里插入图片描述

发现 HelloService 服务的 RegistryDirectory 实例中确实还存在已经下线的提供端,说明提供端下线后该消费端没有感知到

接着,使用 arthas 监控看看消费端的服务监听 notify 方法是否生效,运行以下命令

watch org.apache.dubbo.registry.support.FailbackRegistry notify params

然后,将 20880 那台服务提供端也下线,看看 watch 命令的输出,如下所示

在这里插入图片描述

说明服务下线通知功能是正常的,不过这里的 RegistryDirectory 实例和上面使用 ognl 表达式查询的 RegistryDirectory 实例不是同一个,使用 ognl 表达式查询的实例如下

在这里插入图片描述

说明 HelloService 服务被 refer 了两次,也就是生成了两个服务引用,但是只有一个引用的服务监听生效。

三、结论

联系到 HelloService 在应用中有注解和 xml 两种引用方式,调试一遍服务引用的创建过程,发现在 NacosRegistry 中有这么一段服务订阅代码

在这里插入图片描述

这段代码的意思是,当相同的服务引用被创建了两次,只有第一次创建的引用会订阅服务。所以通过注解和 xml 两种方式创建 HelloService 服务引用时,会导致其中一个引用不会订阅服务变更,导致无法感知提供端下线,就会出现不断重连提供端的现象。

四、解决方案

应用中应当禁止同时使用注解和 xml 的方式来引用 dubbo 服务。


http://www.kler.cn/a/16596.html

相关文章:

  • Excel筛选的操作教程
  • docker构建jdk11
  • 鸿蒙学习基本概念
  • JAVA题目笔记(十五)经典算法题
  • 【前端】Vue中如何避免出现内存泄漏
  • webpack loader全解析,从入门到精通(10)
  • 抓马,互联网惊现AI鬼城:上万个AI发帖聊天,互相嗨聊,人类被禁言
  • ASIC-WORLD Verilog(6)运算符
  • 【.net core 自动生成数据库】
  • 认识Cookie和Session
  • 【算法】求最短路径算法
  • react之按钮鉴权
  • Java微服务商城高并发秒杀项目--013.SentinelResource的使用
  • 算法刷题|392.判断子序列、115.不同的子序列
  • 大型医院影像PACS系统三维重建技术(获取数据、预处理、配准、重建和可视化)
  • Stable Diffusion 本地部署教程不完全指南
  • 第18章 项目风险管理
  • javascript中的严格模式
  • 自动驾驶行业观察之2023上海车展-----车企发展趋势(1)
  • Python基础合集 练习19(类与对象3(多态))
  • Chapter4:频率响应法(上)
  • Linux套接字编程-2
  • Packet Tracer - 静态路由故障排除
  • 如何学习python?
  • 【C++】右值引用完美转发
  • 什么是 Docker?它能用来做什么?