Dubbo 2 入门教程之四

大纲

前言

学习资源

Dubbo 核心特性

代码下载

本节完整的案例代码可以直接从 GitHub 下载对应章节 dubbo-lesson-12

线程模型

特性说明

线程模型

通过网络对外提供服务的组件通常都包含两类线程:网络 I/O 线程和业务线程,Dubbo 框架也不例外。

  • 网络 I/O 线程

    • 负责处理网络请求的接收和传输,包括 acceptconnectionreadwrite 等事件。
    • 如果网络事件的处理逻辑较为简单且能迅速完成,直接在 I/O 线程中处理可以获得更高性能,因为省去了线程切换的开销。
    • 但若处理逻辑较复杂或耗时较长,I/O 线程被阻塞将会导致无法及时响应新的网络请求,从而影响整体并发能力。
  • 业务线程

    • 专用于执行复杂的业务逻辑,例如通过 I/O 调用第三方服务、进行数据计算与处理等。
    • 由于业务逻辑执行时间不确定,使用独立的业务线程可以有效避免阻塞 Dubbo 的网络 I/O 线程,从而保障系统的网络处理能力。
  • 使用场景

    • 如果事件处理的逻辑能迅速完成,并且不会发起新的网络 I/O 请求,比如只是在内存中记个标识,则直接在网络 I/O 线程上处理更快,因为减少了线程池调度。
    • 如果事件处理的逻辑执行较慢,或者需要发起新的网络 I/O 请求,比如需要查询数据库,则必须派发到线程池处理,否则网络 I/O 线程阻塞,将导致不能接收其它新的请求。
    • 如果用网络 I/O 线程处理事件,又在事件处理过程中发起新的网络 I/O 请求,比如在连接事件中发起登录请求,会抛出 “可能引发死锁” 异常,但不会真死锁。
    • 因此,需要通过不同的线程派发策略和不同的线程池配置的组合来应对不同的场景
      • 举个例子,将所有的消息都派发给业务线程池,业务线程池固定 100 个线程,配置示例如下:
      • 服务提供者的配置:<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
线程池类型

Dubbo 提供了以下 4 种线程池类型:

  • fixed(固定大小线程池)

    • 特点:
      • Dubbo 的默认线程池类型。
      • 启动时创建固定数量线程,不会关闭线程,线程始终存在。
      • 任务排队等待执行,如果线程都在忙,任务会进入队列。
    • 优点:
      • 线程数固定,可预测系统资源消耗,便于容量规划。
      • 避免线程无限增长,降低系统过载风险。
      • 稳定性高,适合长期运行的常规业务。
    • 缺点:
      • 并发峰值超过线程数时,任务会排队,可能导致响应延迟增加。
    • 适用场景:
      • 并发量稳定的常规业务场景。
  • cached(缓存线程池)

    • 特点:
      • 空闲线程 1 分钟后自动销毁,需要时重新创建线程。
      • 当任务数超过 maximumPoolSize 时,直接抛出 RejectedExecutionException 异常(拒绝任务),不会将任务放入队列排队。
    • 优点:
      • 根据负载动态调整线程数,节省系统资源。
    • 缺点:
      • 长耗时任务或高并发任务可能导致线程无限增加,引起系统过载。
    • 适用场景:
      • 短时高峰、任务执行快且任务量波动大的业务场景。
  • limited(可伸缩线程池)

    • 特点:
      • 线程池大小可伸缩,但只增长不收缩,可以限制最大线程数。
      • 当线程都被占用且队列满时,会直接拒绝新任务。
      • 可以避免线程收缩后,流量突增导致性能下降。
    • 优点:
      • 以资源换稳定性,可以确保系统快速响应流量波动。
    • 缺点:
      • 空闲线程无法回收,长期运行可能占用较多资源。
    • 适用场景:
      • 流量波动明显,但希望系统在高峰期保持响应稳定的场景。
  • eager(优先创建 Worker 线程池)

    • 工作机制:
      • 当任务数 > corePoolSize 且 < maximumPoolSize 时,优先创建 Worker 线程处理任务。
      • 当任务数 > maximumPoolSize 时,将任务放入阻塞队列。
      • 阻塞队列已满时,抛出 RejectedExecutionException 异常。
    • cached 线程池的区别:
      • cached:一旦超过最大线程数,会直接拒绝任务(抛出异常),不使用队列。
      • eager:一旦超过最大线程数,会将任务放入队列,降低任务被拒绝执行的概率。
    • 优点:
      • 快速响应突发请求,高峰期任务能尽快创建线程处理。
      • 减少任务被拒绝的概率(因为有阻塞队列作为缓冲)。
      • 兼顾低延迟与高并发的处理能力。
    • 缺点:
      • 配置不当可能导致线程数激增,占用大量系统资源。
    • 适用场景:
      • 高并发、低延迟业务,既希望快速创建线程处理任务,又希望尽量减少任务被拒绝执行的概率。

Dubbo 不同类型线程池的对比:

线程池类型是否使用队列队列是否有界拒绝策略触发条件特点与适用场景
fixed使用队列无界队列(LinkedBlockingQueue 默认容量无限)几乎不会触发稳定但可能堆积大量请求,适合后台任务
cached不使用队列根据负载动态扩缩线程,适合短平快请求
limited使用队列有界队列队列满 + 线程忙可以防止堆积任务,控制并发与内存使用,适合网关或限流场景
eager使用队列有界队列满 + 线程忙更积极地扩容线程,适合高峰突发场景
线程派发策略

Dubbo 提供了 5 种线程派发策略(Dispatcher),也叫消息派发策略,用于控制不同类型的消息在网络 I/O 线程和业务线程池之间的派发方式,从而实现高效且可控的并发处理。

  • Dubbo 的消息类型

    • 请求消息(Request):执行服务端业务逻辑,可能耗时较长,通常需要交给业务线程池处理,避免阻塞网络 I/O 线程。
    • 响应消息(Response):只需要将方法的执行结果返回给客户端,逻辑非常轻量,通常直接在网络 I/O 线程写出即可,无需切换到业务线程。
    • 心跳消息(Heartbeat):用于连接保活,逻辑轻量,通常在网络 I/O 线程处理。
    • 连接消息(Connect):表示客户端与服务端建立连接,轻量操作,通常在网络 I/O 线程处理。
    • 断开消息(Disconnect):表示客户端与服务端断开连接,轻量操作,通常在网络 I/O 线程处理。
  • Dubbo 的线程派发策略

    • all:默认的线程派发策略,所有消息都派发到业务线程池处理,包括请求、响应、连接、断开、心跳等事件。
    • direct:所有消息都不派发到业务线程池处理,全部都在网络 I/O 线程上直接执行。
    • message:只有请求响应消息派发到业务线程池处理,其它连接、断开、心跳消息,直接在网络 I/O 线程上执行。
    • execution:只有请求消息派发到业务线程池处理,不包含响应消息;响应和其它连接、断开、心跳消息,直接在网络 I/O 线程上执行。
    • connection:连接和断开事件在网络 I/O 线程上放入队列,按顺序逐个处理;其它请求、响应、心跳消息,则派发到业务线程池处理。
  • Dubbo 的调用图

    • 如下图所示,红框中的 Dispatcher 就是线程派发器,Dubbo 支持 5 种不同的线程派发策略。
    • 需要说明的是,Dispatcher 真实的职责是创建具有线程派发能力的 ChannelHandler,比如 AllChannelHandlerMessageOnlyChannelHandlerExecutionChannelHandler 等,其本身并不具备线程派发能力。
    • 比如,在 AllChannelHandler 的代码实现中,Dubbo 的请求对象会被封装为 ChannelEventRunnable,而 ChannelEventRunnable 将会是服务调用过程的新起点。

配置说明

配置参数

Dubbo 为线程模型提供了三个核心配置参数:dispatcherthreadpoolthreads

  • dispatcher(线程派发策略)
参数值含义说明特点与适用场景
all默认值,所有消息均派发到业务线程池最常见配置,网络 I/O 线程只负责读写,业务逻辑全部交由业务线程池处理。
direct所有消息直接在网络 I/O 线程上执行性能最高但风险大,可能会阻塞网络 I/O 线程,适合极轻量级、无阻塞逻辑的场景。
message只派发请求、响应消息到业务线程池连接、断开、心跳等消息仍在网络 I/O 线程中处理,适合请求耗时较长的场景。
execution仅派发请求消息到业务线程池,不包含响应消息响应和其它连接、断开、心跳消息,直接在网络 I/O 线程上执行,适合请求耗时较长的场景。
connection每个连接独立分配线程池为每个连接创建独立线程池,适合多连接、隔离性要求高的场景。
可扩展自定义派发策略(SPI 扩展)Dubbo 通过 SPI 机制支持扩展自定义 Dispatcher 实现,以满足特殊调度需求。
  • threadpool(线程池类型)
参数值含义说明特点与适用场景
fixed默认值,固定大小线程池线程数固定(由 threads 参数决定),如果线程都在忙,任务会进入队列,适合稳定且可预估的并发场景。
cached缓存线程池无固定线程数,空闲线程可回收,不使用队列,适合流量波动较大的场景,但高并发下可能会创建大量线程。
limited可伸缩线程池线程池中的线程只会增加,不会收缩,但可以限制最大并发数;超出部分任务将排队等待,避免线程过多导致系统过载。
eager优先创建线程的池(Dubbo 特有)优先增加线程来处理请求,队列积压时再排队执行(与 JDK 的 FixedThreadPool 刚好相反),适合低延迟、高并发业务场景。
可扩展自定义线程池 Dubbo SPI 机制允许开发者扩展自定义线程池实现。
  • threads(线程数量)
参数默认值含义说明适用范围调优建议
threads200限制业务线程池中可并行执行的最大线程数。线程数过小会导致请求排队、响应延迟;过大则会增加线程上下文切换和内存开销。Provider 端参数,仅影响服务提供者的业务线程池,不影响 Consumer 的请求线程数。一般根据 CPU 核数与请求耗时进行调优:CPU 密集型业务推荐配置为核数的 2 ~ 4 倍;I/O 密集型业务可适当调高。
配置方式

比如:将所有的消息都派发给业务线程池,业务线程池固定 100 个线程。

  • Dubbo 配置示例:
1
2
<!-- 在服务提供者中的协议中,配置线程池类型与线程派发策略 -->
<dubbo:protocol name="dubbo" port="20880" dispatcher="all" threadpool="fixed" threads="100" />
  • 配置参数的说明:
参数名示例值含义说明作用
namedubbo指定使用的通信协议名称,如 dubbormihttp决定服务暴露时所采用的通信协议类型
port20880服务监听的端口号消费者通过该端口访问服务提供者
threadpoolfixed业务线程池的类型,如 fixedcachedlimitedeager控制业务线程池的创建与使用策略
dispatcherall线程派发策略,如 alldirectmessageexecutionconnection 等,控制网络 I/O 线程与业务线程的任务分配方式决定请求在网络 I/O 线程与业务线程之间的调度方式
threads100业务线程池中的最大线程数限制并发执行的业务线程数量,防止资源耗尽

特别注意

Dubbo 线程模型的配置参数(如 dispatcherthreadpoolthreads)通常是配置在服务提供者中,而服务消费者通常不需要配置。

使用方式

YML 配置方式
  • 服务提供者中配置
1
2
3
4
5
6
7
dubbo:
protocol:
name: dubbo
port: 20880
dispatcher: all
threadpool: fixed
threads: 100
XML 配置方式
  • 服务提供者中配置
1
2
<!-- 配置服务协议,添加并发控制的配置 -->
<dubbo:protocol name="dubbo" port="20880" dispatcher="all" threadpool="fixed" threads="100"/>

并发控制

特性说明

  • 功能说明

    • Dubbo 提供了多种并发控制(限流)功能,可以帮助用户管理其应用程序和服务。
  • 使用场景

    • 限制从同一客户端到同一服务的并发请求数,防止恶意请求使服务器过载,确保服务的稳定性,并防止使用过多资源。
    • 控制某些服务的最大并发请求数,确保其他服务的资源可用性。避免系统过载和确保系统稳定性。
    • 允许在需求增加时更平滑地扩展服务,并且确保服务在高峰使用时间保持可靠和稳定。
    • 这种并发控制方式要求用户准确的预先评估系统能处理的并发数,而准确的评估系统处理能力并不是一件容易的事情。

配置参数

Dubbo 为并发控制提供了 executesactives 配置参数,两者都支持接口级别和方法级别的配置,具体介绍如下表所示:

参数名称作用层面功能描述常见适用场景超限后的行为注意事项
executes服务提供者中,对方法调用进行限流限制某个服务接口的最大并发调用数(即占用服务端线程池线程数)某个服务接口较重、CPU 密集型、需要限流保护时超出并发数上限时直接拒绝请求,抛出 RpcException 异常针对接口级别,常用于保护关键服务不被过载调用
actives服务消费者中,对方法调用进行限流限制某个消费者对某个服务接口的最大并发请求数(即消费端发出的请求并发数)消费端调用高延迟服务时,防止请求堆积超出请求数上限时阻塞等待响应(默认等待超时后抛出异常)针对消费端的服务引用,适合控制客户端对下游的压力

注意事项

在使用 Dubbo 的并发控制参数 executesactives 时,必须注意以下细节:

  • Dubbo 的 actives 参数控制的是「并发请求数(Active Requests)」,而不是 TCP 连接数,仅 Dubbo 协议等支持多路复用协议能体现出其并发控制的特性。
  • 对于 Dubbo 协议而言,多个并发请求可以复用同一个 TCP 连接(支持多路复用),因此即使 connections = 1,一个 TCP 连接也可以同时处理多个请求;当 actives = 10,这就可以限制 Dubbo 协议最多支持 10 个并发请求。
  • 对于其他协议(如 HTTP、RMI、Hessian),这些协议往往是「同步阻塞式」通信,一个 TCP 连接上一次只能发送一个请求,直到响应返回。因此即使设置 actives = 10,实际上也无法同时发出 10 个请求(受协议约束),所以此时 actives 不会生效。
使用案例配置实际效果
Dubbo 协议,connections = 1actives = 10支持多路复用可以在 1 个连接上同时处理最多 10 个并发请求
Dubbo 协议,connections = 5actives = 10支持多路复用,多连接 + 多并发最多有 10 个并行请求分布在 5 个连接上
Dubbo 协议,connections = 1actives = 1请求严格串行同一时间内只允许 1 个并发请求
RMI 或 HTTP 协议,connections = 1actives = 10不支持多路复用,请求严格串行实际只有 1 个并发请求,actives 不会生效

使用方式

特别注意

  • Dubbo 的并发控制参数 executes 必须配置在服务提供者中,不支持配置在服务消费者中。
  • Dubbo 的并发控制参数 actives 可以配置在服务消费者或者服务提供者中,如果两者都配置了 actives 参数,那么服务消费者的配置更优先。
  • Dubbo 的并发控制参数 actives 是点对点(Consumer → Provider)级别的并发控制,而不是全局合计。也就是说限制的是 "单个服务消费者(Consumer)到单个服务提供者(Provider)之间" 的并发请求数。
注解配置方式

executes 参数的配置

  • 在服务提供者中,限制 com.foo.BarService 的每个方法,并发执行数(即占用服务端的线程池线程数)不能超过 10 个
1
2
3
// 在服务提供者中配置
@DubboService(executes = 10)
public class BarServiceImpl implements BarService { }
  • 在服务提供者中,限制 com.foo.BarServicesayHello() 方法,并发执行数(即占用服务端的线程池线程数)不能超过 10 个
1
2
3
4
5
6
7
// 在服务提供者的方法上配置
@DubboService(methods = {@Method(name = "sayHello", executes = 10)})
public class BarServiceImpl implements BarService {

public void sayHello(String name) { }

}

actives 参数的配置

  • 在服务消费者(或者服务提供者)中,限制 com.foo.BarService 的每个方法,每个客户端的并发请求数(即占用 TCP 连接的请求数,不一定是 TCP 连接数,比如 Dubbo 协议支持单连接多路复用)不能超过 10 个
1
2
3
// 在服务消费者中配置
@DubboReference(actives = 10)
private BarService barService;
1
2
3
// 或者,在服务提供者中配置
@DubboService(actives = 10)
public class BarServiceImpl implements BarService { }
  • 在服务消费者(或者服务提供者)中,限制 com.foo.BarServicesayHello() 方法,每个客户端的并发请求数(即占用 TCP 连接的请求数,不一定是 TCP 连接数,比如 Dubbo 协议支持单连接多路复用)不能超过 10 个
1
2
3
// 在服务消费者的方法上配置
@DubboReference(methods = {@Method(name = "sayHello", actives = 10)})
private BarService barService;
1
2
3
4
5
6
7
// 或者,在服务提供者的方法上配置
@DubboService(methods = {@Method(name = "sayHello", actives = 10)})
public class BarServiceImpl implements BarService {

public void sayHello(String name) { }

}
XML 配置方式

executes 参数的配置

  • 在服务提供者中,限制 com.foo.BarService 的每个方法,并发执行数(即占用服务端的线程池线程数)不能超过 10 个
1
2
3
4
5
<!-- 服务实现类 Bean -->
<bean id="barServiceImpl" class="com.foo.impl.BarServiceImpl"/>

<!-- 在服务提供者中配置 -->
<dubbo:service interface="com.foo.BarService" ref="barServiceImpl" executes="10" />
  • 在服务提供者中,限制 com.foo.BarServicesayHello() 方法,并发执行数(即占用服务端的线程池线程数)不能超过 10 个
1
2
3
4
5
6
7
<!-- 服务实现类 Bean -->
<bean id="barServiceImpl" class="com.foo.impl.BarServiceImpl"/>

<!-- 在服务提供者的方法上配置 -->
<dubbo:service interface="com.foo.BarService" ref="barServiceImpl">
<dubbo:method name="sayHello" executes="10" />
</dubbo:service>

actives 参数的配置

  • 在服务消费者(或者服务提供者)中,限制 com.foo.BarService 的每个方法,每个客户端的并发请求数(即占用 TCP 连接的请求数,不一定是 TCP 连接数,比如 Dubbo 协议支持单连接多路复用)不能超过 10 个
1
2
<!-- 在服务消费者中配置 -->
<dubbo:reference id="barService" interface="com.foo.BarService" actives="10" />
1
2
3
4
5
<!-- 服务实现类 Bean -->
<bean id="barServiceImpl" class="com.foo.impl.BarServiceImpl"/>

<!-- 或者,在服务提供者中配置 -->
<dubbo:service interface="com.foo.BarService" ref="barServiceImpl" actives="10" />
  • 在服务消费者(或者服务提供者)中,限制 com.foo.BarServicesayHello () 方法,每个客户端的并发请求数(即占用 TCP 连接的请求数,不一定是 TCP 连接数,比如 Dubbo 协议支持单连接多路复用)不能超过 10 个
1
2
3
4
<!-- 在服务消费者的方法上配置 -->
<dubbo:reference id="barService" interface="com.foo.BarService">
<dubbo:method name="sayHello" actives="10" />
</dubbo:service>
1
2
3
4
5
6
7
<!-- 服务实现类 Bean -->
<bean id="barServiceImpl" class="com.foo.impl.BarServiceImpl"/>

<!-- 或者,在服务提供者的方法上配置 -->
<dubbo:service interface="com.foo.BarService" ref="barServiceImpl">
<dubbo:method name="sayHello" actives="10" />
</dubbo:service>

连接控制

特性说明

  • 功能说明

    • Dubbo 的连接控制参数大致可以分为两类:
      • 服务提供方的连接控制:acceptslazy
      • 服务消费方的连接控制:connectionssticky
    • Dubbo 的连接控制功能可以使用户能够控制和管理进出服务器连接数,限制连接数并设置超时,以确保 Dubbo 系统的稳定性和性能。
    • Dubbo 还允许用户根据 IP 地址、端口和协议配置不同级别的访问控制,保护系统免受恶意流量的影响,并降低服务中断的风险,此外提供了一种监视当前流量和连接状态的方法。
  • 使用场景

    • 服务器过载时减少连接数:当服务器负载过高时,可通过设置 Dubbo 的最大连接数限制,减少连接数,从而降低服务器压力,避免因过载导致的崩溃。
    • 减少服务器受到攻击时的连接数:Dubbo 可限制服务器的最大连接数,防止恶意客户端建立过多连接,占满服务器资源,保障服务可用性。
    • 限制特定服务的连接数:可针对不同服务设置连接数上限,防止单个服务被大量请求占用资源,确保系统整体响应能力。
    • 限制来自单个 IP 地址的连接数:Dubbo 支持限制来自单个 IP 地址的连接数,有助于防止单个 IP 地址的恶意访问或异常流量攻击。

配置参数

Dubbo 为连接控制提供了 acceptsconnectionsstickylazy 配置参数,具体介绍如下表所示:

参数名默认值默认值的说明作用适用场景注意事项
accepts0表示默认不限制 Provider 端(JVM 进程级别)的连接数。限制 Provider(JVM 进程级别)同时接受的最大连接数,超过该值的新连接将被拒绝。- 服务端资源受限(CPU、FD 等)
- 防止恶意连接或瞬时高并发导致服务端过载
- 仅在 Provider 端生效;
- 限制的是 “连接数”,非并发请求数;
- 超限连接会被拒绝,客户端报连接失败。
connections0表示对于同一个 Provider JVM 实例,同一个服务接口的所有 Consumer 引用(如 @DubboReference)共享一个单一的长连接,不同服务接口之间的 Consumer 引用(如 @DubboReference)会各自独立创建一个单一的长连接。控制 Consumer 与每个 Provider 之间的长连接数。- 高并发调用、请求量大
- 希望通过多连接提高吞吐量
- 仅对长连接协议(如 Dubbo 协议)生效;
- 在每个 Consumer 与每个 Provider 之间生效;
- 设置过大会浪费连接资源,设置过小会影响吞吐量。
stickyfalse表示默认不启用粘滞连接。开启粘滞连接,即同一个 Consumer 多次调用优先使用上次的 Provider 实例。- 需要保持 “会话状态” 的业务(有状态服务)
- 如用户登录、缓存服务、分布式 Session
- 仅在有多个 Provider 实例,并启用了集群容错机制时才生效;
- 如果目标 Provider 不可用,会自动切换其他实例;
- 可以与负载均衡策略(如 randomroundrobin)组合使用。
- 启用粘滞连接后,Dubbo 将会自动开启延迟连接,以减少长连接数。
lazyfalse表示默认不启用延迟连接,即 Consumer 在启动时会立即与所有 Provider 建立长连接。控制 Consumer 是否延迟创建与 Provider 的连接,直到第一次方法调用时才建立连接。- 服务依赖关系复杂,启动时连接数过多
- 希望加快应用启动速度
- 部分服务调用频率较低
- 仅对长连接协议(比如 Dubbo 协议)生效
- 设置为 true 可减少应用启动时的连接数,加快启动速度;
- 启用延迟连接后,首次调用会有建立连接的延迟;
- 启用粘滞连接后,Dubbo 将会自动开启延迟连接,以减少长连接数。
- 对于高频调用的服务,建议保持 false 以避免首次调用时建立连接的开销。

特别注意

  • Dubbo 的连接控制参数 sticky 必须配置在服务消费者中,不支持配置在服务提供者中。
  • Dubbo 的连接控制参数 acceptslazy 都必须配置在服务提供者中,不支持配置在服务消费者中。
  • Dubbo 的连接控制参数 connections 可以配置在服务消费者或者服务提供者中,如果两者都配置了 connections 参数,那么服务消费者的配置更优先。
  • connections 的默认值为 0,表示对于同一个 Provider JVM 实例,同一个服务接口的所有 Consumer 引用(如 @DubboReference)共享一个单一的长连接,不同服务接口之间的 Consumer 引用(如 @DubboReference)会各自独立创建一个单一的长连接。

注意事项

使用 connections 配置参数的注意事项

  • 连接池隔离机制

    • Dubbo 的 TCP 连接池是按服务接口维度进行隔离的,其唯一标识是 serviceKey(组成公式:serviceKey = interface + version + group + protocol),而不是按 Provider JVM 实例来隔离。
    • 对于每一个不同的 serviceKey,Consumer 端都会创建一个独立的客户端实例(如 NettyClient)来管理其连接,每个客户端实例会维护一个到对端服务提供者(Provider)的独立连接池。
    • 即使两个服务接口由同一个 Provider 服务器提供,在 Consumer 端也会被视为两个不同的逻辑服务,并建立两套物理连接。
    • 这样做的好处是不同接口可以独立配置连接数、超时等参数,避免接口间相互干扰,例如一个接口阻塞不会影响其他接口。
  • 连接池与物理连接的关系

    • 每个 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 双方的系统资源(如文件描述符、内存、线程等),需要在高并发或大规模微服务架构中格外关注。

使用 sticky 配置参数的注意事项

  • 粘滞连接通常用于有状态服务(比如用户登录、缓存服务等),尽可能让 Consumer 总是向同一个 Provider 发起远程调用,除非该 Provider 宕机,再切换到另一个 Provider。
  • 当启用粘滞连接时(sticky = true),Dubbo 将会自动开启延迟连接(lazy = true),以减少长连接数。

使用 lazy 配置参数的注意事项

  • lazy 参数仅对长连接协议(比如 Dubbo 协议)生效;
  • 启用延迟连接后,首次发起远程调用时会有建立连接的延迟;
  • 因为连接在 Server 上,所以 lazy 参数配置在服务提供者(Provider)中;
  • 当启用粘滞连接时(sticky = true),Dubbo 将会自动开启延迟连接(lazy = true),以减少长连接数。

提供方的连接控制

YML 配置方式

accepts 的配置

  • 在服务提供者中,限制服务提供者接受的连接不能超过 10 个
1
2
3
4
# Provider 端的全局配置
dubbo:
provider:
accepts: 10 # 限制 Provider 端最多接受的连接数
1
2
3
4
5
6
# 或者在 Provider 的协议中配置
dubbo:
protocol:
name: dubbo
port: 20880
accepts: 10 # 限制使用该协议的 Provider 端最多接受的连接数

lazy(延迟连接)的配置

1
2
3
4
5
6
# 在 Provider 的协议中配置
dubbo:
protocol:
name: dubbo
port: 20880
lazy: true # 让使用该协议的 Provider 端启用延迟连接
XML 配置方式

accepts 的配置

  • 在服务提供者中,限制服务提供者接受的连接不能超过 10 个
1
2
<!-- 限制 Provider 端最多接受的连接数 -->
<dubbo:provider protocol="dubbo" accepts="10" />
1
2
<!-- 或者,在协议中配置,限制使用该协议的 Provider 端最多接受的连接数 -->
<dubbo:protocol name="dubbo" port="20880" accepts="10" />

lazy(延迟连接)的配置

1
2
<!-- 在 Provider 的协议中配置 -->
<dubbo:protocol name="dubbo" port="20880" lazy="true" />

消费方的连接控制

注解配置方式

connections 的配置

  • 在服务消费者(或者服务提供者)中,限制服务消费者建立的连接不能超过 10 个
1
2
3
// 在服务消费者中配置
@DubboReference(connections = 10)
private BarService barService;
1
2
3
// 或者,在服务提供者中配置
@DubboService(connections = 10)
public class BarServiceImpl implements BarService { }

sticky(粘滞连接)的配置

  • 在服务消费者中,开启粘滞连接
1
2
3
// 在服务消费者配置
@DubboReference(sticky = true)
private BarService barService;
1
2
3
// 或者,在服务消费者的方法上配置
@DubboReference(methods = {@Method(name = "sayHello", sticky = true)})
private BarService barService;
XML 配置方式

connections 的配置

  • 在服务消费者(或者服务提供者)中,限制服务消费者建立的连接不能超过 10 个
1
2
<!-- 在服务消费者中配置 -->
<dubbo:reference id="barService" interface="com.foo.BarService" connections="10" />
1
2
3
4
5
<!-- 服务实现类 Bean -->
<bean id="barServiceImpl" class="com.foo.impl.BarServiceImpl"/>

<!-- 或者,在服务提供者中配置 -->
<dubbo:service interface="com.foo.BarService" ref="barServiceImpl" connections="10" />

sticky(粘滞连接)的配置

  • 在服务消费者中,开启粘滞连接
1
2
<!-- 在服务消费者中配置 -->
<dubbo:reference id="barService" interface="com.foo.BarService" sticky="true"/>
1
2
3
4
<!-- 或者,在服务消费者的方法上配置 -->
<dubbo:reference id="barService" interface="com.foo.BarService">
<dubbo:method name="sayHello" sticky="true" />
</dubbo:reference>

参考资料