Skip to content

Dubbo 专栏 ​

Dubbo 是 Java 生态里非常典型的高性能 RPC 框架。它解决的核心问题不是“怎么发 HTTP 请求”,而是:服务拆成多个进程以后,调用方怎样像调用本地接口一样调用远程服务,同时还能做到注册发现、负载均衡、超时、重试、容错、治理、监控和扩展。

学习 Dubbo 不能只背 @DubboService、@DubboReference。真正要理解的是:

  1. 为什么微服务需要 RPC。
  2. 一次 Dubbo 调用从代理对象到网络传输再到服务端反射执行经历了什么。
  3. 注册中心在 Dubbo 里保存什么,不负责什么。
  4. 协议、序列化、连接、线程池、负载均衡、集群容错分别解决什么问题。
  5. Dubbo SPI 为什么是核心扩展机制。
  6. 商业项目中哪些场景适合 Dubbo,哪些场景更适合 HTTP、MQ 或事件驱动。

学习目标 ​

学完本专栏后,你应该能做到:

能力具体要求
会用能写 provider、consumer、接口包和注册中心配置
懂链路能画出一次远程调用的完整流程
懂原理能解释代理、Invoker、Directory、Router、LoadBalance、Cluster、Protocol、Codec、Transport
会治理能配置超时、重试、负载均衡、灰度、版本、分组、降级
会排查能定位注册失败、找不到服务、超时、线程池打满、序列化失败、重复调用
会面试能用标准回答讲清 Dubbo 和 Spring Cloud OpenFeign 的区别

本专栏学习路径 ​

阶段文档学习重点
入门RPC 与 Dubbo 总览先理解 Dubbo 解决什么问题
核心调用链路与核心架构掌握代理、Invoker、Filter、Protocol、Exchange、Transport
注册注册发现、Directory刷新与故障恢复理解接口级/应用级发现、注册订阅、元数据、地址对账和Session窗口
协议协议、序列化与线程模型理解 Dubbo 协议、Hessian2、连接复用、线程池
治理路由、负载均衡、Cluster与重试预算理解逻辑调用与物理尝试、算法、超时预算、灰度和Provider保护
扩展Dubbo SPI 与扩展点理解 Dubbo 为什么能高度可插拔
面试Dubbo 面试题标准回答、追问点、项目话术和跳转

为什么需要 RPC ​

单体应用里,订单模块调用库存模块通常就是一个普通方法:

java
stockService.deduct(skuId, count);

拆成微服务后,订单服务和库存服务可能在不同机器、不同 JVM 进程中。此时本地方法调用不再成立,必须通过网络调用:

mermaid
flowchart TD
    A["订单服务进程"] --> B["网络"]
    B --> C["库存服务进程"]
    C --> D["库存数据库"]

如果每个服务都手写 Socket、序列化、超时、连接池、负载均衡、重试、服务发现,业务代码会非常混乱。RPC 框架的价值,就是把这些通用能力封装起来,让业务开发面向接口编程。

RPC 和 HTTP 调用有什么区别 ​

RPC 不是一定比 HTTP 高级,它们解决的问题有重叠,也有差异。

对比项Dubbo RPCSpring Cloud OpenFeign HTTP
调用体验像本地 Java 接口调用像声明式 HTTP 客户端
协议Dubbo 协议、Triple、REST 等HTTP/1.1、HTTP/2
序列化Hessian2、Fastjson2、Protobuf 等JSON 最常见
性能二进制协议通常更轻JSON 可读性强但体积较大
契约Java 接口契约强HTTP API 契约更开放
跨语言传统 Dubbo Java 生态强,Triple 更利于跨语言跨语言天然友好
治理服务治理能力非常丰富依赖 Spring Cloud 组件组合
适合场景Java 内部服务、高性能强契约调用开放 API、前后端、跨语言、云原生 HTTP 主线

商业项目里常见组合是:外部入口用 HTTP/Gateway,内部核心 Java 服务之间用 Dubbo;跨系统异步解耦用 MQ。

一次 Dubbo 调用的简化流程 ​

mermaid
flowchart TD
    A["Consumer 注入接口代理"] --> B["调用接口方法"]
    B --> C["代理转换成 Invocation"]
    C --> D["从注册中心获取 Provider 地址"]
    D --> E["路由过滤不可用实例"]
    E --> F["负载均衡选择一个实例"]
    F --> G["编码和序列化请求"]
    G --> H["Netty 发送网络请求"]
    H --> I["Provider 解码请求"]
    I --> J["Filter 链处理"]
    J --> K["反射调用真实服务方法"]
    K --> L["序列化响应返回 Consumer"]

这张图说明两件事:

  1. Dubbo 的“像本地调用”只是编程体验,底层仍然是网络调用。
  2. 网络调用一定会出现超时、失败、重复、半成功,所以业务仍然要设计幂等、超时、降级和补偿。

最小 Demo:订单服务调用库存服务 ​

项目通常拆成三个模块:

模块作用
stock-api放公共接口和 DTO,provider 与 consumer 都依赖
stock-provider实现库存服务并暴露 Dubbo 服务
order-consumer引用库存服务并发起远程调用

公共接口 ​

java
package com.example.stock.api;

public interface StockService {
    boolean deduct(String skuId, int count);
}

Provider 实现 ​

java
package com.example.stock.provider;

import com.example.stock.api.StockService;
import org.apache.dubbo.config.annotation.DubboService;

@DubboService(version = "1.0.0", group = "trade")
public class StockServiceImpl implements StockService {

    @Override
    public boolean deduct(String skuId, int count) {
        if (count <= 0) {
            throw new IllegalArgumentException("count must be positive");
        }
        System.out.println("扣减库存 skuId=" + skuId + ", count=" + count);
        return true;
    }
}

Provider 配置 ​

yaml
server:
  port: 8081

dubbo:
  application:
    name: stock-provider
  protocol:
    name: dubbo
    port: 20880
  registry:
    address: zookeeper://127.0.0.1:2181
  scan:
    base-packages: com.example.stock.provider

Consumer 引用 ​

java
package com.example.order;

import com.example.stock.api.StockService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    @DubboReference(
            version = "1.0.0",
            group = "trade",
            timeout = 2000,
            retries = 0,
            loadbalance = "roundrobin"
    )
    private StockService stockService;

    @PostMapping("/orders")
    public String createOrder(@RequestParam String skuId, @RequestParam int count) {
        boolean success = stockService.deduct(skuId, count);
        return success ? "order created" : "stock not enough";
    }
}

Consumer 配置 ​

yaml
server:
  port: 8082

dubbo:
  application:
    name: order-consumer
  registry:
    address: zookeeper://127.0.0.1:2181

这个 demo 里最重要的不是注解,而是配置背后的含义:

配置含义不配置或配错会怎样
registry.address注册中心地址provider 注册不上,consumer 找不到服务
protocol.portprovider 暴露 RPC 端口端口冲突或防火墙不通会调用失败
version服务版本多版本共存时避免调用错实现
group服务分组多业务线或多环境隔离
timeout远程调用超时不设置可能长时间阻塞调用线程
retries失败重试次数写接口重试可能造成重复扣减

商业常用场景 ​

场景Dubbo 适合点必须注意
订单调用库存Java 内部服务强契约调用扣库存接口要幂等,写操作慎用重试
资产平台调用字典服务低延迟、接口稳定字典可缓存,避免每次远程调用
医疗采集服务调用规则服务接口治理、版本控制规则版本要隔离,灰度发布
权限服务被多个系统调用公共能力复用权限结果缓存和降级策略
批处理调用基础服务高吞吐内部调用控制并发,避免打满 provider 线程池

初学者必须建立的正确认知 ​

误区为什么不对正确理解
Dubbo 调用就是本地调用底层经过网络,可能失败和超时编程像本地,运行时是远程
有注册中心就不会调用失败注册中心只管地址发现调用还受网络、线程池、序列化、超时影响
重试越多越可靠写接口重复执行会造成脏数据查询可重试,写接口优先幂等和补偿
Dubbo 一定比 HTTP 好场景不同内部 Java 强契约适合 Dubbo,开放和跨语言适合 HTTP
Provider 机器多就一定稳定慢实例也会拖垮调用方需要超时、熔断、限流、隔离和监控

和其他知识点的关系 ​

面试标准回答 ​

Dubbo 是 Java 生态常用的高性能 RPC 框架。它通过接口代理屏蔽远程调用细节,Consumer 调用接口时会把方法、参数、附件等封装成 Invocation,再经过集群容错、路由、负载均衡选择 Provider,之后通过协议编码、序列化和网络通信发送到服务端。Provider 解码后经过 Filter 链,最终调用真实服务实现并返回结果。Dubbo 还提供注册发现、版本分组、超时重试、负载均衡、熔断降级、SPI 扩展等服务治理能力。

追问时要补一句:Dubbo 的本地调用体验不代表它是本地调用,底层仍然是不可靠网络,所以生产上必须设置超时、控制重试、设计幂等、做监控告警和降级。

本章小结 ​

Dubbo 的核心不是几个注解,而是一套完整的 RPC 调用和服务治理体系。学 Dubbo 要从远程调用的不可靠性出发,理解代理、注册发现、路由、负载均衡、协议、序列化、线程模型、容错和扩展点。只有这样,线上遇到“找不到服务、调用超时、重复扣减、线程池打满、序列化失败”时,才知道该从哪条链路排查。