Skip to content

Dubbo 详解:高性能 RPC 框架

  Apache Dubbo 是阿里巴巴开源的高性能、轻量级 RPC 框架,提供六大核心能力:面向接口的远程方法调用、智能容错与负载均衡、服务自动注册与发现、高度可扩展的 SPI 机制、丰富的服务治理功能、以及完善的监控与运维体系。在 Spring Cloud Alibaba 生态中,Dubbo 承担着微服务之间的高性能内部 RPC 调用角色。


一、为什么需要 Dubbo?

1.1 RPC 和 HTTP 的区别

  在微服务通信中,RPC 和 HTTP 是两种最常见的通信方式。理解它们的区别,是理解 Dubbo 定位的前提。

维度RPC(Remote Procedure Call)HTTP(REST)
核心思想像调用本地方法一样调用远程服务通过 URI 操作资源,无状态请求-响应
协议层基于 TCP,自定义应用层协议基于 TCP,标准 HTTP 协议
序列化高效二进制序列化(Hessian、Protobuf、Kryo)文本序列化(JSON、XML)
性能高吞吐、低延迟(TCP 长连接复用)相对较低(每次请求建立连接,HTTP/1.1 可复用)
跨语言需 IDL 定义,多语言 SDK 支持天然跨语言,任何语言均可调用
服务治理完善(注册中心、负载均衡、集群容错)需借助网关/服务网格实现
调试友好差(二进制协议,不可直接阅读)好(JSON 文本,curl 可直接调试)
适用场景微服务内部高性能调用对外 API、跨语言调用、浏览器直接访问

1.2 Dubbo 在微服务中的定位:高性能内部 RPC 调用

  在典型的微服务架构中,服务间通信有两种典型路径:

┌─────────────────────────────────────────────────────────────────────┐
│                       微服务通信架构                                  │
│                                                                      │
│   ┌──────────┐   HTTP/REST (Feign)    ┌──────────┐                  │
│   │  Browser  │ ──────────────────────→│  Gateway  │                  │
│   └──────────┘                        └────┬─────┘                  │
│                                            │                        │
│                      ┌─────────────────────┼────────────────────┐   │
│                      │    服务间内部通信     │                    │   │
│                      ▼                     ▼                    │   │
│               ┌──────────┐          ┌──────────┐               │   │
│               │ 服务 A    │←──TCP──→│ 服务 B    │               │   │
│               │(Dubbo RPC)│  Dubbo  │(Dubbo RPC)│               │   │
│               └──────────┘          └──────────┘               │   │
│                      │                     │                    │   │
│                      └─────────┬───────────┘                    │   │
│                                │                                │   │
│                对外 API 使用 HTTP/REST                          │   │
│                内部服务调用使用 Dubbo RPC                        │   │
└─────────────────────────────────────────────────────────────────────┘

  核心原则:对外暴露 RESTful API(便于跨语言/跨平台),内部服务间使用 Dubbo RPC(高性能)。Dubbo 不是替代 HTTP,而是与 HTTP 互补。

1.3 Feign(HTTP/REST)vs Dubbo(TCP/RPC)

维度Feign(Spring Cloud)Dubbo(Spring Cloud Alibaba)
通信协议HTTP/1.1(REST)TCP 长连接(自定义协议 / HTTP/2)
序列化JSON(文本)Hessian / Protobuf(二进制)
性能中等(HTTP 头部开销 + JSON 序列化)高(自定义协议头精简 + 二进制序列化)
连接管理每次请求建立连接(或连接池复用)TCP 长连接复用,多路复用
服务治理依赖 Ribbon/LoadBalancer + 外部组件内置负载均衡、集群容错、路由
服务注册依赖 Spring Cloud 注册中心多注册中心支持(Nacos/ZK/Redis)
接口定义@FeignClient + @RequestMappingJava Interface + @DubboService/@DubboReference
调试curl / Postman 直接测试需 telnet 或 Dubbo 自带工具
学习成本低(REST 风格,开发者熟悉)中(需理解 RPC 概念和 Dubbo 配置)

1.4 Dubbo 的优势

  1. 高性能:基于 TCP 长连接 + 二进制序列化,比 HTTP/JSON 性能高一倍以上。支持 NIO 网络模型(Netty),单机可支撑数十万并发连接。
  2. 完善的服务治理:内置负载均衡、集群容错、路由规则、服务降级、流量控制等能力,无需额外组件。
  3. 多协议支持:dubbo://(默认高性能协议)、tri://(HTTP/2 + gRPC 兼容)、rest://(HTTP REST)、hessian://、gRPC:// 等,一套代码多协议暴露。
  4. 多注册中心:Nacos、ZooKeeper、Redis、Consul、Etcd 等,与 Spring Cloud Alibaba 生态无缝集成。
  5. 高度可扩展:SPI 机制允许自定义协议、序列化、负载均衡、过滤器等几乎所有组件。
  6. 服务治理可视化:Dubbo Admin 提供可视化控制台,支持服务查询、路由管理、动态配置。

二、核心架构

2.1 整体架构图

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  Registry    │     │   Monitor    │     │  Dubbo Admin │
│  注册中心     │     │   监控中心    │     │   管理控制台   │
│ (Nacos / ZK) │     │ (Dubbo Admin)│     │              │
└──────┬───────┘     └──────┬───────┘     └──────────────┘
       │                    │
       │ ② 注册服务          │ ④ 上报统计
       │                    │
       ▼                    ▼
┌──────────────┐     ┌──────────────┐
│   Provider   │     │   Consumer   │
│  服务提供者   │     │  服务消费者   │
│              │     │              │
│  ┌────────┐  │     │  ┌────────┐  │
│  │ 服务实现 │  │     │  │ 服务调用 │  │
│  └────────┘  │     │  └────────┘  │
│  ┌────────┐  │     │  ┌────────┐  │
│  │ Container│  │     │  │ Cluster │  │
│  │ (Spring) │  │     │  │(容错/均衡)│  │
│  └────────┘  │     │  └────────┘  │
└──────────────┘     └──────────────┘
       │                    │
       └─────────┬──────────┘

                 │ ③ 直连调用(RPC 调用)
                 │    异步 / 同步
                 │    TCP 长连接


          ┌──────────────┐
          │   Network    │
          │   (Netty)    │
          └──────────────┘

2.2 五大核心角色

角色说明
Provider(服务提供者)暴露服务的服务提供方,向注册中心注册自己提供的服务。
Consumer(服务消费者)调用远程服务的服务消费方,从注册中心订阅服务地址列表。
Registry(注册中心)负责服务地址的注册与发现。Provider 注册地址,Consumer 订阅地址。
Monitor(监控中心)统计服务调用次数、调用时间、成功率等,上报到监控中心。
Container(服务运行容器)服务运行的容器环境,通常是 Spring 容器。

2.3 服务注册与发现流程

   Provider                          Registry                          Consumer
      │                                 │                                 │
      │  ① register(service, IP:Port)   │                                 │
      │ ──────────────────────────────→ │                                 │
      │                                 │                                 │
      │                                 │  ② subscribe(service)           │
      │                                 │ ←────────────────────────────── │
      │                                 │                                 │
      │                                 │  ③ notify(provider addresses)   │
      │                                 │ ──────────────────────────────→ │
      │                                 │                                 │
      │                                 │  ④ 缓存地址列表到本地            │
      │                                 │                                 │
      │  ←────────── RPC 调用 ──────────────────────────────────────────→ │
      │                 ⑤ 直连 Provider(TCP 长连接)                      │
      │                                 │                                 │
      │  ⑥ 心跳检测(定期)               │  ⑥ 心跳检测(定期)              │
      │ ──────────────────────────────→ │ ←────────────────────────────── │
      │                                 │                                 │

流程说明

  1. 注册:Provider 启动时,将自身服务信息(接口名、IP、端口、方法列表)注册到注册中心。
  2. 订阅:Consumer 启动时,向注册中心订阅所需服务。
  3. 通知:注册中心将 Provider 地址列表推送给 Consumer。
  4. 缓存:Consumer 将地址列表缓存到本地,以防注册中心不可用时仍能调用。
  5. 直连调用:Consumer 通过负载均衡策略选择一个 Provider,直接发起 RPC 调用(不经过注册中心)。
  6. 心跳检测:Provider 和 Consumer 定期向注册中心发送心跳,保持连接活跃。

2.4 RPC 调用流程(一次完整的 Dubbo 调用)

  Consumer 端                                    Provider 端
      │                                               │
      │  ① 调用接口方法(代理对象)                       │
      ▼                                               │
  ┌─────────┐                                         │
  │  Proxy  │  动态代理(Javassist/JDK)                │
  └────┬────┘                                         │
       │  ② 组装请求(方法名、参数、版本等)               │
       ▼                                               │
  ┌─────────┐                                         │
  │ Cluster │  集群容错(Failover/Failfast 等)          │
  └────┬────┘                                         │
       │  ③ 选择集群策略                               │
       ▼                                               │
  ┌─────────┐                                         │
  │LoadBalance│  负载均衡(Random/RoundRobin 等)        │
  └────┬────┘                                         │
       │  ④ 选择一个 Provider 地址                      │
       ▼                                               │
  ┌─────────┐                                         │
  │  Filter  │  过滤器链(监控、限流、鉴权等)             │
  └────┬────┘                                         │
       │  ⑤ 网络传输                                   │
       ▼                                               │
  ┌─────────┐        TCP 长连接        ┌─────────┐    │
  │ Protocol│ ←──────────────────────→ │ Protocol│    │
  │ (编码)  │     二进制数据流           │ (解码)  │    │
  └────┬────┘                          └────┬────┘    │
       │                                    │         │
       │  ⑥ 序列化(Hessian/Protobuf)       │  ⑦ 反序列化
       │                                    │         │
       │                                    ▼         │
       │                               ┌─────────┐    │
       │                               │  Filter  │   │
       │                               └────┬────┘    │
       │                                    │         │
       │                                    ▼         │
       │                               ┌─────────┐    │
       │                               │  Invoker │   │
       │                               │(反射调用)│    │
       │                               └────┬────┘    │
       │                                    │         │
       │                                    ▼         │
       │                               ┌─────────┐    │
       │                               │  Service │   │
       │                               │ (业务实现)│    │
       │                               └─────────┘    │
       │                                    │         │
       │  ←─────────── 返回结果 ────────────────────── │
       │                                               │

关键步骤

  1. Proxy 代理:Consumer 通过动态代理将接口调用转换为 RPC 请求。
  2. Cluster 集群:选择合适的集群容错策略(如 Failover 失败重试其他节点)。
  3. LoadBalance:从多个 Provider 中选择一个节点进行调用。
  4. Filter 过滤器:在调用前后执行监控、限流、鉴权等逻辑。
  5. Protocol 编解码:将 Java 对象序列化为二进制数据,通过网络传输。
  6. 反序列化:Provider 将收到的二进制数据反序列化为 Java 对象。
  7. 反射调用:Provider 通过反射调用对应的业务实现方法。

三、Dubbo 3.x 新特性

  Dubbo 3.x 是 Dubbo 的一个重大版本升级,从 2.7 直接跳到 3.0,标志着 Dubbo 从"微服务 RPC 框架"向"云原生微服务基础设施"的全面演进。

3.1 应用级服务发现

  这是 Dubbo 3.x 最核心的架构变化。

Dubbo 2.x 接口级服务发现的问题

  注册中心中存储的粒度:接口级
  ┌──────────────────────────────────────────────┐
  │  com.example.UserService  →  192.168.1.1:20880│
  │  com.example.OrderService →  192.168.1.1:20880│
  │  com.example.UserService  →  192.168.1.2:20880│
  │  com.example.OrderService →  192.168.1.2:20880│
  └──────────────────────────────────────────────┘
  问题:一个应用有 100 个接口,3 个实例 → 300 条注册数据

Dubbo 3.x 应用级服务发现

  注册中心中存储的粒度:应用级
  ┌──────────────────────────────────────────────┐
  │  app-user-service  →  192.168.1.1:20880       │
  │  app-user-service  →  192.168.1.2:20880       │
  │  app-user-service  →  192.168.1.3:20880       │
  └──────────────────────────────────────────────┘
  优势:一个应用只需注册一次,与接口数量无关
维度接口级(Dubbo 2.x)应用级(Dubbo 3.x)
注册粒度每个接口单独注册整个应用统一注册
注册数据量接口数 x 实例数(爆炸式增长)实例数(恒定)
注册中心压力高(接口多的应用产生大量数据)低(恒定数据量)
与 Spring Cloud 对齐不对齐(Spring Cloud 是应用级)完全对齐
与 Kubernetes 对齐不对齐(K8s Service 是应用级)完全对齐

3.2 Triple 协议

  Triple 是 Dubbo 3.x 定义的新一代 RPC 通信协议,基于 HTTP/2 构建,兼容 gRPC。

┌─────────────────────────────────────────────────────────┐
│                    Triple 协议栈                          │
│                                                          │
│  ┌──────────────────────────────────────────────────┐   │
│  │              应用层:Dubbo Business                 │   │
│  ├──────────────────────────────────────────────────┤   │
│  │         序列化层:Protobuf / Hessian / JSON         │   │
│  ├──────────────────────────────────────────────────┤   │
│  │              传输层:HTTP/2                         │   │
│  │        • 多路复用(Stream Multiplexing)            │   │
│  │        • 全双工通信(Bidirectional Streaming)      │   │
│  │        • 头部压缩(HPACK)                          │   │
│  │        • 服务端推送(Server Push)                  │   │
│  ├──────────────────────────────────────────────────┤   │
│  │                  TLS(可选)                        │   │
│  ├──────────────────────────────────────────────────┤   │
│  │                  TCP                                │   │
│  └──────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
特性Triple 协议Dubbo 2.x 协议
底层传输HTTP/2TCP 自定义协议
多路复用原生支持(HTTP/2 Stream)不支持
流式调用支持(Client Stream / Server Stream / Bidirectional)不支持
穿透网关天然支持(HTTP/2)困难(私有协议)
与 gRPC 互通完全兼容 gRPC 客户端不兼容
浏览器调用支持(HTTP/2 + JSON)不支持
性能接近 dubbo 协议略高(无 HTTP/2 头部开销)

3.3 云原生支持

  • Kubernetes 原生服务发现:直接使用 K8s API Server 作为注册中心,无需额外部署 Nacos/ZK。
  • xDS 协议支持:支持 Istio/Envoy 的服务发现标准协议,可与 Service Mesh 集成。
  • Proxyless Mesh:Dubbo 3.x 可直接与 Istio 控制面通信,无需部署 Envoy Sidecar,实现无代理服务网格。

3.4 Mesh 支持

  传统 Service Mesh:                          Dubbo Proxyless Mesh:
  
  ┌──────────┐   ┌──────────┐                ┌──────────┐   ┌──────────┐
  │  App A   │   │  App B   │                │  App A   │   │  App B   │
  ├──────────┤   ├──────────┤                │+ Dubbo 3 │   │+ Dubbo 3 │
  │  Sidecar │   │  Sidecar │                │  (xDS)   │   │  (xDS)   │
  ├──────────┤   ├──────────┤                └────┬─────┘   └────┬─────┘
  │  App A   │   │  App B   │                     │              │
  └──────────┘   └──────────┘                     │  xDS 协议     │
       │               │                          └───────┬──────┘
       └───────┬───────┘                                  │
               │                                  ┌───────▼──────┐
        ┌──────▼──────┐                           │   Istio CP   │
        │   Istio CP  │                           │  (Pilot)     │
        │  (Pilot)    │                           └──────────────┘
        └─────────────┘
  
  缺点:Sidecar 额外资源开销          优势:无 Sidecar,性能更高,架构更简单

四、核心概念

4.1 服务接口(Service Interface)

  Dubbo 是面向接口的 RPC 框架,服务接口是 Provider 和 Consumer 之间的契约。通常将接口定义在独立的 API 模块中,供双方共同依赖。

java
// dubbo-api 模块
public interface UserService {
    UserDTO getUserById(Long id);
    List<UserDTO> listUsers(String keyword);
}

4.2 服务分组(Group)

  当一个接口有多种实现时,使用 group 区分。例如:同一个 UserService 接口,有 readwrite 两种实现,分别部署。

yaml
# Provider 端
dubbo:
  provider:
    group: read    # 或 write

# Consumer 端
dubbo:
  consumer:
    group: read    # 订阅 read 分组的服务
java
// 消费者代码中指定分组
@DubboReference(group = "read")
private UserService readUserService;

@DubboReference(group = "write")
private UserService writeUserService;

4.3 服务版本(Version)

  当一个接口有多个不兼容的版本时,使用 version 进行灰度升级。版本号通常遵循语义化版本规范。

  场景:UserService 从 v1.0 升级到 v2.0
  
  ┌──────────┐     ┌──────────┐     ┌──────────┐
  │ Consumer │     │Provider v1│    │Provider v2│
  │  (v1.0)  │────→│  (v1.0)  │    │  (v2.0)  │
  └──────────┘     └──────────┘     └──────────┘

  ┌──────────┐                              │
  │ Consumer │                              │
  │  (v2.0)  │─────────────────────────────→│
  └──────────┘
java
// Provider v2.0
@DubboService(version = "2.0.0")
public class UserServiceImplV2 implements UserService { ... }

// Consumer v2.0
@DubboReference(version = "2.0.0")
private UserService userService;

4.4 超时(Timeout)

  超时是 Dubbo 中最基础的容错机制。默认为 1000ms(1 秒)。

配置位置说明默认值
Provider 端服务端方法执行超时1000ms
Consumer 端客户端调用等待超时1000ms
方法级针对特定方法设置超时继承上级

优先级(从高到低):Consumer 方法级 > Consumer 接口级 > Provider 方法级 > Provider 接口级 > Consumer 全局 > Provider 全局

yaml
dubbo:
  provider:
    timeout: 3000        # Provider 全局超时 3s
  consumer:
    timeout: 5000        # Consumer 全局超时 5s
java
// 方法级超时
@DubboReference(timeout = 3000, parameters = {"findById.timeout", "1000"})
private UserService userService;

4.5 重试(Retries)

  当 RPC 调用失败时,Dubbo 会自动重试。默认重试 2 次(加上第一次调用共 3 次)。注意:重试仅适用于幂等操作(读操作),非幂等操作(写操作)应设置 retries=0

yaml
dubbo:
  consumer:
    retries: 2           # 默认重试 2 次
java
// 写操作禁止重试
@DubboReference(retries = 0)
private OrderService orderService;

// 读操作允许重试
@DubboReference(retries = 3)
private UserService userService;

4.6 负载均衡(Load Balance)

  Dubbo 内置 4 种负载均衡策略,详见第六章。

4.7 集群容错(Cluster)

  Dubbo 内置 6 种集群容错策略,详见第七章。

4.8 服务降级(Service Mock)

  当服务不可用时,返回降级数据(Mock 数据),保证核心业务可用。

java
// 方式一:配置 mock 类
@DubboReference(mock = "com.example.mock.UserServiceMock")
private UserService userService;

// 方式二:配置 mock 返回值
@DubboReference(mock = "return null")
private UserService userService;

// 方式三:配置 mock 抛出异常
@DubboReference(mock = "throw com.example.BusinessException")
private UserService userService;

4.9 本地存根(Stub)

  在 Consumer 端执行部分逻辑(如参数验证、缓存),再发起远程调用。

java
// 存根类
public class UserServiceStub implements UserService {
    private final UserService userService;
    
    public UserServiceStub(UserService userService) {
        this.userService = userService;
    }
    
    @Override
    public UserDTO getUserById(Long id) {
        // 参数验证在本地执行
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("invalid id");
        }
        // 缓存检查
        // ...
        return userService.getUserById(id);
    }
}

// 使用
@DubboReference(stub = "com.example.stub.UserServiceStub")
private UserService userService;

五、协议详解

5.1 各协议详细说明

5.1.1 dubbo:// 协议(默认)

  Dubbo 默认协议,基于 TCP 长连接 + NIO 异步通信,使用 Hessian 二进制序列化。适合小数据量大并发的服务调用。

  • 连接方式:单一长连接(一个 Consumer 与一个 Provider 之间只建立一条 TCP 连接)
  • 传输框架:Netty(NIO)
  • 序列化:Hessian2(默认)
  • 适用场景:请求量较大(> 1000),但每次请求数据量较小(< 100KB)的场景
  • 不适合:传输大文件、超大字符串

5.1.2 tri:// 协议(Dubbo 3.x 推荐)

  基于 HTTP/2 的新一代协议,兼容 gRPC,支持流式调用。

  • 连接方式:HTTP/2 多路复用(一个连接支持多个并发 Stream)
  • 传输框架:Netty(HTTP/2)
  • 序列化:Protobuf(默认)、Hessian、JSON
  • 适用场景:需要穿透网关、需要流式调用、需要与 gRPC 互通、需要浏览器直接访问的场景

5.1.3 rest:// 协议

  基于标准的 HTTP REST 协议,使用 JAX-RS 注解。

  • 连接方式:HTTP 短连接 / 连接池
  • 传输框架:Servlet 容器(Tomcat/Jetty)或 Netty
  • 序列化:JSON、XML
  • 适用场景:需要对外暴露 RESTful API、需要跨语言调用

5.1.4 hessian:// 协议

  基于 HTTP 的 Hessian 远程调用协议,用于 Dubbo 与 Hessian 服务互通。

  • 连接方式:HTTP 短连接
  • 传输框架:Servlet 容器
  • 序列化:Hessian
  • 适用场景:需要与 Hessian 原生服务互通

5.1.5 gRPC:// 协议

  基于 gRPC 的协议,使用 HTTP/2 + Protobuf。

  • 连接方式:HTTP/2 多路复用
  • 传输框架:Netty(gRPC)
  • 序列化:Protobuf
  • 适用场景:需要与 gRPC 生态互通、需要跨语言 IDL 定义

5.2 协议对比表

协议连接方式序列化性能跨语言流式调用穿透网关适用场景
dubbo://TCP 长连接 + NIOHessian2最高不支持困难内部微服务高性能调用
tri://HTTP/2 多路复用Protobuf/Hessian支持天然支持云原生、Mesh、流式场景
rest://HTTP 短连接JSON/XML最好不支持天然支持对外 API、跨语言调用
hessian://HTTP 短连接Hessian较好不支持支持与 Hessian 服务互通
gRPC://HTTP/2 多路复用Protobuf支持天然支持与 gRPC 生态互通

5.3 多协议暴露

  Dubbo 支持同时暴露多种协议,同一服务可以被不同协议的消费者调用。

yaml
dubbo:
  protocols:
    - id: dubbo
      name: dubbo
      port: 20880
    - id: triple
      name: tri
      port: 50051
    - id: rest
      name: rest
      port: 8080

六、负载均衡策略

  Dubbo 内置 4 种负载均衡策略,默认使用 Random(随机,带权重)。

6.1 Random(随机,带权重)

原理:根据权重随机选择 Provider。权重越大,被选中的概率越高。

  假设 3 个 Provider,权重分别为 5、3、2
  
  ┌──────────┐  ┌──────────┐  ┌──────────┐
  │ Provider1│  │ Provider2│  │ Provider3│
  │  weight=5│  │  weight=3│  │  weight=2│
  └──────────┘  └──────────┘  └──────────┘
      50%            30%           20%

适用场景:通用场景,各 Provider 性能差异不大时使用。通过权重可以适配不同性能的机器。

配置

yaml
dubbo:
  consumer:
    loadbalance: random
java
@DubboReference(loadbalance = "random")
private UserService userService;

6.2 RoundRobin(轮询)

原理:按顺序依次调用每个 Provider。支持权重,权重大的 Provider 每轮被调用更多次。

  无权重:轮询 1 → 2 → 3 → 1 → 2 → 3 → ...
  有权重(5:3:2):
  每 10 次调用:Provider1 被调用 5 次,Provider2 被调用 3 次,Provider3 被调用 2 次

适用场景:各 Provider 性能完全一致,需要均匀分配请求的场景。

注意:Dubbo 的 RoundRobin 存在请求累积问题(当 Provider 响应时间不一致时,慢的 Provider 会累积更多请求)。推荐使用 LeastActive 替代。

配置

java
@DubboReference(loadbalance = "roundrobin")
private UserService userService;

6.3 LeastActive(最小活跃数)

原理:选择当前活跃请求数最少的 Provider。活跃请求数 = 已发送但未收到响应的请求数。如果活跃数相同,则随机选择。

  活跃请求数状态:
  ┌──────────┐  ┌──────────┐  ┌──────────┐
  │ Provider1│  │ Provider2│  │ Provider3│
  │ active=5 │  │ active=2 │  │ active=8 │
  └──────────┘  └──────────┘  └──────────┘

                              选择 Provider2(活跃数最小)

适用场景:各 Provider 处理能力不同,或者请求处理时间差异较大的场景。能自动将请求分配给处理速度更快的 Provider,实现动态负载均衡。

配置

java
@DubboReference(loadbalance = "leastactive")
private UserService userService;

6.4 ConsistentHash(一致性哈希)

原理:根据请求参数(默认第一个参数)的哈希值,将请求路由到固定的 Provider。相同参数的请求始终落到同一台机器。

  哈希环:
  
                    ┌──────────┐
                    │ Provider1│
                    │  hash=100│
                    └──────────┘

    ┌──────────┐        │        ┌──────────┐
    │ Provider3│        │        │ Provider2│
    │ hash=300 │────────○────────│ hash=200 │
    └──────────┘                 └──────────┘

                   请求 hash=150
                   → 顺时针找到 Provider2

适用场景

  • 需要缓存亲和性的场景(相同请求打到同一台机器,可命中本地缓存)
  • 有状态服务(如 WebSocket 长连接需要固定路由到同一节点)

注意:当 Provider 增减时,只有部分请求会重新分配,不会全部打散。

配置

java
// 使用一致性哈希,指定哈希参数
@DubboReference(loadbalance = "consistenthash")
private UserService userService;

6.5 负载均衡策略对比

策略原理权重支持适用场景注意事项
Random随机选择通用场景,默认策略调用量少时可能不均匀
RoundRobin依次轮询各 Provider 性能一致响应慢的 Provider 会累积请求
LeastActive选活跃数最小Provider 性能差异大需要预热时间
ConsistentHash参数哈希路由有状态服务、缓存亲和Provider 增减时部分请求重分配

七、集群容错

  Dubbo 内置 6 种集群容错策略,默认使用 Failover(失败自动切换)。

7.1 Failover(失败自动切换,默认)

原理:调用失败后,自动切换到其他 Provider 重试。默认重试 2 次(共 3 次调用)。

  Consumer                              Provider 集群

      │  ① 调用 Provider1
      │ ──────────────────────────────→  Provider1 ❌ 失败

      │  ② 重试 Provider2
      │ ──────────────────────────────→  Provider2 ✅ 成功

      │  ③ 返回结果
      │ ←──────────────────────────────

适用场景:读操作(幂等查询),对可用性要求高的场景。

注意:写操作必须谨慎使用,可能导致数据重复写入。建议写操作设置 retries=0

配置

yaml
dubbo:
  consumer:
    cluster: failover
    retries: 2

7.2 Failfast(快速失败)

原理:调用失败后立即报错,不重试。适合非幂等写操作。

  Consumer                              Provider 集群

      │  ① 调用 Provider1
      │ ──────────────────────────────→  Provider1 ❌ 失败

      │  ② 立即抛出异常,不重试

适用场景:写操作(新增、修改、删除),必须保证不重复执行。

配置

java
@DubboReference(cluster = "failfast", retries = 0)
private OrderService orderService;

7.3 Failsafe(忽略失败)

原理:调用失败后忽略异常,返回空结果。仅记录日志,不影响主流程。

适用场景:非关键功能(如日志记录、审计、通知),失败不影响核心业务。

配置

java
@DubboReference(cluster = "failsafe")
private AuditLogService auditLogService;

7.4 Failback(失败后重试)

原理:调用失败后,将请求放入失败队列,后台定时重试(默认 5 秒一次),直到成功。

  Consumer

      │  ① 调用 Provider → 失败

      │  ② 放入失败队列
      │     ┌──────────────────┐
      │     │ 5s 后重试一次      │
      │     │ 10s 后重试二次     │
      │     │ ...              │
      │     │ 直到成功或超时     │
      │     └──────────────────┘

适用场景:消息通知、异步任务,必须保证最终一致性。

注意:失败队列在内存中,Consumer 重启会丢失未重试的请求。

配置

java
@DubboReference(cluster = "failback")
private NotificationService notificationService;

7.5 Forking(并行调用)

原理:同时向多个 Provider 发起调用,只要有一个成功就返回结果(取最快响应)。

  Consumer                              Provider 集群

      │  ① 同时调用 Provider1、Provider2、Provider3
      │ ──────────────────────────────→  Provider1 ⏱ 100ms ✅
      │ ──────────────────────────────→  Provider2 ⏱ 200ms (忽略)
      │ ──────────────────────────────→  Provider3 ⏱ 150ms (忽略)

      │  ② 取第一个返回的成功结果

适用场景:对延迟要求极高的场景(如实时推荐),用资源换时间。

注意:会消耗更多 Provider 资源(每个请求被 N 个 Provider 处理),仅在资源充足时使用。

配置

java
@DubboReference(cluster = "forking", parameters = {"forks", "3"})
private RecommendService recommendService;

7.6 Broadcast(广播调用)

原理:向所有 Provider 广播调用,任何一个 Provider 报错即报错。调用所有 Provider 后才返回结果。

  Consumer                              Provider 集群

      │  ① 广播调用所有 Provider
      │ ──────────────────────────────→  Provider1 ✅
      │ ──────────────────────────────→  Provider2 ✅
      │ ──────────────────────────────→  Provider3 ❌ → 整体报错

适用场景:通知所有 Provider 刷新缓存、更新配置等全局操作。

配置

java
@DubboReference(cluster = "broadcast")
private CacheRefreshService cacheRefreshService;

7.7 集群容错策略对比

策略失败处理资源消耗适用场景典型业务
Failover自动切换重试幂等读操作查询用户信息
Failfast立即报错非幂等写操作创建订单
Failsafe忽略异常非关键功能日志审计
Failback后台定时重试异步保证最终一致发送通知
Forking并行多路调用极致低延迟实时推荐
Broadcast全量广播全局通知刷新缓存

八、服务治理

8.1 超时配置

  超时配置是 Dubbo 中最基础也最重要的配置项。合理的超时配置可以防止服务雪崩。

配置优先级(从高到低)

  Consumer 方法级  >  Consumer 接口级  >  Provider 方法级  >  Provider 接口级  >  Consumer 全局  >  Provider 全局
yaml
dubbo:
  provider:
    timeout: 3000                      # Provider 全局:3 秒
  consumer:
    timeout: 5000                      # Consumer 全局:5 秒
java
// 接口级优先级更高
@DubboService(timeout = 2000)
public class UserServiceImpl implements UserService { ... }

// Consumer 方法级优先级最高
@DubboReference(timeout = 1000, parameters = {"getUserById.timeout", "500"})
private UserService userService;

最佳实践

  • 数据库查询类接口:2~5 秒
  • 缓存查询类接口:500ms~1 秒
  • 复杂计算类接口:5~10 秒
  • 永远不要设置 timeout=0(无限等待),可能导致线程耗尽

8.2 重试机制

重试策略

  第一次调用 → 失败 → 等待 → 第二次调用(重试1) → 失败 → 等待 → 第三次调用(重试2)
  
  默认配置:retries=2,即最多调用 3 次

重试配置示例

yaml
dubbo:
  consumer:
    retries: 2                         # 默认重试 2 次
java
// 读操作:允许重试
@DubboReference(retries = 3)
private UserService userService;

// 写操作:禁止重试
@DubboReference(retries = 0)
private OrderService orderService;

重试的注意事项

  1. 重试仅适用于幂等操作(GET、QUERY)。
  2. 非幂等操作(INSERT、UPDATE、DELETE)必须设置 retries=0
  3. 重试会放大下游压力(3 次调用 = 3 倍压力),需评估下游容量。
  4. 超时时间应大于单次调用的合理时间,否则重试不会生效。

8.3 版本灰度(Version)

  通过 version 实现服务版本管理和灰度发布。

  灰度发布流程:
  
  Step 1: 初始状态
  ┌──────────┐     ┌──────────┐
  │ Consumer │────→│Provider v1│  (100% 流量)
  │(version=1│     │(version=1│
  │   .0.0)  │     │  .0.0)   │
  └──────────┘     └──────────┘
  
  Step 2: 部署新版本 Provider v2
  ┌──────────┐     ┌──────────┐     ┌──────────┐
  │ Consumer │────→│Provider v1│     │Provider v2│
  │(version=1│     │(version=1│     │(version=2│
  │  .0.0)   │     │  .0.0)   │     │  .0.0)   │
  └──────────┘     └──────────┘     └──────────┘

                                    无流量(未被订阅)
  
  Step 3: 切换部分 Consumer
  ┌──────────┐     ┌──────────┐     ┌──────────┐
  │ Consumer │────→│Provider v1│     │Provider v2│
  │(version=1│     │(version=1│     │(version=2│
  │  .0.0)   │     │  .0.0)   │     │  .0.0)   │
  └──────────┘     └──────────┘     └──────────┘

  ┌──────────┐                        有流量
  │ Consumer │─────────────────────────→│
  │(version=2│
  │  .0.0)   │
  └──────────┘
java
// Provider v1
@DubboService(version = "1.0.0")
public class UserServiceImplV1 implements UserService { ... }

// Provider v2
@DubboService(version = "2.0.0")
public class UserServiceImplV2 implements UserService { ... }

// Consumer - 灰度切换
@DubboReference(version = "2.0.0")
private UserService userService;

8.4 分组隔离(Group)

  通过 group 实现同一接口的多种实现隔离。

  场景:线上环境和测试环境共享注册中心,用 group 隔离
  
  ┌──────────┐     ┌──────────┐
  │ Consumer │────→│Provider   │
  │(group=   │     │(group=    │
  │  prod)   │     │  prod)    │
  └──────────┘     └──────────┘
  
  ┌──────────┐     ┌──────────┐
  │ Consumer │────→│Provider   │
  │(group=   │     │(group=    │
  │  test)   │     │  test)    │
  └──────────┘     └──────────┘
java
// 读写分离
@DubboReference(group = "read")
private UserService readUserService;

@DubboReference(group = "write")
private UserService writeUserService;

8.5 多注册中心

yaml
dubbo:
  registries:
    nacos:
      address: nacos://localhost:8848
      group: DUBBO_GROUP
    zookeeper:
      address: zookeeper://localhost:2181
java
// 指定服务注册到特定注册中心
@DubboService(registry = {"nacos", "zookeeper"})
public class UserServiceImpl implements UserService { ... }

// 消费者从特定注册中心订阅
@DubboReference(registry = "nacos")
private UserService userService;

8.6 多协议暴露

yaml
dubbo:
  protocols:
    dubbo:
      name: dubbo
      port: 20880
    triple:
      name: tri
      port: 50051
java
// 同时暴露 dubbo 和 triple 协议
@DubboService(protocol = {"dubbo", "triple"})
public class UserServiceImpl implements UserService { ... }

九、核心配置

9.1 完整 YAML 配置示例

yaml
dubbo:
  # ==================== 应用配置 ====================
  application:
    name: user-service-provider          # 应用名称(必填),用于服务注册和监控
    owner: team-platform                 # 应用负责人
    organization: example                # 组织名称
    logger: slf4j                        # 日志框架
    qos-enable: true                     # 是否开启 QOS 运维命令
    qos-port: 22222                      # QOS 端口

  # ==================== 注册中心配置 ====================
  registry:
    address: nacos://localhost:8848      # 注册中心地址
    protocol: nacos                      # 注册中心协议(nacos/zookeeper/redis/consul)
    group: DUBBO_GROUP                   # 注册中心分组
    timeout: 5000                        # 注册中心连接超时
    check: true                          # 启动时检查注册中心是否可用
    register: true                       # 是否向注册中心注册
    subscribe: true                      # 是否从注册中心订阅

  # ==================== 协议配置 ====================
  protocol:
    name: dubbo                          # 协议名称:dubbo/tri/rest/hessian/grpc
    port: 20880                          # 服务端口
    host: 192.168.1.100                  # 绑定的主机地址(多网卡时指定)
    serialization: hessian2              # 序列化方式:hessian2/fastjson2/kryo/protobuf
    threads: 200                         # 业务线程池大小
    iothreads: 8                         # IO 线程数
    accepts: 1000                        # 最大连接数
    payload: 8388608                     # 请求/响应最大字节数(默认 8MB)

  # ==================== Provider 配置 ====================
  provider:
    timeout: 3000                        # 远程调用超时(毫秒)
    retries: 2                           # 重试次数(不含首次调用)
    version: 1.0.0                       # 服务版本
    group: prod                          # 服务分组
    loadbalance: random                  # 负载均衡策略
    cluster: failover                    # 集群容错策略
    delay: -1                            # 延迟暴露(毫秒),-1 表示 Spring 初始化完成后暴露
    weight: 100                          # 服务权重
    connections: 1                       # 每个消费者最大连接数
    actives: 0                           # 每个服务最大并发调用数,0 表示不限制
    executes: 0                          # 每个方法最大并发调用数,0 表示不限制
    filter: providerFilter1,providerFilter2  # 服务提供者过滤器
    token: false                         # 令牌验证

  # ==================== Consumer 配置 ====================
  consumer:
    timeout: 5000                        # 远程调用超时(毫秒),优先级高于 Provider
    retries: 2                           # 重试次数
    version: 1.0.0                       # 服务版本
    group: prod                          # 服务分组
    loadbalance: random                  # 负载均衡策略
    cluster: failover                    # 集群容错策略
    check: true                          # 启动时检查 Provider 是否可用
    init: false                          # 是否在启动时初始化引用
    validation: true                     # 参数验证
    filter: consumerFilter1,consumerFilter2  # 服务消费者过滤器
    lazy: false                          # 延迟创建连接
    sticky: false                        # 粘滞连接

  # ==================== 监控中心配置 ====================
  monitor:
    protocol: registry                   # 从注册中心发现监控中心地址
    address: nacos://localhost:8848

  # ==================== 元数据中心配置 ====================
  metadata-report:
    address: nacos://localhost:8848      # 元数据中心地址
    retry-times: 30                      # 重试次数
    cycle-report: true                   # 是否循环上报

9.2 核心配置项速查

配置项位置说明默认值
dubbo.application.name全局应用名称必填
dubbo.registry.address全局注册中心地址必填
dubbo.protocol.name全局协议名称dubbo
dubbo.protocol.port全局协议端口20880
dubbo.provider.timeoutProvider服务端超时1000ms
dubbo.provider.retriesProvider服务端重试2
dubbo.provider.versionProvider服务版本0.0.0
dubbo.provider.groupProvider服务分组-
dubbo.provider.weightProvider服务权重100
dubbo.consumer.timeoutConsumer客户端超时1000ms
dubbo.consumer.retriesConsumer客户端重试2
dubbo.consumer.loadbalanceConsumer负载均衡random
dubbo.consumer.clusterConsumer集群容错failover
dubbo.consumer.checkConsumer启动检查true

十、Spring Cloud Alibaba + Dubbo 集成

10.1 项目结构

  dubbo-demo
  ├── dubbo-api                          # API 模块(接口定义)
  │   ├── pom.xml
  │   └── src/main/java/com/example/api/
  │       └── UserService.java
  ├── dubbo-provider                     # 服务提供者
  │   ├── pom.xml
  │   └── src/main/java/com/example/provider/
  │       ├── ProviderApplication.java
  │       └── UserServiceImpl.java
  │   └── src/main/resources/
  │       └── application.yml
  └── dubbo-consumer                     # 服务消费者
      ├── pom.xml
      └── src/main/java/com/example/consumer/
          ├── ConsumerApplication.java
          └── UserController.java
      └── src/main/resources/
          └── application.yml

10.2 依赖配置

父 POM(dependencyManagement)

xml
<dependencyManagement>
    <dependencies>
        <!-- Spring Cloud Alibaba BOM -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2023.0.1.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- Spring Boot BOM -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

dubbo-api 模块 pom.xml

xml
<dependencies>
    <!-- 仅需 Lombok,无 Dubbo 依赖 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

dubbo-provider 模块 pom.xml

xml
<dependencies>
    <!-- 依赖 API 模块 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>dubbo-api</artifactId>
        <version>1.0.0</version>
    </dependency>
    <!-- Spring Cloud Alibaba Dubbo Starter -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!-- Dubbo Spring Boot Starter -->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
    </dependency>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

10.3 服务接口定义(API 模块)

java
package com.example.api;

import java.io.Serializable;

/**
 * 用户服务接口
 * Provider 和 Consumer 共同依赖此接口
 */
public interface UserService {
    
    /**
     * 根据 ID 查询用户
     */
    UserDTO getUserById(Long id);
    
    /**
     * 创建用户
     */
    Long createUser(UserDTO user);
}

/**
 * 用户数据传输对象
 * 必须实现 Serializable 接口
 */
@Data
public class UserDTO implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private Long id;
    private String username;
    private String email;
    private Integer age;
}

10.4 服务提供者(Provider)

java
package com.example.provider;

import com.example.api.UserDTO;
import com.example.api.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;

/**
 * 用户服务实现类
 * @DubboService 注解将服务注册到 Dubbo 和 Nacos
 */
@DubboService(
    version = "1.0.0",           // 服务版本
    group = "prod",              // 服务分组
    timeout = 3000,              // 超时时间
    retries = 2,                 // 重试次数
    weight = 100                 // 服务权重
)
@Service
public class UserServiceImpl implements UserService {
    
    @Override
    public UserDTO getUserById(Long id) {
        // 模拟数据库查询
        UserDTO user = new UserDTO();
        user.setId(id);
        user.setUsername("user_" + id);
        user.setEmail("user_" + id + "@example.com");
        user.setAge(25);
        return user;
    }
    
    @Override
    public Long createUser(UserDTO user) {
        // 模拟数据库插入
        // 注意:写操作建议设置 retries=0,这里仅为演示
        user.setId(System.currentTimeMillis());
        return user.getId();
    }
}

ProviderApplication.java

java
package com.example.provider;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo                       // 启用 Dubbo
@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

Provider application.yml

yaml
server:
  port: 8081

spring:
  application:
    name: user-service-provider     # 应用名称,会注册到 Nacos
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # Nacos 地址

dubbo:
  application:
    name: user-service-provider     # Dubbo 应用名称
    logger: slf4j
  registry:
    address: nacos://localhost:8848 # 注册中心
  protocol:
    name: dubbo                     # 使用 dubbo 协议
    port: 20880                     # Dubbo 服务端口
  provider:
    timeout: 3000
    retries: 2
    version: 1.0.0

10.5 服务消费者(Consumer)

java
package com.example.consumer;

import com.example.api.UserDTO;
import com.example.api.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {
    
    /**
     * @DubboReference 注入远程服务代理
     */
    @DubboReference(
        version = "1.0.0",           // 匹配 Provider 版本
        group = "prod",              // 匹配 Provider 分组
        timeout = 5000,              // 超时时间(Consumer 端优先级更高)
        retries = 3,                 // 读操作允许重试
        loadbalance = "leastactive", // 负载均衡策略
        cluster = "failover",        // 集群容错
        check = false                // 启动时不检查 Provider 是否可用
    )
    private UserService userService;
    
    @GetMapping("/{id}")
    public UserDTO getUser(@PathVariable Long id) {
        // 像调用本地方法一样调用远程服务
        return userService.getUserById(id);
    }
    
    @PostMapping
    public Long createUser(@RequestBody UserDTO user) {
        return userService.createUser(user);
    }
}

ConsumerApplication.java

java
package com.example.consumer;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo
@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

Consumer application.yml

yaml
server:
  port: 8082

spring:
  application:
    name: user-service-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

dubbo:
  application:
    name: user-service-consumer
    logger: slf4j
  registry:
    address: nacos://localhost:8848
  consumer:
    timeout: 5000
    retries: 2
    loadbalance: random
    cluster: failover
    check: false                   # 启动时不检查 Provider

10.6 关键注解说明

注解位置说明
@EnableDubbo启动类启用 Dubbo 自动配置
@DubboServiceProvider 实现类标记为 Dubbo 服务,自动注册到注册中心
@DubboReferenceConsumer 字段注入远程服务代理,自动从注册中心订阅
@ServiceProvider 实现类Spring 的 Service 注解,与 @DubboService 共存

十一、Dubbo vs Feign vs gRPC

11.1 全面对比

维度DubboFeign(Spring Cloud)gRPC
协议TCP 自定义协议 / HTTP/2(Triple)HTTP/1.1(REST)HTTP/2
序列化Hessian2 / Protobuf / Kryo(二进制)JSON(文本)Protobuf(二进制)
性能高(自定义协议头部精简,长连接复用)中(HTTP 头部开销 + JSON 序列化)高(HTTP/2 + Protobuf)
连接模型TCP 长连接 + NIO 多路复用HTTP 连接池(短连接/Keep-Alive)HTTP/2 多路复用
跨语言一般(需 Dubbo SDK,Triple 后改善)最好(任何语言可调用 HTTP REST)好(官方多语言 SDK)
接口定义Java InterfaceJava Interface + 注解.proto 文件 + 代码生成
服务治理完善(内置负载均衡、容错、路由、降级)依赖 Spring Cloud 体系(LoadBalancer)依赖外部组件(Envoy/Istio)
注册中心多注册中心(Nacos/ZK/Redis/Consul)Spring Cloud 注册中心(Nacos/Eureka)需外部服务发现(DNS/K8s/Istio)
流式调用支持(Triple 协议)不支持原生支持(4 种流式模式)
学习成本中(需理解 RPC 概念)低(REST 风格,开发者熟悉)高(需学习 Protobuf + .proto 定义)
调试不直观(二进制协议)方便(curl/Postman 直接测试)不直观(需 grpcurl 等工具)
社区/生态Apache 顶级项目,阿里主导Spring Cloud 官方,社区庞大Google 主导,云原生标准
适用场景微服务内部高性能 RPC 调用对外 API、跨语言调用、内部 REST 服务跨语言高性能调用、流式场景

11.2 选型建议

                        开始


                  ┌──────────────┐
                  │ 是否需要      │
                  │ 跨语言调用?  │
                  └──────┬───────┘
                    是   │   否
                 ┌───────┴───────┐
                 ▼               ▼
          ┌──────────────┐ ┌──────────────┐
          │ 是否需要      │ │ 是否需要      │
          │ 流式调用?    │ │ 对外暴露 API? │
          └──────┬───────┘ └──────┬───────┘
            是   │   否      是   │   否
          ┌──────┴──┐    ┌───────┴───┐
          ▼         ▼    ▼           ▼
        gRPC      Feign Feign      Dubbo
       (HTTP/2)  (HTTP) (HTTP)    (TCP RPC)

简要总结

  • Dubbo:Java 微服务内部高性能 RPC 调用首选,服务治理能力最强。
  • Feign:对外 API、跨语言调用、简单 REST 服务场景合适,学习成本最低。
  • gRPC:跨语言 + 高性能 + 流式调用的场景,适合混合技术栈团队。

十二、面试要点

面试题 1:Dubbo 的工作流程是什么?

回答要点

  1. 服务注册:Provider 启动时,将服务信息(接口名、IP、端口、方法列表)注册到注册中心(Nacos/ZK)。
  2. 服务订阅:Consumer 启动时,从注册中心订阅所需服务,获取 Provider 地址列表并缓存到本地。
  3. 服务调用:Consumer 通过动态代理将接口调用转为 RPC 请求,经过集群容错(Failover)、负载均衡(Random/RoundRobin)、过滤器链,最终通过 Netty 发送 TCP 请求。
  4. 服务处理:Provider 收到请求后,反序列化、经过过滤器链、反射调用业务实现,返回结果。
  5. 监控上报:调用次数、耗时、成功率等统计数据上报到监控中心(Dubbo Admin)。
  6. 心跳检测:Provider 和 Consumer 定期向注册中心发送心跳,注册中心剔除不健康节点。

面试题 2:Dubbo 的负载均衡策略有哪些?

回答要点

策略原理适用场景
Random(默认)带权重的随机选择通用场景,各 Provider 性能相近
RoundRobin带权重的轮询各 Provider 性能完全一致
LeastActive选择活跃请求数最少的 ProviderProvider 性能差异大,响应时间不一致
ConsistentHash相同参数哈希到同一 Provider有状态服务、缓存亲和性

追问:RoundRobin 有什么问题?
:当 Provider 响应时间不一致时,慢的 Provider 会累积更多请求(因为轮询不考虑当前负载),可能导致请求堆积。LeastActive 策略可以解决这个问题。

面试题 3:Dubbo 的集群容错策略有哪些?

回答要点

策略原理典型场景
Failover(默认)失败后自动切换其他 Provider 重试幂等读操作
Failfast失败立即报错,不重试非幂等写操作(创建订单)
Failsafe失败忽略异常,记录日志非关键功能(日志审计)
Failback失败后放入队列,后台定时重试异步通知,保证最终一致性
Forking并行调用多个 Provider,取第一个成功极致低延迟(实时推荐)
Broadcast广播调用所有 Provider全局通知(刷新缓存)

追问:为什么写操作不能用 Failover?
:写操作(INSERT/UPDATE/DELETE)不是幂等的。如果 Provider 实际执行成功但 Consumer 因网络超时没收到响应,Failover 会重试到另一个 Provider,导致数据重复写入。

面试题 4:Dubbo 3.x 应用级服务发现是什么?为什么要从接口级升级?

回答要点

Dubbo 2.x 接口级服务发现:以接口为粒度注册,一个应用有 N 个接口、M 个实例,注册中心存储 N x M 条数据。当接口数量多时,注册数据量爆炸式增长,增大注册中心压力。

Dubbo 3.x 应用级服务发现:以应用为粒度注册,注册中心只存储 M 条数据(实例数),与接口数量无关。数据量大幅减少,注册中心压力恒定。

升级原因

  1. 降低注册中心存储和推送压力。
  2. 与 Spring Cloud(应用级)和 Kubernetes Service(应用级)对齐,更好地融入云原生生态。
  3. 支持 Proxyless Service Mesh,Dubbo 可直接与 Istio 控制面通信。

面试题 5:Dubbo 和 Feign 的区别?什么时候用哪个?

回答要点

维度DubboFeign
协议TCP 长连接 RPCHTTP/1.1 REST
性能高(二进制序列化 + 长连接)中(JSON + HTTP 开销)
服务治理内置完善依赖 Spring Cloud 体系
跨语言一般最好
调试不直观curl/Postman 直接测试

选型建议

  • Dubbo:Java 微服务内部高性能调用,服务治理要求高,QPS 大。
  • Feign:对外 API,跨语言调用,内部服务间调用量不大,团队对 REST 更熟悉。

面试题 6:Dubbo 的 RPC 调用原理(从 Consumer 到 Provider 的完整链路)?

回答要点

  1. 代理层(Proxy):Consumer 通过 @DubboReference 注入的不是真正的实现类,而是 Dubbo 生成的动态代理对象(Javassist/JDK Proxy)。
  2. 集群层(Cluster):代理对象将调用委托给 Cluster 层,Cluster 根据配置的容错策略(Failover/Failfast 等)决定如何调用。
  3. 负载均衡层(LoadBalance):Cluster 通过 LoadBalance 从 Provider 列表中选择一个节点。
  4. 过滤器链(Filter):在调用前后执行一系列 Filter(监控、限流、鉴权、上下文传递等)。
  5. 协议层(Protocol):将调用请求(接口名、方法名、参数类型、参数值)序列化为二进制数据,通过 Netty 的 TCP 长连接发送。
  6. 网络传输:Provider 端 Netty 接收数据,Protocol 反序列化。
  7. 过滤器链(Filter):Provider 端执行 Filter 链。
  8. 反射调用:通过反射找到对应的实现类和方法,传入参数执行业务逻辑。
  9. 返回结果:将结果序列化后原路返回给 Consumer。

关键点:整个过程中,Consumer 完全无感知,就像调用本地方法一样。这是 Dubbo 的核心设计理念——透明化远程调用。


参考文档