一、报错问题
Dubbo3注册为应用级时,Nacos注册中心看到注册服务服务和订阅列表均正常,但是实际调用时报错“No provider available for the service XXX”
二、Dubbo3注册模式介绍
dubbo3共有三种provider服务注册模式,分别为 interface(接口级)、instance(应用级)、all,默认是all(双注册,兼容模式)
大概配置如下
dubbo:
application:
name: ${spring.application.name}
#provider注册模式,可选值 interface(接口级)、instance(应用级)、all,默认是all(双注册)
register-mode: instance
metadata-service-port: -1
#consumer服务发现模式
service-discovery:
# FORCE_INTERFACE,只消费接口级地址,如无地址则报错,单订阅 2.x 地址
# APPLICATION_FIRST,智能决策接口级/应用级地址,双订阅
# FORCE_APPLICATION,只消费应用级地址,如无地址则报错,单订阅 3.x 地址
migration: FORCE_APPLICATION
registry:
address: nacos://localhost:8848?namespace=my_local
protocol:
port: -1
consumer:
check: false
provider:
filter: dubboExceptionFilter,-exception
三、踩坑记录
简单记录一下踩坑过程,当注册模式dubbo.application.register-mode=all
双注册时可以正常调用,注册模式都改为应用级注册时dubbo.application.register-mode=instance
调用报错“No provider available for the service XXX”
最终排查导致这个报错的原因是项目中自定义的日志traceId传递filter中使用了RpcContext.getContext().isProviderSide()
这行代码报错NullPointException
导致Consumer端拉取Provider端接口元数据失败,最终导致调用时报错“No provider available for the service XXX”
原来代码:
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order = MDCTraceUtils.FILTER_ORDER)
public class DubboTraceFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 使用应用级时,这行代码会报错 NullPointException
boolean isProviderSide = RpcContext.getContext().isProviderSide();
//服务提供者逻辑
if (isProviderSide) {
} else { //服务消费者逻辑
}
try {
return invoker.invoke(invocation);
} finally {
}
}
}
在这个代码中加了一行判断,如果时内置元数据拉取服务MetadataService
时,跳过当前Filter
if (MetadataService.isMetadataService(invocation.getServiceName())) {
return invoker.invoke(invocation);
}
修改后代码为
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order = MDCTraceUtils.FILTER_ORDER)
public class DubboTraceFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 如果是内置元数据服务则跳过filter,否则走下面的会报错,导致元数据拉取失败,最终导致No provider错误
if (MetadataService.isMetadataService(invocation.getServiceName())) {
return invoker.invoke(invocation);
}
boolean isProviderSide = RpcContext.getContext().isProviderSide();
//服务提供者逻辑
if (isProviderSide) {
} else { //服务消费者逻辑
}
try {
return invoker.invoke(invocation);
} finally {
}
}
}
以上代码基于dubbo-3.0.8,nacos-2.1.0调试
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.0.8</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.1.0</version>
</dependency>