Dubbo2 巩固教程之七
大纲
- Dubbo 2 巩固教程之一、Dubbo 2 巩固教程之二、Dubbo 2 巩固教程之三
- Dubbo 2 巩固教程之四、Dubbo 2 巩固教程之五、Dubbo 2 巩固教程之六
- Dubbo 2 巩固教程之七
前言
学习资源
Dubbo 性能优化
优化 Connections 参数
@DubboReference 注解中的 connections 参数用于限制服务消费者对同一个服务提供者实例建立的长连接(TCP)数量,主要解决高并发场景下连接复用与网络资源占用的平衡问题。值得注意的是,connections 参数的默认值是 0,表示对于同一个 Provider JVM 实例,同一个服务接口的所有 Consumer 引用(如 @DubboReference)共享一个单一的长连接,而不同服务接口之间的 Consumer 引用(如 @DubboReference)会各自独立创建一个单一的长连接。
特别注意
本节所提到的服务消费者(Consumer)通常不是指 JVM 进程级别的应用,而是指 Consumer 引用(如 @DubboReference),两者是一对多关系。参数 connections 的底层实现使用了 TCP 连接池,而 Dubbo 的 TCP 连接池是按服务接口维度进行隔离的,其唯一标识是 serviceKey(组成公式:serviceKey = interface + version + group + protocol),而不是按 Provider JVM 实例来隔离。举个例子,如果一个 Provider 暴露了 50 个接口,并且在 Consumer 引用(@DubboReference)中为每个服务接口都配置了 connections = 1,那么 Consumer 与这个 Provider 实例之间将建立 50 条物理 TCP 连接。
connections参数的作用- 在 Dubbo 中,服务消费者(Consumer)和服务提供者(Provider)之间使用长连接(TCP)进行通信。
- 默认情况下:
- 对于消费者来说,同一个 Provider 实例只会建立一个 TCP 长连接,所有请求都复用这条连接,资源占用小,适用于业务流量不大的场景。
- 如果
connections > 0,表示消费者会和每个 Provider 实例建立多个 TCP 长连接,并在请求时通过轮询或其他负载均衡算法选择具体的连接,适用于高并发或单连接成为性能瓶颈的场景。
- 配置方式一(单独配置):
1
2
private DemoService demoService; - 配置方式二(全局配置):
1
2
3dubbo:
consumer:
connections: 3
connections参数的使用场景- 单连接足够的场景,不需要配置
connections参数- 普通的业务接口调用,每次请求数据量不大,QPS 不高。
- 复用同一条 TCP 长连接,可以减少系统资源开销:
- 文件描述符(FD)数量低
- 内核 TCP 连接管理压力小
- 减少 TCP 连接的心跳、握手等开销
- 例子:
- 每秒只有几百个请求,QPS 不高,单连接带宽也够用,就不需要配置
connections参数。
- 每秒只有几百个请求,QPS 不高,单连接带宽也够用,就不需要配置
- 多连接的场景,以下几种情况建议配置
connections > 1- (1) 单连接带宽瓶颈
- 如果请求数据量非常大,例如每次响应数据都在 1 MB 以上,那么单条连接可能会填满 TCP 窗口,阻塞后续请求。
- 表现症状:
- Dubbo 的 RPC 调用延迟突然增大
- 网络监控到单条 TCP 连接的带宽被打满,但 CPU 却空闲
- 通过配置
connections = 2 ~ 4,可以分散流量,避免单连接成为性能瓶颈。
- (2) 串行化阻塞的问题
- Dubbo 的网络层默认基于 Netty 的 NIO,同一条连接上的请求是无序并发的,但如果:
- Provider 端是单线程处理请求,或者 Consumer 端串行发送请求;
- 可能出现请求阻塞队头(Head-of-line Blocking)。
- 通过多个连接让请求分散处理,可以提升并发度。
- Dubbo 的网络层默认基于 Netty 的 NIO,同一条连接上的请求是无序并发的,但如果:
- (3) Provider 实例数量少,但请求量大
- 假设只有 2 个 Provider 实例,但 Consumer 的 QPS 很高,单个 TCP 连接无法支撑。
- 例子:
- Consumer 的总请求量达到 1 万 QPS;
- 如果每个 Provider 实例只有 2 个连接,实际单连接需要支持 5000 QPS,这很容易成为性能瓶颈。
- (1) 单连接带宽瓶颈
- 单连接足够的场景,不需要配置
connections参数的调优建议- 不随便更改配置
connections参数的默认值是0,表示对于同一个 Provider 实例,Consumer 只会建立一个 TCP 长连接。- 不随便更改
connections参数的值,先进行性能压测。
- 如果发现:
- 单连接的 RTT(往返时间)过高
- TCP 窗口打满
- 请求阻塞
- Provider 实例数量少且流量大
→ 可以逐步调高connections参数的值。
- 监控
ESTABLISHED状态的 TCP 连接数和文件描述符(FD)使用率,避免触发操作系统的ulimit限制。
- 不随便更改配置
connections参数的注意事项- 连接池隔离机制
- Dubbo 的 TCP 连接池是按服务接口维度进行隔离的,其唯一标识是
serviceKey(组成公式:serviceKey = interface + version + group + protocol),而不是按 Provider JVM 实例来隔离。 - 对于每一个不同的
serviceKey,Consumer 端都会创建一个独立的客户端实例(如 NettyClient)来管理其连接,每个客户端实例会维护一个到对端服务提供者(Provider)的独立连接池。 - 即使两个服务接口由同一个 Provider 服务器提供,在 Consumer 端也会被视为两个不同的逻辑服务,并建立两套物理连接。
- 这样做的好处是不同接口可以独立配置连接数、超时等参数,避免接口间相互干扰,例如一个接口阻塞不会影响其他接口。
- Dubbo 的 TCP 连接池是按服务接口维度进行隔离的,其唯一标识是
- 连接池与物理连接的关系
- 每个
serviceKey对应的客户端实例(如 NettyClient)都会独立维护一个到对端 Provider 的连接池。 - 在默认配置 (
connections = 0) 下,每个serviceKey的连接池内与同一个 Provider 地址之间会建立一条物理 TCP 长连接。
- 每个
- 配置的作用域与影响
connections参数的作用范围是每个serviceKey到单个 Provider 地址。因此,即使是同一个 Provider 实例,其不同服务接口(不同serviceKey)也不会共享connections配置所限定的连接。- 举个例子:如果一个 Provider 暴露了 50 个接口,并且在 Consumer 引用(
@DubboReference)中为每个服务接口都配置了connections = 1,那么 Consumer 与这个 Provider 实例之间将建立 50 条物理 TCP 连接。
- 潜在风险与配置建议
- 这种设计带来了配置独立性和故障隔离的好处,但也意味着物理连接数会随着引用接口数量的增加而线性增长。
- 如果需要配置
connections参数,建议配置connections = 2 ~ 4,这样可以分散流量,避免单连接成为性能瓶颈。 - 如果为大量接口配置
connections > 1,或者在高接口数的应用中,会快速消耗 Consumer 和 Provider 双方的系统资源(如文件描述符、内存、线程等),需要在高并发或大规模微服务架构中格外关注。
- 连接池隔离机制
connections参数的使用总结
| 项目 | 说明 |
|---|---|
| 默认行为 | 对于 Consumer,同一个 Provider 实例只建立 1 条 TCP 长连接 |
设置 connections > 0 | 对于 Consumer,同一个 Provider 实例建立 N 条 TCP 长连接,缓解单连接的性能瓶颈 |
| 主要解决的问题 | 单连接带宽不足、请求阻塞、并发度不足的问题 |
| 底层网络实现 | 底层基于 Netty,多条 TCP 连接对应多个 Channel,通过 ChannelPool 轮询选择 TCP 连接 |
| 建议配置值 | connections 参数的值一般设置 2 ~ 4 已经够用,因此不要盲目设置太大,否则会浪费资源 |
| 连接建立的时机 | Provider 的 TCP 连接是在 Consumer 启动、从注册中心获取到服务列表之后就会立即建立,不是在第一次发起 RPC 调用时才建立连接,这属于 “预热连接” 机制 |
扩展阅读
