写点什么

Dubbo No provider 问题排查思路

用户头像
捉虫大师
关注
发布于: 3 小时前

本文已收录 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


protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {    if (CollectionUtils.isEmpty(invokers)) {        throw new RpcException(RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER, "Failed to invoke the method "                + invocation.getMethodName() + " in the service " + getInterface().getName()                + ". No provider available for the service " + getDirectory().getConsumerUrl().getServiceKey()                + " from registry " + getDirectory().getUrl().getAddress()                + " on the consumer " + NetUtils.getLocalHost()                + " using the dubbo version " + Version.getVersion()                + ". Please check if the providers have been started and registered.");    }}
复制代码


当配置 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 订阅信息可从缓存文件中查看,缓存文件默认按如下规则生成:


String defaultFilename = System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getApplication() + "-" + url.getAddress().replaceAll(":", "-") + ".cache";
复制代码


例如:


~/.dubbo/dubbo-registry-ddog-my-demo-c0-127.0.0.1-2181.cache


有多个注册中心,将有多个缓存文件,文件内容如下:


#Dubbo Registry Cache#Wed Aug 11 20:26:15 CST 2021org.newboo.basic.api.MyDemoService=empty\://127.0.0.1/org.newboo.basic.api.MyDemoService?application\=ddog-my-demo-c0&category\=routers&check\=false&dubbo\=2.0.2&init\=false&interface\=org.newboo.basic.api.MyDemoService&loadbalance\=xxx&methods\=call&owner\=roshilikang&pid\=3084&qos.enable\=true&qos.port\=33333&release\=2.7.6&side\=consumer&sticky\=false&timestamp\=1628684774590 empty\://127.0.0.1/org.newboo.basic.api.MyDemoService?application\=ddog-my-demo-c0&category\=configurators&check\=false&dubbo\=2.0.2&init\=false&interface\=org.newboo.basic.api.MyDemoService&loadbalance\=xxx&methods\=call&owner\=roshilikang&pid\=3084&qos.enable\=true&qos.port\=33333&release\=2.7.6&side\=consumer&sticky\=false&timestamp\=1628684774590 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&timestamp\=1628684412247
复制代码


搜索文件中是否有对应服务的 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&timestamp\=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


  1. 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 错误

  2. 与 1 类似,当自定义某些扩展只在 provider 使用时,provider 的一些参数会传递给 consumer,让 consumer 也使用相同扩展,但 consumer 不一定实现了该扩展,导致 invoker 生成失败;比如自定义的 dispatcher 扩展。


注:可能你会问为什么 provider 的参数会传递给 consumer?这合理吗?举个例子,如果 provider 指定序列化协议为 json,那 consumer 是否也要按照 provider 的序列化协议 json 来传输数据呢?只能说没有万全的设计

总结

跟很多问题排查思路一样,根据已有现象一步步缩小排查范围,最终锁定根本原因。用一副思维导图来总结:





搜索关注微信公众号"捉虫大师",后端技术分享,架构设计、性能优化、源码阅读、问题排查、踩坑实践。



发布于: 3 小时前阅读数: 3
用户头像

捉虫大师

关注

还未添加个人签名 2018.09.19 加入

欢迎关注我的公众号“捉虫大师”

评论

发布
暂无评论
Dubbo No provider问题排查思路