Dubbo No provider 问题排查思路
本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎 star。
不想看字的同学可直接划到底部查看思维导图
问题分析
使用过 Dubbo 的朋友很多都碰到过如下报错:
No provider available for the service org.newboo.basic.api.MyDemoService from registry 127.0.0.1:2181 on the consumer 127.0.0.1 using the dubbo version 2.7.6. Please check if the providers have been started and registered.
从源码来看这个报错位于
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#checkInvokers
当配置 reference 的 check=false 时调用它的代码位于
org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke
(为 true 时在启动时校验)
从代码能看出导致这个报错的直接原因是:invokers
为空
此处 invoker 对应一个 provider URL,当没有 provider 可用时,invokers 为空
排查思路
这个问题看似简单,但实际情况异常复杂,碰到后无从下手,本文提供一种可行的排查思路。
排查大致分为两条线,provider 端和 consumer 端。
provider 端
出问题第一时间排查 provider,因为 provider 的情况比较少,可以简单地排除一部分情况。
provider 出问题只有一种情况:未注册到注册中心
所以对应的排查思路是去看 provider 有没有注册成功:
如果有 dubbo 控制台或者注册中心查询页面,直接查询一下即可
如果没有可视化界面,比如 zk、etcd 可通过相应的客户端连上去查看是否注册成功
以 zk 为例,可通过 ls /dubbo/${service}/providers
查看注册上的 provider
如果 provider 未注册成功,那么就需要排查,可能的原因有:
provider 未启动成功,启动一下即可
provider 虽然启动了,但注册失败了,查看一下错误日志,对症解决
注册中心地址是否写错?环境是否一致?
如果 provider 已经注册,说明 provider 没问题,再看 consumer。
consumer 端
consumer 端排查还需再细分,以是否订阅(拉取)到对应 provider 信息为界
如何查看 consumer 的订阅信息
consumer 订阅信息可从缓存文件中查看,缓存文件默认按如下规则生成:
例如:
~/.dubbo/dubbo-registry-ddog-my-demo-c0-127.0.0.1-2181.cache
有多个注册中心,将有多个缓存文件,文件内容如下:
搜索文件中是否有对应服务的 provider
未成功订阅
如果没拿到信息(搜索不到对应的 provider),说明订阅存在问题,检查 consumer 日志是否有报错,注册中心地址,环境等配置是否有问题。
成功订阅
比如这个文件,存在
dubbo\://127.0.0.1\:20880/org.newboo.basic.api.MyDemoService?anyhost\=true&application\=ddog-my-demo-p0&deprecated\=false&dubbo\=2.0.2&dynamic\=true&generic\=false&interface\=org.newboo.basic.api.MyDemoService&methods\=call&owner\=roshilikang&pid\=2058&release\=2.7.6&side\=provider&threads\=500×tamp\=1628684412247
说明 consumer 已经拿到了 provider 信息
当 consumer 拿到 provider,也不一定就能保证调用不会报 No provider,有这么几种情况需要排查
检查 consumer 的 group、version 是否和 provider 完全匹配,不匹配会报 No provider
是否被禁用,搜索缓存文件中是否有该服务对应的 override URL,且 disabled=true
consumer 是否配置了路由规则,如 tag 路由,条件路由等,路由规则可能导致 No provider
group、version 是否匹配,有一个不看代码就知道 consumer 的 version、group 配置的小技巧,如果 consumer 指定了 version 或 group,报错信息如下(group=read,version=1.0):
No provider available from registry 127.0.0.1:2181 for service read/org.newboo.basic.api.MyDemoService:1.0 on consumer 127.0.0.1 use dubbo version 2.7.6
service 前包含 group,用斜线分隔,service 后有 version 用冒号分隔。
以上可覆盖 95%的场景,还有一种比较少见:consumer 生成 invoker 失败导致 invokers 为空;
此种情况请仔细检查错误日志,不明的报错需要关注。此处列举一些碰到过的 case
Dubbo 2.6.x 中 transport 实现了 netty 和 netty4,而在 2.6.10 版本中,netty transport 扩展名字被改为了 netty3;如果 provider 使用 dubbo 2.6.10 且指定了 transport 为 netty3,低版本的 dubbo 调用时因为没有实现 netty3 的扩展而导致 invoker 生成失败;此时 consumer 端看起来是拿到了 provider 的 URL,但也会报 No provider 错误
与 1 类似,当自定义某些扩展只在 provider 使用时,provider 的一些参数会传递给 consumer,让 consumer 也使用相同扩展,但 consumer 不一定实现了该扩展,导致 invoker 生成失败;比如自定义的 dispatcher 扩展。
注:可能你会问为什么 provider 的参数会传递给 consumer?这合理吗?举个例子,如果 provider 指定序列化协议为 json,那 consumer 是否也要按照 provider 的序列化协议 json 来传输数据呢?只能说没有万全的设计
总结
跟很多问题排查思路一样,根据已有现象一步步缩小排查范围,最终锁定根本原因。用一副思维导图来总结:
搜索关注微信公众号"捉虫大师",后端技术分享,架构设计、性能优化、源码阅读、问题排查、踩坑实践。
版权声明: 本文为 InfoQ 作者【捉虫大师】的原创文章。
原文链接:【http://xie.infoq.cn/article/20615e66fa4c650753a050f60】。文章转载请联系作者。
评论