丛林背景
dubbo框架的核心就是远程调用。在设计上,作者对远程调用的实现进行了分层,一共是三层:business层、rpc层与remoting层。
- business层,这一层有为RPC接口创建的动态代理对象
- rpc层,这一层的核心为Invoker链
- remoting层,封装底层通信细节,如果底层通信走netty4则这一层的核心为: NettyChannel、ChannelHandler链以及dubbo线程池
本文探秘dubbo远程调用中客户端和服务端的行为,咋们这篇不求甚解,只要在脑海中形成清晰的远程调用的流程图即可。
文章目录
- 丛林背景
- (一)客户端发起远程调用的过程
- 1.1 business层解析
- 1.2 rpc层解析
- 1.2.1 DubboInvoker
- 1.2.2 AsyncToSyncInvoker
- 1.3 remoting层解析
- 1.3.1 ExchangeClient
- 1.3.2 NettyChannel
- (二)客户端收到服务端响应的过程
- 1.1 DefaultFuture
- (三)服务端处理请求的过程
- 3.1 remoting层分析
- 3.1.1 AllChannelHandler
- 3.1.2 HeaderExchangeHandler
- 3.2 rpc层分析
- 3.2.1 AbstractProxyInvoker
(一)客户端发起远程调用的过程
以下图示是我在客户端发起一次远程调用的客户端调用链截图,整个客户端的调用链比较清晰,三层的界限圈出来了,以下将对每一层进行分析。
1.1 business层解析
RPC接口的动态代理对象持有了InvokerInvocationHandler对象。InvokerInvocationHandler对象持有了Invoker对象,并将请求委托给Invoker对象来处理。
1.2 rpc层解析
rpc层上,请求从MockClusterInvoker一直传递给DubboInvoker,可以把这一段看成一个变体的责任链。DubboInvoker位于invoker链的尾部,委托给remoting层来发送tcp请求。
1.2.1 DubboInvoker
DubboInvoker 委托给ExchangeClient对象来发起请求,请求由此传递到了remoting层,ExchangeClient.request方法返回一个CompletableFuture对象,RPC层通过CompletableFuture对象可以获取到调用的结果。
1.2.2 AsyncToSyncInvoker
AsyncToSyncInvoker是invoker链中的一个类,在invoker.invoke()方法调用返回之后,他会阻塞在
Future.get()方法中(Result实现了Future接口)直到收到一个响应结果才会接着往下执行。
所以当客户端的业务线程发起远程调用时就会阻塞在这个方法上,直到有响应结果。
1.3 remoting层解析
remoting层封装底层通信的细节。这次客户端的远程调用请求最终委托给netty4的 NioSocketChannel.writeAndFlush方法。根据netty4的React线程池模型的实现,NioSocketChannel.writeAndFlush方法是会将这次写事件提交给netty的worker线程池来执行。
1.3.1 ExchangeClient
ExchangeClient 负责 RPC层与Remoting层的数据交互,RPC层的数据实体为Invocation,Remoting层的数据实体为Request与Response。在客户端调用过程中ExchangeClient 负责将Invocation封装为Request对象。
1.3.2 NettyChannel
NettyChannel持有一个netty4的NioSocketChannel对象,并调用它的writeAndFlush来发送请求。
(二)客户端收到服务端响应的过程
客户端的netty worker线程在收到服务端发来的tcp响应包后会封装为一个ChannelEventRunnable对象并提交给DubboClientHandler线程池来处理。ChannelEventRunnable任务就是调用DefaultFuture.complete方法并传入远程调用的结果。
1.1 DefaultFuture
DefaultFuture继承了CompletableFuture类,这个类在设计上是用来获取远程调用的结果。当DubboClientHandler线程调用DefaultFuture对象的comlete方法并传入远程调用的结果,则阻塞在future.get() 的业务线程就能拿到远程调用的结果,这次调用流程基本就走完了!
(三)服务端处理请求的过程
以下截图为服务端收到远程调用请求后的调用链,我红框圈出来的是一个channelHandler链,最下层的NettyServerHandler是一个适配器,适配了dubbo自家的ChannelHandler接口并实现了netty4的ChannelHandler接口,由NettyServerHandler这个适配器作为dubbo自家的ChannelHandler链的链首。这个ChannelHandler链的链尾是AllChannelHandler。
以下截图为dubbo线程池处理上述被提交的任务,并最终调用服务对象的目标方法的调用链截图。
3.1 remoting层分析
3.1.1 AllChannelHandler
AllChannelHandler作为channelFilter链的尾部,这个地位可想而知。如以下截图所示,他会将TCP请求封装为一个ChannelEventRunnable对象,并分发给dubbo线程池。
这边还是得额外拓展以下,根据dubbo.protocol.dispatcher的配置不同,可以有以下5种选择,由于我配置的dubbo.protocol.dispatcher=all(默认的配置) 所以这边对应的分发策略为AllChannelHandler,对应这个处理器,worker线程的连接建立事件、连接失效事件、发送数据事件、接受数据事件等都会提交给dubbo线程池来处理。
3.1.2 HeaderExchangeHandler
HeaderExchangeHandler是一个比较核心的ChannelHandler类,在得到调用的结果之后它会调用NettyChannel.send(res)方法来发送结果。
3.2 rpc层分析
rpc层就是一个invoker链,重点是最后一个invoker类,就是我红框圈出来的部分 AbstractProxyInvoker
3.2.1 AbstractProxyInvoker
AbstractProxyInvoker持有了服务对象,并通过反射来调用服务对象的目标方法
对,这里是结尾,很仓促对不对hhhhhh