Dubbo 的整体架构是怎样的?
结论先行:Dubbo 是“分层 + 插件化”的 RPC 与服务治理框架。纵向分十层,横向按角色分 Provider、Consumer、Registry、Monitor、Container 五部分;层与层之间用 URL 统一模型传递参数,每一层都能通过 SPI(Service Provider Interface)替换实现。
一、五个角色
| 角色 | 职责 | 是否必经 |
|---|---|---|
| Provider | 暴露服务、处理请求 | 是 |
| Consumer | 引用服务、发起调用 | 是 |
| Registry | 注册与订阅,推送实例列表 | 否,可直连 |
| Monitor | 统计调用量、耗时、失败率 | 否,异步上报 |
| Container | 承载服务运行的容器 | 是(启动依赖) |
调用链:Provider 启动 → 向 Registry 注册 → Consumer 订阅 → Registry 推送地址 → Consumer 本地缓存 → 直连 Provider 发起 RPC → Monitor 异步收集指标。
一个常见误解是“每次调用都要问注册中心”。实际上注册中心只在启动与地址变更时参与,正常调用是 Consumer 直连 Provider,所以注册中心抖动不会立刻打断业务。
二、十层结构
service 业务接口与实现,使用者能碰到的最上层
config 解析 XML / 注解 / YAML,折叠成 URL 模型
proxy 生成代理:Javassist 或 JDK 动态代理
registry 注册中心抽象:注册、订阅、通知
cluster 集群容错:目录、路由、负载均衡、重试
monitor 调用统计与上报
protocol RPC 协议:dubbo、triple、rest 等
exchange 请求响应语义:Request/Response 与 Future
transport 网络传输:Netty、Mina、Grizzly
serialize 序列化:Hessian2、Fastjson2、Protobuf 等
各层只依赖下层的抽象。换注册中心只动 registry 层,换序列化只动 serialize 层,业务代码零改动,这是分层最大的收益。
层间传递的“通用货币”是 URL:
dubbo://192.168.1.10:20880/com.demo.UserService
?interface=com.demo.UserService
&version=1.0.0&timeout=3000&serialization=hessian2
所有配置最终都折叠进这个字符串,因此日志里打印一条 URL 就能还原这次调用的全部参数。
三、最小组网配置
Provider 侧:
dubbo:
application:
name: user-provider
registry:
address: zookeeper://127.0.0.1:2181
protocol:
name: dubbo
port: 20880
@DubboService(version = "1.0.0")
public class UserServiceImpl implements UserService {
@Override
public User getById(Long id) {
return new User(id, "demo");
}
}
Consumer 侧只需 @DubboReference(version = "1.0.0") 注入接口,调用方法时框架完成代理、路由、负载均衡、序列化与网络收发。
常见追问
- 追问:十层粒度是不是太细?每层只承担一类变化,扩展点按层注册,排查问题也能按层定位日志:cluster 层看路由与重试,transport 层看连接与超时。
- 追问:Dubbo 与 Spring Cloud 的架构差异?Dubbo 是“RPC + 服务治理”,接口级强契约;Spring Cloud 是“HTTP + 组件生态”,协议通用,治理粒度偏应用。
- 追问:Dubbo 3 有什么架构变化?引入应用级服务发现(Application-level Service Discovery),注册数据从“接口 × 实例”降为“应用 × 实例”,注册中心容量压力下降一个数量级;同时提供 Triple 协议兼容 gRPC。
小结
- 纵向十层、横向五角色,是描述 Dubbo 架构的两条正交主线。
- 正常调用不经过注册中心,注册中心只负责名单与变更通知。
- URL 统一模型让配置可序列化、可传输、可回放。
- SPI 是分层可替换的底层支撑,也是所有扩展点的统一入口。