Dubbo 3.x 新特性

📖 前置阅读:本文假设读者已掌握 Dubbo 的基本 RPC 开发、注册中心使用(Nacos)和 dubbo 协议。如果还不熟悉,建议先阅读 Dubbo 核心架构与 RPC 模型注册中心:Nacos 与 Zookeeper

一、⚡ 问题切入:dubbo 协议有什么不够用的?

第一篇说了 dubbo 协议的优点——TCP 长连接 + Hessian2 二进制序列化,性能极佳。但它的设计产生于 2011 年:

dubbo 协议的局限为什么是问题
私有二进制协议浏览器和 curl 调不了——非 HTTP,无法穿透通用 HTTP 网关
Java 中心协议体是 Java 特有的——Go/Node.js/Python 客户端需要单独实现协议栈
服务网格不友好Istio/Envoy 基于 HTTP/1.1 和 HTTP/2 做流量治理——私有协议无法被 Sidecar 理解
接口级服务发现注册中心存储的是接口粒度数据(org.example.OrderService:getOrderById)——微服务有几百个接口时,注册数据爆炸

Dubbo 3.x 的两大革新直接解决这些问题:

  1. Triple 协议——基于 HTTP/2 + Protobuf,解决私有协议问题
  2. 应用级服务发现——从接口粒度改为应用粒度,解决注册数据爆炸

二、Triple 协议 —— HTTP/2 能力 + RPC 性能

2.1 Triple 协议的本质

Triple 协议 = 将 gRPC 的传输协议(HTTP/2 + Protobuf)搬到 Dubbo 上,同时保留 Dubbo 的服务治理能力(注册中心、负载均衡、集群容错)。

dubbo 协议:    Dubbo RPC  → TCP 长连接 + Hessian2
Triple 协议:   Dubbo RPC  → HTTP/2 + Protobuf(兼容 JSON/Hessian2)
gRPC:          gRPC 调用  → HTTP/2 + Protobuf

Triple 约等于 Dubbo 的治理 + gRPC 的传输协议
flowchart TD
classDef startEnd fill:#701a4c,stroke:#e11d48,stroke-width:2px,color:#fce7f3,font-weight:bold;
classDef process fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#e5e7eb;
classDef data fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#bbf7d0,font-weight:bold;
classDef highlight fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#fecaca,font-weight:bold;

    BROWSER([浏览器]) -->|"HTTP/1.1\nJSON"| TRIPLE
    CURL([curl]) -->|"HTTP/1.1\nJSON"| TRIPLE
    JAVA([Java Consumer]) -->|"HTTP/2\nProtobuf"| TRIPLE
    GO([Go Consumer]) -->|"HTTP/2\nProtobuf"| TRIPLE

    TRIPLE["Triple 协议\nHTTP/2 多路复用"] --> PROVIDER[Provider]

    DUBBO_JAVA([Java Consumer\n老 dubbo 协议]) -->|"TCP + Hessian2"| DUBBO_PROVIDER[Provider\ndubbo 协议端口]

    class BROWSER,CURL,JAVA,GO,DUBBO_JAVA startEnd;
    class TRIPLE highlight;
    class PROVIDER,DUBBO_PROVIDER data;

2.2 Triple 协议的核心优势

特性dubbo 协议Triple 协议
传输层TCP 长连接(私有帧格式)HTTP/2(标准帧格式)
序列化Hessian2Protobuf(默认),兼容 Hessian2、JSON
浏览器/curl 访问✓——HTTP/2 向下兼容 HTTP/1.1
跨语言需要该语言的 Dubbo SDK任何支持 HTTP/2 + Protobuf 的语言
网关穿透需要专门的协议转换标准 Nginx/Envoy 直接代理
服务网格Sidecar 不理解私有协议Sidecar 天然理解 HTTP/2
多路复用单连接多请求(私有实现)HTTP/2 Stream(标准实现)
服务治理完整完整——继承 Dubbo 的所有治理能力

2.3 Triple 协议配置

# Provider——暴露 Triple 协议
dubbo:
  protocol:
    name: triple
    port: 30880
// Provider 实现——接口和逻辑完全不变
@DubboService
public class OrderServiceImpl implements OrderService {
    // 和 dubbo 协议时完全一样——不需要改一行代码
}
// Consumer——引用 Triple 协议的服务
@DubboReference
private OrderService orderService;
// 调用方代码也不变——Dubbo 自动识别协议

和 dubbo 协议的 API 完全兼容——接口定义、@DubboService@DubboReference 全部不变。唯一变化的是一行 yml 配置:dubbo.protocol.name: triple

2.4 用 curl 直接调用 Triple 服务

Triple 协议最直观的优势——可以用 curl 直接调

# 1. 启动 Provider——监听 Triple 协议 30880 端口
# 2. 确认 Provider 在运行

# 3. 用 curl 直接调用——无需 Java Consumer!
curl -X POST http://localhost:30880/org.example.api.OrderService/getOrderById \
  -H "Content-Type: application/json" \
  -d '{
    "orderId": 10001
  }'

# 返回:
# {"orderId":10001,"userId":2001,"productName":"iPhone 15","amount":6999.00}

这个能力意味着:

  • 测试:不需要写 Consumer 代码——curl + JSON 就能验证 Provider
  • 调试:浏览器 + Postman 直接发请求看返回
  • 跨语言:Go/Node.js 用标准 HTTP Client 就能调(JSON 模式),用 gRPC Client 调性能更好(Protobuf 模式)

2.5 Protobuf —— Triple 的高性能模式

上面的 curl 例子用的是 JSON 模式(方便调试)。生产环境推荐 Protobuf——体量更小、解析更快:

// order.proto
syntax = "proto3";

option java_package = "org.example.api";
option java_multiple_files = true;

message Order {
  int64 order_id = 1;
  int64 user_id = 2;
  string product_name = 3;
  string amount = 4;  // BigDecimal 用字符串传输
}

message GetOrderRequest {
  int64 order_id = 1;
}

service OrderService {
  rpc getOrderById(GetOrderRequest) returns (Order);
}
// Java 接口——基于 protobuf 生成的类
public interface OrderService {
    // 方法名和 proto 中的 rpc 方法名一致
    Order getOrderById(GetOrderRequest request);
}

// Provider 实现不变
// Consumer 调用不变
序列化模式适用场景curl 可调?
JSON调试、跨语言快速集成
Protobuf生产环境——最高性能需要用 grpcurl 等工具

2.6 同时暴露 dubbo 和 triple 两个端口

老系统迁移时——新 Consumer 用 Triple,老 Consumer 继续用 dubbo 协议:

dubbo:
  protocols:
    dubbo-legacy:
      id: dubbo
      name: dubbo
      port: 20880       # 老 Consumer 继续用这个端口
    triple-new:
      id: triple
      name: triple
      port: 30880       # 新 Consumer 迁移到这个端口

同一个 Provider 同时监听 20880 和 30880——两套协议、一个服务实现、零代码改动

三、应用级服务发现 —— 注册粒度从接口到应用

3.1 接口级服务发现的"注册爆炸"

Dubbo 2.x 的注册模型是接口级——每个接口方法作为独立条目注册到 Registry:

一个 Provider 应用有 20 个接口,每个接口有 5 个方法
  → 注册中心存了 100 条服务信息

100 个 Provider 实例(水平扩展)
  → 注册中心存了 10000 条服务信息

Consumer 订阅 10 个服务
  → 每次从注册中心拉取 100 × 10 = 1000 条地址信息

当微服务规模到几百个时,注册中心的数据量和推送频率成为瓶颈。

3.2 应用级服务发现的模型

Dubbo 3.x 引入应用级服务发现——注册粒度从"接口"变为"应用":

接口级(Dubbo 2.x):
  Registry 存储:providers:org.example.OrderService:getOrderById
                 providers:org.example.OrderService:createOrder
                 providers:org.example.UserService:getUserById
                 ...(每个接口方法一条)

应用级(Dubbo 3.x):
  Registry 存储:order-provider → [192.168.1.10:20880, 192.168.1.11:20880]
                 user-provider → [192.168.1.20:20880, 192.168.1.21:20880]
                 ...(每个应用一条)
  
  接口的详细信息(方法列表、参数类型等)存在<strong>元数据服务</strong>中
flowchart TD
classDef startEnd fill:#701a4c,stroke:#e11d48,stroke-width:2px,color:#fce7f3,font-weight:bold;
classDef process fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#e5e7eb;
classDef data fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#bbf7d0,font-weight:bold;
classDef highlight fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#fecaca,font-weight:bold;

    subgraph LEVEL2 [Dubbo 2.x 接口级注册]
        REG2[Registry] --- I1["org.example.OrderService:1.0.0\n├─ getOrderById\n├─ createOrder\n└─ cancelOrder"]
        REG2 --- I2["org.example.UserService:1.0.0\n├─ getUserById\n└─ updateUser"]
    end

    subgraph LEVEL3 [Dubbo 3.x 应用级注册]
        REG3[Registry] --- A1["order-provider\n→ [192.168.1.10:20880, ...]"]
        REG3 --- A2["user-provider\n→ [192.168.1.20:20880, ...]"]
        META[Metadata Service] --- M1["order-provider 的接口列表\n→ {OrderService, PaymentService}"]
        META --- M2["user-provider 的接口列表\n→ {UserService, AuthService}"]
    end

    class REG2,REG3 highlight;
    class I1,I2,A1,A2 data;
    class META process;
    class M1,M2 process;

3.3 注册数据量对比

场景:1 个订单系统有 5 个接口,每个接口 3 个方法,部署 100 个实例

接口级(Dubbo 2.x):
  Registry 数据量 = 100 实例 × 5 接口 × 3 方法 = 1500 条
  Consumer 每次拉取 = 100 实例 × 5 接口 = 500 条地址

应用级(Dubbo 3.x):
  Registry 数据量 = 100 条(每个实例一条)
  Consumer 每次拉取 = 100 条地址
  (接口方法信息通过元数据服务拿)

数据量减少 15 倍

3.4 配置应用级服务发现

dubbo:
  application:
    name: order-provider
    register-mode: instance    # instance = 应用级, interface = 接口级(默认兼容), all = 双注册
  registry:
    address: nacos://localhost:8848
register-mode行为使用场景
interface接口级注册(Dubbo 2.x 方式)兼容 Dubbo 2.x Consumer
instance应用级注册(Dubbo 3.x 新方式)全部 Consumer 都是 Dubbo 3.x
all(默认)双注册——同时注册接口级和应用级过渡期——Consumer 有 2.x 也有 3.x
# 过渡期推荐配置——双注册
dubbo:
  application:
    register-mode: all
  registry:
    address: nacos://localhost:8848
  metadata-report:
    address: nacos://localhost:8848   # 元数据服务也走 Nacos

⚠️ 新手提示:Dubbo 3.x 默认 register-mode: all——同时注册接口级和应用级。这意味着启动一个 Dubbo 3.x Provider,Nacos 里会看到两条注册信息(一条接口级、一条应用级)。全量迁移到 3.x 后可以切到 instance

四、Dubbo 3.x 其他值得关注的特性

特性含义什么时候用
云原生支持 Kubernetes 作为注册中心(不用 Nacos/ZK)在 K8s 上部署时——用 K8s Service 做服务发现
AOT 编译支持 Spring Native / GraalVM 编译为原生二进制需要快速启动和低内存占用的场景
Mesh 模式Dubbo 可以跑在 Istio Sidecar 后面——Sidecar 做流量管理公司已有 Service Mesh 基础设施
Reactive支持 Reactor / RxJava 响应式调用需要非阻塞 RPC——和高性能网关配合

五、Dubbo 2.x 迁移到 3.x 的检查清单

#检查项操作
1dubbo.version 从 2.7.x 升级到 3.3.x改 POM——3.x 向后兼容 2.7 的 API
2dubbo.protocol.name 固定为 dubbo 还是切 triple先保持 dubbo——协议不变就无风险。后续逐步开 triple
3register-mode 设为 all(默认)双注册——2.x Consumer 和 3.x Consumer 都能发现
4元数据服务配 metadata-report.address应用级服务发现需要元数据服务——通常指向同一个 Nacos
5序列化保持一致Hessian2 不变——2.x 和 3.x 的默认序列化器相同
6Consumer 先升级还是 Provider 先升级先升级 Provider 再升级 Consumer——因为 3.x Provider 同时做了接口级注册,2.x Consumer 不受影响
7验证——接口级和应用级两条注册信息都在 Nacos 中可见Nacos 控制台 → 服务列表 → 看到 providers:org.example.OrderService:::xxxorder-provider

🎯 总结

  1. Triple 协议 = Dubbo 治理 + gRPC 传输:基于 HTTP/2 + Protobuf,同时兼容 JSON(curl 可调)。用一行 yml 切换——接口和业务代码完全不变。同一服务可以同时暴露 dubbo 和 triple 两个端口——兼容老 Consumer。

  2. 应用级服务发现解决注册爆炸:注册粒度从"接口方法"改为"应用"——100 实例 × 5 接口 × 3 方法 = 1500 条减少到 100 条。接口方法信息存元数据服务——Consumer 在调用时才获取。

  3. 迁移策略:先开双注册,再切协议register-mode: all(兼容 2.x Consumer)→ Consumer 全量升 3.x → register-mode: instance(关闭接口级注册)。协议迁移独立:先保持 dubbo 协议 → 逐步切 triple。

  4. Triple 协议让 Dubbo 真正走出了 Java 生态:浏览器、curl、gRPC 客户端都能调用——这就是 HTTP/2 标准化的力量。

📖 下一步阅读:所有功能都玩明白了。最后一步——生产环境部署。多协议多注册中心怎么配?Dubbo Admin 看哪些指标?JVM 怎么调?继续阅读 生产环境部署与调优