Dubbo源码分析:客户端基于dubbo协议的RPC并发调用

撸了今年阿里、腾讯和美团的面试,我有一个重要发现…….

作者:backend

出处:https://blog.csdn.net/u010013573/article/category/8462451


概述

对consumer而言,Dubbo协议对每个Service默认是基于Netty单一长连接和NIO异步通讯的,适合小数据大并发的服务调用。在consumer端,会对需要调用的每个服务都创建一个服务代理bean,即Reference,该服务代理bean在consumer就是一个跟使用Spring的@Service注解修饰的普通Service类bean一样注册到spring容器,也是单例的。

consumer端Service代理

Service在consumer端的服务Service代理的核心组件

  1. 客户端Service代理:每个远程Service接口,在consumer端对应dubbo-config包的一个ReferenceBean实例;
  2. 客户端Service调用器:ReferenceBean实例为一个服务代理refer,服务代理refer包含一个dubbo-rpc-dubbo包的DubboInvoker调用器invoker实例;
  3. 客户端Service调用底层通讯: DubboInvoker实例invoker包含一个或多个dubbo-remoting包的ExchangerClient实例,默认为1个,通过connections参数指定。ExchangerClient的默认实现类为HeaderExchangeClient,HeaderExchangeClient使用Netty的Bootstrap作为远程通讯client,Bootstrap使用NioSocketChannelFactory作为channelFactory。再用HeaderExchangeChannel来封装Bootstrap实例client,而HeaderExchangeClient则使用HeaderExchangeChannel实例channel来发送请求,具体看下面的服务调用分析。
    2019071910010_1.png

DubboInvoker实例的创建过程

  • 在consumer端,每个Service接口的服务代理,底层都包含一个DubboInvoker实例。具体为在consumer应用启动,加载spring,创建dubbo的服务代理refer bean时,在refer对应proxy中会包含一个invoker:
  • 在ReferenceConfig中创建服务代理
    2019071910010_2.png
    createProxy(map)的实现:refprotocol为DubboProtocol的实例,refer方法生成DubboInvoker实例,最后封装到服务代理refer中:
    2019071910010_3.png
    2019071910010_4.png
    JavassistProxyProxy: createProxy默认使用javassist生成代理
    2019071910010_5.png
  • DubboProtocol的refer方法的实现:getClients获取底层通讯的client实例,默认为netty的client。根据connections参数,即Constants.CONNECTIONS_KEY,默认数量为1(即单一长连接),即所有调用这个服务代理refer的线程,使用同一个连接发送请求和接收响应。
    2019071910010_6.png
    DubboInvoker的doInvoker:对远程服务进行调用,使用client发送请求,根据是否是异步,返回ResponseFuture或者阻塞等到结果返回。
    2019071910010_7.png

ExchangerClient默认使用单一Netty长连接和NIO通讯

  • AbstractClient:ExchangerClient接口的抽象实现类,定义模板方法
    2019071910010_8.png
  • ExchangerClient接口基于Netty实现类,继承于AbstractClient
    使用NioSocketChannel作为客户端Channel,即使用NIO;
    bootstrap.setOption(“keepAlive”, true),使用TCP长连接
    2019071910010_9.png
    2019071910010_10.png

consumer的并发调用

使用过Spring MVC都知道,Controller,Service都是单例的,Controller接收客户端的请求,调用Service处理业务逻辑获取数据。请求是并发过来的,共享Controller,Service实例,而consumer的服务代理也是一个Service实例,dubbo协议默认又是基于netty单一长连接(也可以通过connections参数生成多个连接)和NIO异步通讯的,所以需要考虑如何来使得这些并发调用能够获取自身的数据,即请求都是通过一个管道发出去的,当服务端响应消息时,如何交给对应的客户端调用线程,而不会调用线程之间互相影响,数据混乱。

服务调用过程

consumer调用远程service的method ——> 服务代理refer ——> DubboInvoker调用器invoker的doInvoker ——> ExchangerClient发起服务调用并获取结果

ExchangerClient的实现:HeaderExchanger,数据包头定长的数据交换器

2019071910010_11.png
client:默认为dubbo-remoting包的NettyClient
channel:HeaderExchangeChannel

  • 底层HeaderExchangeClient调用:通过一条绑定的Netty长连接的channel发送请求Request,返回一个DefaultFuture(ResponseFuture的子类)
    2019071910010_12.png
  • 顶层DubboInvoker的doInvoke:使用HeaderExchangeClient发送请求,如果是异步请求,则通过new创建一个Result新实例(通过局部变量的方式包保证线程安全性)返回,一路往上返回,最终到最顶层的Controller。该Result包装了ResponseFuture,在最顶层Controller的调用线程,可以灵活控制,从该Result实例获取结果,如先做其他事情,最后在调用get方法阻塞获取结果(一般在Service中完成)。
    如果是同步请求,则阻塞等到结果再返回,此时最顶层Controller的调用线程,阻塞在这里了。
    2019071910010_13.png

并发调用的数据安全性

客户端基于单一长连接的并发调用结果,请参加我的另外一篇文章:Dubbo源码分析:Dubbo协议客户端单一长连接下并发调用的结果获取

赞(0) 打赏

如未加特殊说明,此网站文章均为原创,转载必须注明出处。Java 技术驿站 » Dubbo源码分析:客户端基于dubbo协议的RPC并发调用
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

关注【Java 技术驿站】公众号,每天早上 8:10 为你推送一篇技术文章

扫描二维码关注我!


关注【Java 技术驿站】公众号 回复 “VIP”,获取 VIP 地址永久关闭弹出窗口

免费获取资源

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏