dubbo 2.6.0 调用过程
异常堆栈
at com.service.lmpl.client.ChatServiceImpl.getTalkMsg(LrbServiceMsgServiceImpl.java:1299)
at com.alibaba.dubbo.common.bytecode.Wrapper80.invokeMethod(Wrapper80.java)
at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:45)
at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:71)
at com.alibaba.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke(DelegateProviderMetaDataInvoker.java:48)
at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:52)
at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:61)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:74)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:41)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:77)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:71)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:131)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:37)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:37)
at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:68)
at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:98)
at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:96)
at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:168)
at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:50)
at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:79)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)
让我们分析这个异常堆栈,从下往上讲解 Dubbo 的调用过程:
线程启动 (
java.lang.Thread.run
):- 调用链的起点是 Java 线程的启动。
Thread.run
方法是所有线程执行的入口。
- 调用链的起点是 Java 线程的启动。
线程池执行 (
ThreadPoolExecutor$Worker.run
):- 线程池中的工作线程开始执行任务。这里使用的是
ThreadPoolExecutor
,它管理并调度线程池中的线程。
- 线程池中的工作线程开始执行任务。这里使用的是
线程池调度 (
ThreadPoolExecutor.runWorker
):ThreadPoolExecutor
的runWorker
方法调度并执行具体的任务。这个任务对应的是一个 RPC 请求的处理。
通信层处理 (
ChannelEventRunnable.run
):ChannelEventRunnable
是 Dubbo 中的一个类,用于处理通信通道中的事件。在这里,它执行了网络事件的处理。
解码器处理 (
DecodeHandler.received
):DecodeHandler
是 Dubbo 中的一个处理器,用于对收到的数据进行解码。它将解码后的数据传递给下一个处理器。
请求处理 (
HeaderExchangeHandler.received
):HeaderExchangeHandler
负责处理解码后的请求,主要是对请求进行处理和响应。
协议层调用 (
HeaderExchangeHandler.handleRequest
):- 这个方法具体负责处理接收到的请求,并调用相应的服务方法。
Dubbo 协议 (
DubboProtocol$1.reply
):DubboProtocol
是 Dubbo 中的核心协议处理器,负责将调用分发到具体的服务实现上。这里的reply
方法是处理响应的。
过滤器链调用 (
ProtocolFilterWrapper$1.invoke
):- 这个调用标志着过滤器链的开始,过滤器会逐层包裹并处理请求。过滤器链的执行顺序是由内向外的顺序(先执行内部,再执行外部)。
各类过滤器:
EchoFilter.invoke
,ClassLoaderFilter.invoke
,GenericFilter.invoke
,ContextFilter.invoke
,TraceFilter.invoke
,TimeoutFilter.invoke
,MonitorFilter.invoke
,ExceptionFilter.invoke
:这些过滤器在请求被处理前后插入额外的逻辑,比如日志、监控、超时处理等。
服务调用 (
InvokerWrapper.invoke
):InvokerWrapper
负责调用实际的服务实现,它是一个Invoker
的包装器。
元数据包装器 (
DelegateProviderMetaDataInvoker.invoke
):DelegateProviderMetaDataInvoker
是对服务提供者的元数据进行包装和管理。
抽象代理调用 (
AbstractProxyInvoker.invoke
):AbstractProxyInvoker
是服务调用的抽象层,通过它来调用实际的服务实现。
代理调用 (
JavassistProxyFactory$1.doInvoke
):- 这是 Dubbo 动态代理生成的代理类,通过 Javassist 技术生成,用来代理实际的服务调用。
动态代理方法调用 (
Wrapper80.invokeMethod
):Wrapper80
是由 Dubbo 生成的动态代理类的字节码,负责调用目标方法。
业务逻辑层 (
ChatServiceImpl.getTalkMsg
):- 最终,调用到了业务代码中的
ChatServiceImpl.getTalkMsg
方法,这里是具体的业务逻辑执行点,也是异常发生的地方。
- 最终,调用到了业务代码中的
服务地址
zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=app-backend-api&dubbo=2.6.0&interface=com.interface.api.client.IndexApi&logger=slf4j&methods=getCityList,getToken&pid=147470®ister.ip=172.17.0.1&revision=0.0.1-SNAPSHOT&side=consumer&timeout=3000×tamp=1726526308198
这是一条 Dubbo 框架中使用的服务引用地址,采用了 ZooKeeper 作为注册中心。下面我们逐一分析地址中的各个部分及其含义:
协议和注册中心地址:
zookeeper://127.0.0.1:2181
:- 协议(scheme):
zookeeper
,表示使用 ZooKeeper 作为注册中心协议。 - 注册中心地址:
127.0.0.1:2181
,表示注册中心的主机地址是本地(127.0.0.1
),端口是2181
,这是 ZooKeeper 的默认端口。
- 协议(scheme):
服务路径:
/com.alibaba.dubbo.registry.RegistryService
:- 服务接口全限定名:
com.alibaba.dubbo.registry.RegistryService
,这是在注册中心中存储服务信息的路径,表示正在引用或注册的服务接口。
- 服务接口全限定名:
查询参数(Query Parameters):
application=app-backend-api
:- 应用名称:
app-backend-api
,标识当前应用的名称。
- 应用名称:
dubbo=2.6.0
:- Dubbo 版本:
2.6.0
,表示使用的 Dubbo 框架版本。
- Dubbo 版本:
interface=com.interface.api.client.IndexApi
:- 服务接口:
com.interface.api.client.IndexApi
,表示正在引用或提供的服务接口的全限定名。
- 服务接口:
logger=slf4j
:- 日志框架:
slf4j
,指定使用 SLF4J 作为日志记录框架。
- 日志框架:
methods=getCityList,getToken
:- 方法列表:列出了该服务接口提供的所有方法名称,供消费者调用。
pid=147470
:- 进程 ID:
147470
,表示当前应用进程的进程号。
- 进程 ID:
register.ip=172.17.0.1
:- 注册 IP:
172.17.0.1
,表示在注册中心中登记的 IP 地址,可能是容器或虚拟机的内部 IP。
- 注册 IP:
revision=0.0.1-SNAPSHOT
:- 服务版本:
0.0.1-SNAPSHOT
,表示服务接口的版本号,通常用于管理服务的迭代和兼容性。
- 服务版本:
side=consumer
:- 角色:
consumer
,表示当前应用在该服务中扮演的是消费者的角色,而非提供者。
- 角色:
timeout=3000
:- 超时时间:
3000
,表示服务调用的超时时间为 3000 毫秒(3 秒)。
- 超时时间:
timestamp=1726526308198
:- 时间戳:
1726526308198
,表示注册或引用服务的时间戳,单位为毫秒。这个时间戳可以用于跟踪服务的注册时间。
- 时间戳:
总结:
- 这条地址表示一个名为
app-backend-api
的应用,作为消费者(side=consumer
),使用 Dubbo 2.6.0 框架,通过 ZooKeeper 注册中心(位于127.0.0.1:2181
)引用了服务接口com.interface.api.client.IndexApi
。 - 该服务接口的版本是
0.0.1-SNAPSHOT
,提供了多个方法供调用。 - 应用使用 SLF4J 作为日志框架,设置了服务调用的超时时间为 3 秒。
- 进程 ID 和注册 IP 提供了应用的运行时信息,时间戳记录了引用服务的具体时间。
通过解析这些信息,可以更好地理解应用与服务之间的调用关系,以及在分布式系统中的部署和配置情况。