写点什么

RPC 框架 -dubbo:架构及源码分析 - 初篇

发布于: 2021 年 02 月 19 日
RPC框架-dubbo:架构及源码分析-初篇

一 dubbo 相关问题

1.1 基础问题

在自学或面试 dubbo 时,相关的问题有很多,例如 dubbo 的基本工作原理,这是使用过 dubbo 后应该知道的。包括 dubbo 的分层架构、长短链接选择、二进制协议支持;之后是使用方式(服务的注册、发现、调用方式),基础配置(超时时间、线程数),这些是最基本的。

在这些问题之后,就可以继续深入底层:关于连接方式,使用长连接还是短连接?为什么? dubbo 的二进制协议支持哪些,之间有什么区别/优缺点等等,也可以考察在使用过程中遇到过哪些问题,是如何解决的。这些都需要深入理解,并且有真实、长时间使用经验。

1.2 dubbo 要解决的需求

在大规模服务化之前,应用可能只是通过 RMI 或 Hessian 等工具,简单的暴露和引用远程服务,通过配置服务的 URL 地址进行调用,通过 F5 等硬件进行负载均衡。

当服务越来越多时,服务 URL 配置管理变得非常困难,F5 硬件负载均衡器的单点压力也越来越大。 此时需要一个服务注册中心,动态地注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和 Failover,降低对 F5 硬件负载均衡器的依赖,也能减少部分成本。

当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。 这时,需要自动画出应用间的依赖关系图,以帮助架构师理清关系。

接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器? 为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阈值,记录此时的访问量,再以此访问量乘以机器数反推总容量。

二 dubbo 架构

关于 dubbo 架构,官方有如下两张图进行了描述:

2.1 dubbo 基本模块图(逻辑结构抽象图)

节点角色说明:

Provider - 暴露服务的服务提供方

Consumer - 调用远程服务的服务消费方

Registry - 服务注册与发现的注册中心

Monitor - 统计服务的调用次数和调用时间的监控中心

Container - 服务运行容器

调用关系说明:

0、服务容器负责启动,加载,运行服务提供者。

1、服务提供者在启动时,向注册中心注册自己提供的服务。

2、服务消费者在启动时,向注册中心订阅自己所需的服务。

3、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

4、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

5、服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。


Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。

2.2 dubbo 运行流程分析图(调用链路图)


2.3 dubbo 服务暴露流程


执行流程:


2.4 dubbo 代码结构

dubbo 的 2.7.2 版本,代码结构如下:


三 连接方式

根据dubbo协议参考手册,Dubbo 缺省协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。

反之,Dubbo 缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。



  • Transporter: mina, netty, grizzy

  • Serialization: dubbo, hessian2, java, json

  • Dispatcher: all, direct, message, execution, connection

  • ThreadPool: fixed, cached

3.1 特性

缺省协议,使用基于 mina 1.1.7 和 hessian 3.2.1 的 tbremoting 交互。

  • 连接个数:单连接

  • 连接方式:长连接

  • 传输协议:TCP

  • 传输方式:NIO 异步传输

  • 序列化:Hessian 二进制序列化

  • 适用范围:传入传出参数数据包较小(建议小于 100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用 dubbo 协议传输大文件或超大字符串。

  • 适用场景:常规远程服务方法调用

3.2 约束

  • 参数及返回值需实现 Serializable 接口

  • 参数及返回值不能自定义实现 ListMapNumberDateCalendar 等接口,只能用 JDK 自带的实现,因为 hessian 会做特殊处理,自定义实现类中的属性值都会丢失。

  • Hessian 序列化,只传成员属性值和值的类型,不传方法或静态变量。

3.3 配置

Dubbo 协议缺省每服务每提供者每消费者使用单一长连接,如果数据量较大,可以使用多个连接。

<dubbo:service connections="1"/><dubbo:reference connections="1"/>
复制代码
  • <dubbo:service connections="0"> 或 <dubbo:reference connections="0"> 表示该服务使用 JVM 共享长连接。缺省

  • <dubbo:service connections="1"> 或 <dubbo:reference connections="1"> 表示该服务使用独立长连接。

  • <dubbo:service connections="2"> 或<dubbo:reference connections="2"> 表示该服务使用独立两条长连接。


为防止被大量连接撑挂,可在服务提供方限制大接收连接数,以实现服务提供方自我保护。

<dubbo:protocol name="dubbo" accepts="1000" />
复制代码

dubbo.properties 配置:

dubbo.service.protocol=dubbo
复制代码

如果采用的是 yml 配置文件,那么配置信息如下:

dubbo:  protocol:    name: dubbo
复制代码


3.4 常见问题解答

3.4.1 为什么要消费者比提供者个数多

因为 dubbo 协议采用单一长连接,假设网络为千兆网卡,根据测试经验数据每条连接最多只能压满 7MByte(不同的环境可能不一样,供参考),理论上 1 个服务提供者需要 20 个服务消费者才能压满网卡。

3.4.2 为什么不能传大包?

因为 dubbo 协议采用单一长连接,如果每次请求的数据包大小为 500KByte,假设网络为千兆网卡 3,每条连接最大 7MByte(不同的环境可能不一样,供参考),单个服务提供者的 TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。单个消费者调用单个服务提供者的 TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14。如果能接受,可以考虑使用,否则网络将成为瓶颈。

3.4.3 为什么采用异步单一长连接?

因为服务的现状大都是服务提供者少,通常只有几台机器,而服务的消费者多,可能整个网站都在访问该服务,比如 Morgan 的提供者只有 6 台提供者,却有上百台消费者,每天有 1.5 亿次调用,如果采用常规的 hessian 服务,服务提供者很容易就被压跨,通过单一连接,保证单一消费者不会压死提供者,长连接,减少连接握手验证等,并使用异步 IO,复用线程池,防止 C10K 问题。

四 rpc 支持协议

相关文件在 jar 包内,META-INF/dubbo.internal 下的 org.apache.dubbo.rpc.Protocol,


支持的协议内容如下:

filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapperlistener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrappermock=org.apache.dubbo.rpc.support.MockProtocoldubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocolinjvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocolrmi=org.apache.dubbo.rpc.protocol.rmi.RmiProtocolhessian=org.apache.dubbo.rpc.protocol.hessian.HessianProtocolhttp=org.apache.dubbo.rpc.protocol.http.HttpProtocol
org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocolthrift=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocolnative-thrift=org.apache.dubbo.rpc.protocol.nativethrift.ThriftProtocolmemcached=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocolredis=org.apache.dubbo.rpc.protocol.redis.RedisProtocolrest=org.apache.dubbo.rpc.protocol.rest.RestProtocolxmlrpc=org.apache.dubbo.xml.rpc.protocol.xmlrpc.XmlRpcProtocolregistry=org.apache.dubbo.registry.integration.RegistryProtocolqos=org.apache.dubbo.qos.protocol.QosProtocolWrapper
复制代码


发布于: 2021 年 02 月 19 日阅读数: 37
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
RPC框架-dubbo:架构及源码分析-初篇