Dubbo 架构与核心概念

候选人小李在面试美团 P6 时,简历上写着"精通 Dubbo,参与过服务治理"。

面试官翻到这一页,问了一句:"Dubbo 的架构分哪几层?Registry、Config、Cluster、Protocol 分别负责什么?"

小李愣了两秒,说:"好像有十几层,我也记不太清..."

【面试官心理】 Dubbo 的分层架构是理解整个框架的基础。一个"精通 Dubbo"的候选人如果说不清楚分层,说明他只是会用 API,从来没有研究过框架的内部设计。这种候选人我通常会继续追问到源码细节,看他是真的理解还是装的。

一、Dubbo 的整体架构 🔴

1.1 十五层架构全景图

Dubbo 采用分层架构设计,这种设计的好处是每一层都可以独立替换,而不影响其他层:

graph TD
    subgraph Client["客户端层"]
        A[Service 层<br/>业务接口]
    end

    subgraph Config["配置层"]
        B[Config 层<br/>@DubboReference<br/>@DubboService]
    end

    subgraph Proxy["代理层"]
        C[Proxy 层<br/>动态代理<br/>生成 Stub]
    end

    subgraph Registry["注册层"]
        D[Registry 层<br/>注册中心<br/>地址发现]
    end

    subgraph Cluster["集群层"]
        E[Cluster 层<br/>负载均衡<br/>容错路由]
    end

    subgraph Monitor["监控层"]
        F[Monitor 层<br/>监控统计<br/>链路追踪]
    end

    subgraph Protocol["协议层"]
        G[Protocol 层<br/>远程调用<br/>Invocation/Result]
    end

    subgraph Exchange["交换层"]
        H[Exchange 层<br/>Request/Response<br/>封装]
    end

    subgraph Transport["传输层"]
        I[Transport 层<br/>Netty/Mina<br/>NIO 网络]
    end

    subgraph Serialize["序列化层"]
        J[Serialize 层<br/>Kryo/Hessian<br/>数据编解码]
    end

    A --> B
    B --> C
    C --> D
    D --> E
    E --> G
    G --> H
    H --> I
    I --> J

每一层的核心职责

层级核心组件职责面试高频追问
config 配置层ReferenceConfig
ServiceBean
解析配置注解
生成配置对象
@DubboReference 怎么解析的
proxy 代理层JavassistProxyFactory
StubProxyFactory
生成客户端 Stub
生成服务端 Wrapper
动态代理用什么实现
registry 注册层RegistryFactory
ZookeeperRegistry
服务注册
服务发现
注册中心挂了怎么办
cluster 集群层Cluster
LoadBalance
容错路由
负载均衡
Cluster 挂了怎么容错
protocol 协议层DubboProtocol
HttpProtocol
远程调用封装
Invocation 构建
Dubbo 协议头多少字节
exchange 交换层HeaderExchange
ExchangeChannel
Request/Response 封装
状态管理
怎么实现同步转异步
transport 传输层NettyChannel
NIO Server
网络传输
编解码
Netty Pipeline 怎么设计
serialize 序列化层KryoSerialization
HessianSerialization
对象序列化
反序列化
为什么选 Kryo

1.2 ❌ 错误示范

候选人原话:"Dubbo 就是基于 Spring 的 RPC 框架,用起来跟 Feign 差不多。"

问题诊断

  • 完全不理解 Dubbo 的分层架构
  • 把 Dubbo 和 Spring Cloud 的组件混为一谈
  • 说明没有深入研究过 Dubbo 源码

面试官内心 OS:这个人简历上写"精通 Dubbo"简直是笑话,连基本架构都不清楚。

二、四大核心组件角色 🔴

2.1 Provider(服务提供者)

服务提供者在启动时向注册中心注册自己的服务:

// 服务发布
@DubboService(version = "1.0.0", group = "order-service")
public class OrderServiceImpl implements OrderService {
    @Override
    public Order putOrder(Order order) {
        // 业务逻辑
        return order;
    }
}

发布流程:

graph LR
    A[@DubboService 注解<br/>被 Spring 扫描] --> B[ServiceBean<br/>afterPropertiesSet]
    B --> C[DubboBootstrap.start]
    C --> D[ServiceConfig.export<br/>导出服务]
    D --> E[向 Registry 注册<br/>URL 信息]
    E --> F[启动 Netty Server<br/>监听端口]

关键问题:服务暴露在哪个时机发生?

答案是:Spring 容器刷新完成后ContextRefreshedEvent 事件)。具体来说,是 ServiceBean 实现了 ApplicationListener<ContextRefreshedEvent>,在 onApplicationEvent 中触发的。

2.2 Consumer(服务消费者)

消费者通过动态代理发起调用:

// 服务引用
@DubboReference(version = "1.0.0", group = "order-service")
private OrderService orderService;

// 实际调用的是这个
public Order putOrder(Order order) {
    // 1. Cluster 选择一个 Invoker
    // 2. Directory 获取所有 Invoker
    // 3. LoadBalance 负载均衡
    // 4. Protocol 执行远程调用
    return doInvoke(order);
}

2.3 Registry(注册中心)

注册中心是 Dubbo 架构的大脑,负责:

  • 服务注册(Provider 上线时注册)
  • 服务发现(Consumer 订阅获取 Provider 列表)
  • 变更通知(Provider 列表变化时推送给 Consumer)

Dubbo 支持多种注册中心:

注册中心CAP 模型适用场景运维复杂度
ZooKeeperCP(强一致)老项目、Kubernetes 环境
NacosAP + CP 双模式Spring Cloud Alibaba 生态
RedisAP临时用,不推荐生产
Multicast-本地开发-

2.4 Monitor(监控中心)

Monitor 负责收集调用统计信息:

graph TD
    A[Consumer 调用 Provider] --> B[Monitor 拦截<br/>收集调用数据]
    B --> C[定时聚合<br/>每分钟汇总]
    C --> D[写入数据库<br/>展示 Dashboard]
    D --> E[调用次数<br/>响应时间<br/>成功率]

2.5 Container(容器)

Container 不是 Docker 容器,而是 Dubbo 的依赖容器

  • Spring Container:Dubbo 默认依赖 Spring 容器
  • Jetty Container:轻量级容器
  • Logback Container:日志容器

三、Dubbo 版本演进:2.6 vs 2.7 vs 3.0 🟡

3.1 Dubbo 2.6 的局限性

Dubbo 2.6 是 2017 年发布的,有几个明显问题:

  1. 注册中心压力大:每个 Consumer 直接订阅所有 Provider,10 万实例的集群会有大量的通知风暴
  2. 元数据存储不合理:服务元数据(方法签名、参数类型)存在 URL 参数中,URL 长度限制导致大服务无法注册
  3. 治理能力弱:缺乏配置中心、元数据中心概念

3.2 Dubbo 2.7 的三大中心化组件

Dubbo 2.7 引入了三个中心化组件来解决上述问题:

graph TD
    A[Dubbo 2.7 新架构] --> B[注册中心<br/>服务注册与发现<br/>临时实例感知]
    A --> C[配置中心<br/>启动参数<br/>动态配置<br/>统一管理]
    A --> D[元数据中心<br/>服务元数据<br/>接口签名<br/>方法参数类型]

    B --> E[Registry]
    C --> F[Config Center]
    D --> G[Metadata Center]

配置中心:以前你需要在 XML 或 properties 文件里配置所有参数,现在统一放到 Nacos/Apollo 配置中心,支持动态修改。

元数据中心:服务的方法签名、参数类型不再塞在 URL 里,而是存到元数据中心。注册中心只存"服务 -> 实例列表"的映射。

3.3 Dubbo 3.0 的 ApplicationModel

Dubbo 3.0 是 2021 年发布的,核心目标是云原生化

graph TD
    A[Dubbo 3.0 ApplicationModel] --> B[应用级服务发现<br/>Consumer 直接拿到<br/>应用实例 IP:Port]
    A --> C[Triple 协议<br/>基于 HTTP/2<br/>兼容 gRPC 语义]
    A --> D[云原生适配<br/>Kubernetes 探针<br/>Service Mesh]

    subgraph Old["Dubbo 2.x"]
        E[接口级发现<br/>Consumer 拿到<br/>接口 -> 实例列表]
    end
    Old -.-> F[注册压力大<br/>URL 长度限制]

应用级服务发现是最大的变化。以前 Consumer 拿到的是 interface + method + version + group,Dubbo 3.0 拿到的是 appName + ip + port,直接省去了接口映射层。

💡

Dubbo 3.0 的应用级服务发现让注册中心压力降低了 90% 以上。原来 10 万个 Dubbo 实例需要注册 50 万条数据(每个实例有 5 个接口),现在只需要 10 万条。

3.4 版本选型建议

版本适用场景不适用场景
Dubbo 2.6维护老项目新项目、性能敏感场景
Dubbo 2.7Spring Cloud Alibaba 生态云原生、Kubernetes
Dubbo 3.0新项目、云原生需要大量老系统改造

【面试官心理】 能说清楚 Dubbo 版本演进路径的候选人,说明他有技术视野,能看到技术债务和演进方向。这种人在团队里是技术 leader 的苗子。

四、Dubbo 的扩展机制 🟢

4.1 SPI 机制

Dubbo 的核心扩展机制是基于 SPI(Service Provider Interface),这是 Dubbo 区别于 Spring 的关键设计:

// Dubbo SPI 用法:ExtensionLoader
ExtensionLoader<LoadBalance> loader =
    ExtensionLoader.getExtensionLoader(LoadBalance.class);

// 获取指定实现
LoadBalance random = loader.getExtension("random");

// 获取自适应实现(@Adaptive 标注的类)
LoadBalance adaptive = loader.getAdaptiveExtension();

Dubbo SPI vs JDK SPI

特性JDK SPIDubbo SPI
加载时机首次加载时全部实例化按需加载(lazy)
AOP 支持支持 Wrapper 包装
依赖注入支持
自适应扩展支持 @Adaptive
// JDK SPI:一次性加载所有实现
ServiceLoader<Log> loader = ServiceLoader.load(Log.class);
for (Log log : loader) {  // 全部实例化!
    log.info("loaded");
}

// Dubbo SPI:只加载需要的实现
ExtensionLoader<LoadBalance> loader =
    ExtensionLoader.getExtensionLoader(LoadBalance.class);
LoadBalance lb = loader.getExtension("random");  // 只实例化 random

4.2 常用扩展点

Dubbo 预留了大量扩展点:

扩展点接口默认实现作用
LoadBalanceRandomLoadBalance负载均衡
ClusterFailoverCluster集群容错
ProtocolDubboProtocol协议层
RegistryZookeeperRegistry注册中心
FilterEchoFilter拦截器链

五、生产避坑

5.1 常见翻车点

  1. 注册中心选错:选了 ZooKeeper 但运维能力不足,导致注册中心成了单点故障
  2. 版本号不一致:Provider 和 Consumer 的 version 不匹配,导致调用失败
  3. 超时配置连锁:A -> B -> C 调用链超时配置不合理,导致资源浪费
  4. 序列化不兼容:Provider 升级序列化方式后,Consumer 没升级,无法反序列化

5.2 排查方法

# 查看注册到 ZooKeeper 的服务
zkCli.sh -server 127.0.0.1:2181
ls /dubbo/com.xxx.OrderService/providers

# 查看 Dubbo 线程池状态
dubbo.admin -> 线程池监控

# 开启调试日志
<logger name="com.alibaba.dubbo" level="DEBUG"/>
⚠️

Dubbo 的线程池模型容易被忽略。默认用 FixedThreadPool,当线程池满时新请求会被拒绝。如果你的服务是高并发入口,记得改成CachedThreadPool或根据压测结果调整线程池参数。

【面试官心理】 Dubbo 架构是理解整个微服务生态的基础。能说清楚分层架构、版本演进、扩展机制的候选人,至少是 P6+。我通常会在这道题的基础上继续追问服务治理、流量管理相关的问题。