Dubbo 开发随笔
Dubbo 版本说明
Dubbo 3 对比 Dubbo 2
Dubbo 3 版本对比 Dubbo 2 版本:
- 服务发现资源利用率显著提升
- 对比接口级服务发现,单机常驻内存下降 50%,地址变更期 GC 消耗下降一个数量级(百次 -> 十次)
- 对比应用级服务发现,单机常驻内存下降 75%,GC 次数趋零
- Dubbo 协议性能基本持平,Triple 协议在网关、Stream 吞吐量方面更具优势
- Dubbo 协议(
3.0vs2.x),3.0实现较2.x总体 QPS、RT 持平,略有提升 - Triple 协议 vs Dubbo 协议,直连调用场景 Triple 性能并无优势,但其优势在于网关、Stream 调用场景
Dubbo 2.7.1 版本存在的 Bug
Dubbo 2.7.1 版本存在无法正确获取到网卡 IP 地址和动态注册服务的 Bug,详细介绍可以看 这里。
Dubbo 基础介绍
Dubbo 支持的通信协议
Dubbo 支持的序列化协议
Dubbo 整合框架
Spring 与 SpringBoot 整合
使用 Dubbo 的三种方式
- 三种使用方式分别为:XML 配置、Annotation 配置、原生 API
- Spring 与 SpringBoot 都支持以 XML 配置、Annotation 配置使用 Dubbo
Spring 与 SpringBoot 整合 Dubbo 的简单总结
- SpringBoot + XML:
@ImportResource - SpringBoot + Annotation:
@EnableDubbo - Spring + Annotation:
AnnotationConfigApplicationContext - Spring + XML:
ClassPathXmlApplicationContext、FileSystemXmlApplicationContext
- SpringBoot + XML:
特别注意
在 Dubbo 2.6.x 版本及以前,由于使用基于注解(Annotation)的方式整合 Dubbo,无法实现 Dubbo 方法级的配置(即 <dubbo:method> 标签的功能),如果 Spring、SpringBoot 需要用到 Dubbo 方法级的配置,那么就需要使用 XML 的方式整合 Dubbo。但在 Dubbo 2.7.x 版本及以后,Dubbo 已经支持注解方式实现方法级配置,不再必须依赖 XML 配置。
Dubbo 服务高可用
Dubbo 服务降级
当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。Dubbo 可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
基于 Dubbo Mock 实现服务降级 - 返回空结果
- 在服务消费者中配置
<dubbo:reference>时,将mock属性设置为return null:
1 | <dubbo:reference id="fooService" |
- Dubbo 会在调用服务提供者失败时,直接返回
null结果,实现最简单的降级逻辑。
基于 Dubbo Mock 实现服务降级 - 自定义降级逻辑
- 在服务消费者中配置
<dubbo:reference>时,将mock属性设置为true:
1 | <dubbo:reference id="fooService" |
- 在服务消费者中,往接口同一个包路径下创建一个 Mock 类,命名规则:
接口名 + Mock,实现接口和降级逻辑:
1 | public class FooServiceMock implements FooService { |
- Dubbo 会在调用服务提供者失败时,自动使用该 Mock 类来替代真实服务,实现自定义的降级逻辑。
Dubbo 向注册中心写入动态配置覆盖规则
1 | RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); |
- 配置参数说明:
mock=force:return+null表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。- 还可以改为
mock=fail:return+null表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。 - 利用 Dubbo-Admin 的 UI 界面(旧版),可以方便地对服务进行屏蔽 / 恢复(
mock=force:return+null)、容错 / 恢复(mock=fail:return+null)处理,即上面提到的两种服务降级方式
Dubbo 集群容错策略
在集群调用失败时,Dubbo 提供了以下多种集群容错策略,默认策略为 Failover(故障转移)。在线上生产环境中,一般使用 Hystrix、Resilience4j 等框架进行容错处理。
- Failover:故障转移,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过
retries="2"参数来配置重试次数(不含第一次)。 - Failfast:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
- Failsafe:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
- Failback:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
- Forking:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过
forks="2"来设置最大并行数。 - Broadcast:广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
- ZoneAwareCluster:区域感知集群,当部署了多个机房或区域(Zone)时,优先调用同一机房的服务提供者,以降低跨区调用延迟和网络风险。
- MergeableCluster:结果合并集群,会调用多个服务提供者,并将多个服务提供者的调用结果进行合并,最终返回合并后的结果。
1 | <!-- 使用 Failover 集群容错策略时,重试次数的几种配置方式如下 --> |
1 | <!-- 集群模式配置,按照以下几种配置方式在服务提供方和消费方配置集群模式 --> |
Dubbo 失败重试和超时重试
在分布式系统中,网络抖动、节点故障等情况时有发生,Dubbo 提供了灵活的失败重试与超时重试配置来提高服务调用成功率。
基本原理
- 失败重试:服务消费者调用服务提供者失败(抛出异常)时,Dubbo 会自动按配置的
retries参数进行重试。 - 超时重试:服务调用时间超过
timeout限制时,Dubbo 会中断等待,并按retries配置进行重试。
- 失败重试:服务消费者调用服务提供者失败(抛出异常)时,Dubbo 会自动按配置的
配置示例
- 在服务消费者中配置
<dubbo:reference>时,设置retries和timeout属性1
2
3
4
5
6<dubbo:reference id="userService"
interface="com.test.service.UserService"
check="true"
async="false"
retries="3"
timeout="2000" /> timeout="2000":表示单次调用超时时间为 2 秒,超时即中断调用,不会无限等待。retries="3":表示调用失败或超时后,最多重试 3 次(即总共调用 4 次:1 次原始调用 + 3 次重试),默认重试 2 次。
- 在服务消费者中配置
参数建议
- 建议结合实际业务特点配置参数:
timeout:建议根据业务 SLA 设置。例如:公司部分读请求要求在 200ms 内返回结果,那么可以设置timeout="200",超时即放弃等待。retries:适用于读操作(幂等操作,如查询数据)。例如设置retries="3",表示原始调用失败后再尝试调用 3 次,提升服务调用的成功率。
- 建议结合实际业务特点配置参数:
注意事项
- 对于写操作(非幂等操作),由于可能会引发重复提交等问题,一般需要显式设置
retries="0"。 - 重试并不是万能的,过高的
retries会放大系统压力,建议与限流、降级等策略结合使用。 - 对高延迟接口,应优先优化接口性能,而不是依赖长超时配置。
- 对于写操作(非幂等操作),由于可能会引发重复提交等问题,一般需要显式设置
Dubbo 宕机环境下的高可用性
- 监控中心宕掉不影响使用,只是丢失部分采样数据
- 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
- 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
- 服务提供者无状态,任意一台宕掉后,不影响使用
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
Dubbo 源码剖析
Dubbo 的服务暴露

Dubbo 的服务引用

Dubbo 配置类之间的关系

Dubbo 代码调试
打印详细日志信息
为了更好观察 Dubbo 的运行行为,通常需要打印 DEBUG 级别的日志信息,比如:
- 基于 Properties 的日志配置内容(比如
Log4j的log4j.properties)
1 | # =============================== |
- 基于 XML 的日志配置内容(比如
Lockback的logback.xml或者 SpringBoot 的logback-spring.xml)
1 |
|
参考资料
Dubbo 性能调优
线程池状态导出
概念介绍
- Dubbo 可以通过
jstack自动导出线程堆栈来保留现场,方便排查问题。 - Dubbo 线程池状态的默认导出策略:
- 导出开关:默认打开
- 导出路径:
user.home标识的用户主目录 - 导出间隔:最短间隔允许每隔 10 分钟导出一次
- 当业务线程池满时,往往需要知道线程都在等待哪些资源、条件,以找到系统的瓶颈点或异常点。
配置方式
- 导出开关
1 | # Properties 配置(比如 dubbo.properties) |
1 | <!-- Spring XML 配置 --> |
1 | # YAML 配置(比如 application.yml) |
- 导出路径
1 | # Properties 配置(比如 dubbo.properties) |
1 | <!-- Spring XML 配置 --> |
1 | # YAML 配置(比如 application.yml) |
Dubbo 动态配置
配置规则(也叫 “动态配置” 或者 “动态配置规则”)是 Dubbo 设计的在无需重启应用的情况下,动态调整 RPC 调用行为的一种能力。Dubbo 从 2.7.0 版本开始,支持从应用和服务两个粒度来调整动态配置。
Dubbo 官方文档
Dubbo-Admin 服务治理
- Dubbo 支持通过 Dubbo-Admin 实现服务治理,支持以下功能(如下图所示):

Dubbo 常见使用问题
多网卡环境指定 IP 的问题
服务器有多个网卡接口(比如
eth1、eth0),希望 Provider(服务提供者)使用指定的 IP 地址往册中心(比如 ZooKeeper、Nacos)注册服务
- 方法一:在配置文件中明确指定 Provider 要注册的 IP 地址
1 | # 使用 Properties 配置方式,如 application.properties |
1 | # 使用 YAML 配置方式,如 application.yml |
1 | # 使用 XML 配置方式,如 dubbo.xml |
- 方式二:通过 JVM 启动参数指定 Provider 要注册的 IP 地址
1 | java -Ddubbo.protocol.host=<your_ip> -jar your-application.jar |
- 方法三:通过系统环境变量指定 Provider 要注册的 IP 地址
1 | export DUBBO_IP_TO_BIND=<your_ip> |
- 方式四:通过 JVM 启动参数指定 Provider 要使用的网卡
1 | java -Ddubbo.network.interface.preferred=eth1 -jar your-application.jar |
服务器有多个网卡接口(比如
eth1、eth0),希望 Consumer(服务消费者)使用指定的 IP 地址去调用 Provider(服务提供者)的接口
- 方式一:通过 JVM 启动参数指定 Consumer 要使用的网卡
1 | java -Ddubbo.network.interface.preferred=eth1 -jar your-application.jar |
Dubbo 关于网卡的配置
- 通过 JVM 启动参数
-Ddubbo.network.interface.ignored=eth1,eth0,排除一个或多个网卡,适用于服务消费者(Consumer)和服务提供者(Provider)。 - 通过 JVM 启动参数
-Ddubbo.network.interface.preferred=eth1,eth0,指定一个或多个网卡,适用于服务消费者(Consumer)和服务提供者(Provider)。
SpringBoot 整合 Dubbo 出错
错误信息:
1 | SpringBoot-2.1.0+ 整合 Apache Dubbo-2.7.0,启动应用后提示需要添加SpringBoot配置 “spring.main.allow-bean-definition-overriding=true” |
异常日志:
1 | *************************** |
异常分析:
1 | 问题是由注解 @EnableDubbo、@EnableDubboConfig 的使用所导致,具体可参考以下资料: |
解决方法:
1 | 方法一: 往 SpringBoot 的配置文件(application.properties)中添加对应配置,允许在 Spring 容器内可以覆盖 Bean 的定义: spring.main.allow-bean-definition-overriding=true |
@DubboReference 注解无法实现注入
错误描述:
1 | 在 Spring + SpringMVC + Dubbo 的项目中,发现在服务消费者中的 Controller 里面的 @DubboReference 注解会失效,即无法正常注入 Bean,导致程序运行时抛出空指针异常。 |
错误分析:
1 | (1) Spring 的扫描根本无法识别 Dubbo 的 @DubboReference 注解;同一方面,Dubbo 的扫描也无法识别 Spring 的 @Controller 注解,所以这两个扫描的顺序要安排好。 |
解决方法:
第一步:在服务提供者的模块中,先扫描 Spring 的注解(如
@Controller),然后再扫描 Dubbo 的注解(如@DubboService,为了暴露服务到注册中心),配置示例如下所示:
application-context.xml配置文件
1 | <!-- 扫描并注册 Spring 组件 --> |
application-mvc.xml配置文件
1 | <!-- 启用 SpringMVC 的注解驱动功能 --> |
第二步:在服务消费者的模块中,先扫描 Dubbo 的注解(如
@DubboReference,为了引用远程服务),然后再扫描 Spring 的注解(如@Controller),配置示例如下所示:
application-context.xml配置文件
1 | <!-- 扫描并注册 Spring 组件 --> |
application-mvc.xml配置文件
1 | <!-- 启用 SpringMVC 的注解驱动功能 --> |
