Dubbo 协议

特性描述

Dubbo 默认协议使用单一长连接和 NIO 异步通信,适用于小数据量、高并发服务调用,以及服务消费者机器数量远大于服务提供者机器数量的情况。

反之,Dubbo 默认协议不适用于传输大数据量的服务,例如文件传输、视频传输等,除非请求量非常低。

dubbo-protocol.jpg

  • 传输器:mina、netty、grizzy
  • 序列化:dubbo、hessian2、java、json
  • 调度器:all、direct、message、execution、connection
  • 线程池:fixed、cached

默认协议,使用基于 netty 3.2.5.Final 和 hessian2 3.2.1-fixed-2(阿里巴巴嵌入式版本) 的 tbremoting 交互。

  • 连接数:单连接
  • 连接方式:长连接
  • 传输协议:TCP
  • 传输方式:NIO 异步传输
  • 序列化:Hessian 二进制序列化
  • 适用范围:传入和传出参数数据包较小(建议小于 100K),消费者数量多于提供者,单个消费者无法填满提供者。尽量不要使用 dubbo 协议传输大文件或超大字符串。
  • 适用场景:常规远程服务方法调用

约束

  • 参数和返回值需要实现 Serializable 接口
  • 参数和返回值不能自定义实现 ListMapNumberDateCalendar 等接口,只能使用 JDK 自带的实现,因为 hessian 会做特殊处理,自定义实现会导致类中所有属性值丢失。
  • Hessian 序列化,只传递成员属性值和值类型,不传递方法或静态变量,兼容性由**吴亚军提供**
数据通信情况结果
A->B类 A 多了一个属性(或类 B 少了一个属性)不会抛出异常,A 多出的属性值,B 没有,其他正常
A->B枚举 A 多了一个枚举值(或 B 少了一个枚举值)A 使用多出的枚举值进行传输
A->B枚举 A 多了一个枚举值(或 B 少了一个枚举值)A 不使用多出的枚举值进行传输
A->BA 和 B 的属性同名但类型不同抛出异常
A->BserialId 不同正常传输

接口中新增的方法对客户端没有影响,如果客户端不需要该方法,则客户端无需重新部署。输入参数和结果集中新增的属性对客户端没有影响,如果客户端不需要新的属性,则无需重新部署。

输入参数和结果集属性名称的更改对客户端序列化没有影响,但如果客户端没有重新部署,则无论输入还是输出,都无法获取属性名称已更改的属性值。

总结

  • 服务端和客户端不需要完全一致的领域对象,但要遵循最大匹配原则。
  • 会抛出异常的情况:枚举值类型多一个少一个,刚好用的是不同的那个,或者属性名相同,但类型不同。

适用场景

适用于并发量大、数据量小的服务调用,且服务消费者远大于服务提供者。

使用方法

配置协议

<dubbo:protocol name="dubbo" port="20880" />

设置默认协议

<dubbo:provider protocol="dubbo" />

设置服务的协议

<dubbo:service interface="..." protocol="dubbo" />

多端口

<dubbo:protocol id="dubbo1" name="dubbo" port="20880" />
<dubbo:protocol id="dubbo2" name="dubbo" port="20881" />

配置协议选项

<dubbo:protocol name="dubbo" port="9090" server="netty" client="netty" codec="dubbo" serialization="hessian2" charset="UTF-8" threadpool="fixed" threads="100 " queues="0" iothreads="9" buffer="8192" accepts="1000" payload="8388608" />

多连接配置

默认情况下,Dubbo 协议每个服务、每个提供者和每个消费者使用一个长连接。如果数据量较大,可以使用多个连接。

<dubbo:service interface="..." connections="1"/>
<dubbo:reference interface="..." 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" />

常见问题

问题 1

为什么消费者要比提供者多?

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

问题 2

为什么不能传大包?

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

问题 3

为什么要使用异步单一长连接?

因为服务的现状是服务提供者很少,通常只有几台机器,但服务消费者很多,整个网站都可能在访问该服务。例如,Morgan 的提供者只有 6 个,但有数百个消费者。或者,每天有 1.5 亿次调用。如果使用传统的 Hessian 服务,服务提供者很容易不堪重负。通过单一连接,可以保证单个消费者不会压垮提供者,长期连接,减少连接握手验证等。并使用异步 IO,复用线程池,防止 C10K 问题。


上次修改时间:2023 年 1 月 2 日: 增强英文文档 (#1798) (95a9f4f6c1c)