Skip to content

Dubbo 整体架构:Provider、Consumer、Registry、Monitor、Container

凌晨 2 点,你正准备上线新功能,突然监控大屏一片红——服务 A 调用服务 B 超时,报错 Connection reset

你打开注册中心一看:服务 B 的 10 个实例只剩 3 个在线。

这时候,Consumer 是怎么知道 Provider 的地址变化的?Monitor 是怎么统计调用数据的?Registry 又在中间扮演什么角色?

今天,我们来彻底搞清楚 Dubbo 的架构设计。

Dubbo 的分层架构

Dubbo 的架构设计非常精妙,它采用了分层架构,每一层都有明确的职责。我们先从整体看:

┌─────────────────────────────────────────────────────────┐
│                      Business 业务层                      │
│                  (用户接口、业务逻辑)                      │
└─────────────────────────────────────────────────────────┘

                           │ 调用

┌─────────────────────────────────────────────────────────┐
│                     RPC 层(远程过程调用)                  │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐     │
│  │ Config  │→ │ Proxy   │→ │ Registry│→ │ Cluster │     │
│  │ 配置层   │  │ 代理层   │  │ 注册层   │  │ 路由层   │     │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘     │
│                                                    │
│  ┌─────────┐  ┌─────────┐                           │
│  │ Monitor │← │ Exchange│                           │
│  │ 监控层   │  │ 交换层   │                           │
│  └─────────┘  └─────────┘                           │
└─────────────────────────────────────────────────────────┘

                           │ 数据交换

┌─────────────────────────────────────────────────────────┐
│                     Remoting 层(网络传输)                │
│      ┌─────────┐  ┌─────────┐  ┌─────────┐             │
│      │Transport│  │ Serialize│ │   IO   │             │
│      │ 传输层   │  │ 序列化层 │  │ 线程池  │             │
│      └─────────┘  └─────────┘  └─────────┘             │
└─────────────────────────────────────────────────────────┘

每一层都在解决特定的问题:

  • Config 配置层:以 ServiceConfigReferenceConfig 为中心,管理系统配置
  • Proxy 代理层:将 DemoService 的调用变成 Invoker,生成接口的动态代理
  • Registry 注册中心层:封装服务注册与发现的逻辑,支持 Zookeeper、Nacos、Redis 等
  • Cluster 路由层:封装多个 Provider 的伪装(Mock)和负载均衡
  • Monitor 监控层:统计服务调用次数、响应时间,生成监控报表
  • Exchange 信息交换层:封装请求-响应模式,同步转异步
  • Transport 网络传输层:抽象 Mina 和 Netty 为统一接口
  • Serialize 序列化层:将数据序列化成二进制流

五大核心角色

Dubbo 的架构由五大核心角色组成,它们各司其职,协同工作:

1. Provider(服务提供者)

Provider 是服务的真正实现者。它做的事情很纯粹:

  1. 暴露服务:将自己的接口信息注册到注册中心
  2. 处理请求:接收 Consumer 的调用,执行真正的业务逻辑
  3. 上报状态:向 Monitor 汇报自己的调用统计
java
// Provider 示例
@Service(version = "1.0.0")
public class UserServiceImpl implements UserService {
    @Override
    public User findById(Long id) {
        return userDao.findById(id);
    }
}

2. Consumer(服务消费者)

Consumer 是服务的调用方。它的职责是:

  1. 订阅服务:从注册中心订阅自己需要的服务
  2. 负载均衡:当有多个 Provider 时,选择一个来调用
  3. 容错处理:当调用失败时,按照配置进行处理
java
// Consumer 示例
@Reference(version = "1.0.0")
private UserService userService;

public User getUser(Long id) {
    return userService.findById(id);  // 像调用本地方法一样
}

3. Registry(注册中心)

Registry 是服务注册与发现的核心。它解决了 Consumer 如何知道 Provider 地址的问题:

  • 服务注册:Provider 启动时将自己的地址注册到 Registry
  • 服务订阅:Consumer 启动时从 Registry 订阅自己需要的服务
  • 变更通知:当 Provider 地址变化时,Registry 通知 Consumer

Dubbo 支持多种注册中心:

注册中心特点适用场景
ZookeeperCP 原则,高可靠大规模生产环境
NacosAP/CP 双模式,开箱即用Alibaba 技术栈
Redis高性能,内存型对性能要求极高的场景
Multicast组播模式小规模测试环境

4. Monitor(监控中心)

Monitor 负责统计和监控:

  • 调用统计:记录每个服务被调用的次数
  • 响应时间:统计每次调用的耗时
  • 服务排名:展示最繁忙、最慢的服务
java
// Monitor 的核心数据结构
public class InvocationStatistic {
    private String serviceName;      // 服务名
    private String methodName;        // 方法名
    private long totalCalls;          // 总调用次数
    private long successCalls;        // 成功次数
    private long failedCalls;        // 失败次数
    private long totalElapsed;       // 总耗时(毫秒)
    private long maxElapsed;         // 最大耗时
    private long minElapsed;         // 最小耗时
}

5. Container(服务容器)

Container 负责 Provider 的启动和停止:

  • Dubbo Spring 容器:默认使用 Spring 容器管理 Provider 的生命周期
  • 启动顺序:Container → Provider → Registry → Monitor
  • 优雅停机:收到停机信号后,先停止接收新请求,再关闭现有连接

调用流程:一次 Dubbo 调用的完整旅程

现在我们来看一次完整的 Dubbo 调用是怎么走的:

┌─────────┐    1.注册    ┌────────────┐    2.订阅    ┌─────────┐
│Provider │────────────→│  Registry  │←────────────│Consumer │
│         │             │(注册中心)   │ 订阅返回地址  │         │
└─────────┘             └────────────┘              └────┬────┘
       ↑                                              │
       │                                              │
       │                  3.调用                      │
       │              ←────────────────→              │
       │                   4.响应                      │
       │                                              │
       │    5.统计数据    ┌────────────┐              │
       └────────────────→│  Monitor   │              │
                        │ (监控中心)   │              │
                        └────────────┘              │

具体步骤:

  1. Provider 启动,将自己的接口和地址注册到 Registry
  2. Consumer 启动,从 Registry 订阅自己需要的服务,获取 Provider 地址列表
  3. Consumer 调用:Consumer 基于负载均衡选择某个 Provider,发起 RPC 调用
  4. Provider 处理:Provider 接收请求,执行真正的业务逻辑,返回结果
  5. Monitor 统计:双方都将调用数据上报给 Monitor

Dubbo vs Spring Cloud:两种微服务方案的哲学差异

很多人在选型时会纠结:Dubbo 和 Spring Cloud 到底选哪个?

我们先来看一张对比表:

对比维度DubboSpring Cloud
通信协议TCP(私有协议)HTTP(REST API)
序列化Hessian/Protobuf(高效二进制)JSON(人类可读)
性能高(序列化快,网络开销小)较低(JSON 解析开销大)
功能范围RPC 通信(功能专注)生态完整(200+ 组件)
服务治理内置(负载均衡、容错等)Netflix 组件(Feign、Hystrix)
学习曲线陡峭较平缓
社区活跃度Alibaba 背书VMware/Pivotal 背书

但这种对比忽略了一个根本问题:它们的定位不同。

Dubbo 本质上是一个高性能 RPC 框架,它专注于解决服务间的通信问题。它的设计哲学是「做好一件事,做到极致」。

Spring Cloud 本质上是一套微服务解决方案,它不只是 RPC,还包括配置中心、服务网关、链路追踪等一整套工具。设计哲学是「生态完整,开箱即用」。

所以选择的关键是:

  • 如果你追求极致性能,选 Dubbo
  • 如果你想要生态完整,选 Spring Cloud
  • 如果你两者都要,Dubbo 3.0+ 已经支持 HTTP/2 和 RESTful,可以和 Spring Cloud 生态无缝对接

为什么 Dubbo 的架构设计值得关注?

Dubbo 的架构设计体现了几个重要思想:

  1. 关注点分离:每一层只做自己的事,Proxy 不关心序列化,Transport 不关心路由
  2. 可扩展性:所有核心组件都基于 SPI 机制,可以灵活替换
  3. 面向接口编程:通过抽象接口,让具体实现可插拔

这些设计思想,在你自己设计系统时,同样值得借鉴。

面试追问方向

  • Dubbo 为什么选择 TCP 而不是 HTTP 进行通信?有什么优缺点?
  • 注册中心挂了,Consumer 还能调用 Provider 吗?Cached Registry 是什么?
  • Dubbo 的心跳检测机制是怎么实现的?为什么要设计心跳?
  • Dubbo 3.0 的 Triple 协议是什么?为什么要统一 HTTP/2?

总结

Dubbo 的五大角色各司其职:

  • Provider:服务的真正实现者
  • Consumer:服务的调用方
  • Registry:服务发现的中枢
  • Monitor:调用的统计者
  • Container:生命周期的管理者

理解了这个架构,你才能理解后续要讲的负载均衡、路由策略、集群容错是怎么工作的——它们都是在这个框架下各司其职的组件。

基于 VitePress 构建