【Spring Cloud Alibaba】(一)微服务介绍 及 Nacos注册中心实战
【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战
【Spring Cloud Alibaba】(三)OpenFeign扩展点实战 + 源码详解
【Spring Cloud Alibaba】(四)Dubbo框架介绍 及 整合Dubbo和OpenAI实战【文末附源码】
书接上文,关于Dubbo,真心好用,真心强大!但是人红是非多,偶尔还能听到关于Dubbo的各种坑的说法。
比如,消费方启动报错:Failed to check the status of the service xxx. No provider available for the service。。。
再比如,消费方启动成功后,但一直与提供方重连报错:Fail to connect to HeaderExchangeClient。。。
你真的以为这是Dubbo的坑吗?
加一个小插曲,我想做一下调查:当你遇到技术问题时你会怎么做?
报错了没见过,管它三七二十一,网上直接搜,施展搜索大法~~~
然后,网上各种文章鱼龙混杂,运气好直接解决,运气不好方法试个遍也没效果…
向同事请教,一次一次请教,倍感无奈…
对报错快速排查一下(运气好直接解决),不行再有针对性的查找资料,遇到难点再向同事(或CSDN大佬)请教。
本文就以这两个Dubbo常见问题入手,带你进入源码分析如何排查问题 !一起拉开有趣的程序人生,Let’s go!
在消费方启动时,可能会遇到以下两种场景:
不管怎么样,得先让服务启动起来吧~~~
那么,消费方启动失败,会抛出 IllegalStateException
,报错信息大致如下:
Error creating bean with name ‘xxxBean’: Injection of @DubboReference dependencies is failed; nested exception is java.lang.IllegalStateException:
Failed to check the status of the service
xxxInterfaceName.No provider available for the service
xxxInterfaceName from the url xxxUrl to the consumer xxxLocalhost use dubbo version xxxVersion
搜索报错信息Failed to check the status of the service
,可以快速定位到报错的源码,如下图:
看到if
判断条件shouldCheck()
方法了吧? 从命名就可以看出来,这是判断是否应该检查,进去看看:
没有几行代码,我想你能想到:
① :isCheck() 没有配置,默认为null
② :由于① 为null,所以主要看getConsumer()
③ :如果① 和②均没配置,第3步默认设为true,即检查是否可用!
所以,对于我们来说,主要可配置点在 getConsumer().isCheck() ,
即ConsumerConfig类的isCheck()方法
:
public Boolean isCheck() {
return check;
}
ConsumerConfig
类,从名子可以看出来:消费者配置类.
稍微找一找就可以找到,在@EnableDubbo
注解上有一个@EnableDubboConfig
注解,里面注释写着:
再到注释对应的源码里验证一下,如果你从@EnableDubboConfig
上的DubboConfigConfigurationRegistrar
进去,可以看到DubboConfigConfiguration
:
再跟进去,从这里就可以找到对应的源码:ConsumerConfig
类绑定的配置前缀为dubbo.consumer
,如下图:
综上,配置dubbo.consumer.check = false
就代表消费方启动时不检查提供方是否可用!
dubbo.consumer.check = false
这里补充说明如下:
Dubbo服务消费方在启动时,缺省会检查依赖的服务提供方是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认
check=true
。可以通过
check=false
关闭检查,比如:测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
当通过check=false
启动消费方后,还可能会遇到以下两种场景:
如果对报错的提供方 不关心,就真的不想看到一直重连的报错!
消费方启动成功,但与提供方连接失败,会一直报错并抛出 RemotingException
,报错信息大致如下:
header.ReconnectTimerTask : [DUBBO] Fail to connect to HeaderExchangeClient [channel=org.apache.dubbo.remoting.transport.netty4.NettyClient [xxx -> /xxx:20880]], dubbo version: xxxVersion, current host: xxxLocalhost
org.apache.dubbo.remoting.RemotingException: client(url: xxxURL) failed to connect to server /xxx:20880 client-side timeout 3000ms (elapsed: 3012ms) from netty client xxx using dubbo version xxxVersion
例如,我这里消费方在本地环境,提供方在DEV环境,重现的报错截图如下:
全局
或者直接到报错的ReconnectTimerTask
类中搜索报错信息Fail to connect to
,可以快速定位到报错的源码,如下:
打印的e
根据报错信息,可以确定是这里:
ReconnectTimerTask
,从名子就可以看出来:是重连的定时任务,所以,如果想让它不报错,就需要看看:是否可以不启动这个定时器,这样自然就不会打印ERROR
了,是这个逻辑吧?
OK,那我们得先找到启动定时器的地方,怎么找?
对,先查找一下ReconnectTimerTask
的类的引用,很快就定位到了HeaderExchangeClient.startReconnectTask(URL url)
方法,看名子就知道:开始重连任务。
OK,到这我不说你应该也发现了,这里有个if
判断条件shouldReconnect(url)
方法,和第一个问题的shouldCheck
都是统一命名规则,想都不用想,可以肯定就在这里控制它!
我们看一下,代码就一行,url.getParameter
内部是从Map
中查找reconnect
,找不到默认会设为true:
String RECONNECT_KEY = "reconnect";
private boolean shouldReconnect(URL url) {
return url.getParameter(Constants.RECONNECT_KEY, true);
}
那么问题来了, reconnect参数在哪配置?
这里向上查找引用的话,链路有点深,所以为了看的更清晰,我们可以打个断点,看下调用堆栈。
这样,一下就找到了入口:ReferenceConfig.get
方法,这里代码更少,主要就是调用init()
方法。
转到init()
方法的313行,传入的正是一个map
,如下图,调试发现里面竟然有check=false
,所以猜测还是与ConsumerConfig(消费者配置类)
有关,方法里再向上找一找,还真找到了ConsumerConfig
类的对象consumer
,从名子appendParameters
就知道它是往map里追加consumer的配置!所以就这样配置上了!
所以我们在dubbo.consumer
下面配一下试试,
dubbo.consumer.reconnect = false
综上,配置dubbo.consumer.reconnect = false
就代表消费方不重连提供方!
实际上,这里有一个机制,就是Dubbo的重连机制,也是为了能及早发现问题,所以生产环境建议不要修改此配置!
而这个配置多用于开发环境,用于忽略不关心的服务!
那么,对于关心的服务,需要调用的话,怎么做?
可以考虑以下两种做法:
可以通过配置Nacos服务发现group隔离服务注册,例如:
spring.cloud.nacos.discovery.group=XXX_GROUP
这样,就可以做到本地环境只调本地服务,DEV环境只调DEV服务,只需要配置相同组名即可!
因为调用链路可能会错综复杂,有时环境隔离成本太高,这时就可以转为HTTP请求,对Nginx或Gateway发起HTTP调用,这也是对上述两种场景RPC调用异常的兜底方案!
Java的开源框架,我们有时可以不用跟的太深,一样可以快速搞定一些问题!
虽然框架源码一直在变,但方法万变不离其宗,套路都是相通的,你更值得学习的是排查问题的方法,更重要的是养成独立解决问题的习惯,相信你可以做到!
如果你学会了排查问题的方法,那么你以后就会很独立,也会被你的领导和同事看到你有两把刷子,说不准还能成为疑难杂症专家!即使你在遇到难题问了师傅,他也会觉得你问的有水平,他也会为帮你解决这个问题,漏了一手而沾沾自喜!
所以,遇到问题不是坏事, 多解决问题,问题会让你的经验越来越丰富,也会让你对吃饭的框架越来越熟悉,这些都是你的财富,也可以写进简历让面试官更喜欢你。不过友情提醒,尺度把控好,项目中遇到问题切勿死磕,切勿陷入细节影响项目进度!
那么对于Dubbo RPC调用异常转HTTP调用,你知道怎么实现吗?这也是我计划将在本专栏下文分享的内容,如果感觉不错,欢迎订阅本专栏,后面还有更多的【Spring Cloud Alibaba】实战知识陆续放出。
关注我 天罡gg 分享更多干货: https://blog.csdn.net/scm_2008
大家的「关注❤️ + 点赞 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!