Dubbo 注册中心

📖 前置阅读:本文假设读者已掌握 Dubbo 的基本 RPC 开发和集群容错配置。如果还不熟悉,建议先阅读 SpringBoot Dubbo 全操作指南集群容错与负载均衡

一、⚡ 问题切入:Registry 到底是什么?

前面三篇反复提到"注册中心"——Provider 向它注册,Consumer 从它订阅。但注册中心不只是一个"存地址的地方":

注册中心的职责具体行为
服务注册Provider 启动时把"IP:Port + 接口名 + 元数据"写入 Registry
服务发现Consumer 启动时从 Registry 拉取"接口名 → 地址列表"的映射
健康检查检测 Provider 是否存活——不存活就剔除
变更推送Provider 地址列表变化时,主动通知 Consumer
配置管理(Nacos)动态下发配置——不需要重启应用

关键点:Registry 只在服务发现阶段起作用。Consumer 拿到 Provider 地址后——直连调用,不经过 Registry。这是和 MQ 的 Broker 最本质的区别。

二、服务注册与发现的全链路

2.1 详细流程

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 REGISTER [注册阶段]
        P1[Provider 启动] --> P2["向 Nacos 注册\nServiceName: order-provider\nIP: 192.168.1.10\nPort: 20880\nInterface: org.example.OrderService\nMethods: getOrderById, createOrder..."]
    end

    subgraph DISCOVER [发现阶段]
        C1[Consumer 启动] --> C2["向 Nacos 订阅\nInterface: org.example.OrderService"]
        C2 --> C3["Nacos 返回\n[192.168.1.10:20880\n 192.168.1.11:20880\n 192.168.1.12:20880]"]
        C3 --> C4[Consumer 存到本地缓存]
        C4 --> C5["选一个 Provider\n建立 TCP 长连接"]
    end

    subgraph HEARTBEAT [心跳阶段]
        P2 --> H1["Provider 每 5s\n向 Nacos 发心跳"]
        H1 --> H2{Nacos 15s\n没收到心跳?}
        H2 -- "是" --> H3["标记为不健康\n30s 后剔除"]
        H3 --> H4["推送变更通知\n给所有订阅的 Consumer"]
        H4 --> C6[Consumer 更新\n本地地址缓存]
    end

    class P1,C1,C5 startEnd;
    class P2,C2,C3,C4,C6,H1,H3,H4 process;
    class H2 highlight;

2.2 注册中心的存储结构

以 Nacos 为例,注册的数据长这样:

Namespace: public (默认)
  └── Group: DEFAULT_GROUP
       └── Service: providers:org.example.OrderService:::
              ├── Instance: 192.168.1.10:20880
              │    ├── metadata: {dubbo.metadata.revision=xxx, ...}
              │    ├── weight: 100
              │    ├── healthy: true
              │    └── enabled: true
              ├── Instance: 192.168.1.11:20880
              └── Instance: 192.168.1.12:20880

这里的层级关系

层级含义Dubbo 中的应用
Namespace租户隔离——不同环境用不同 Namespacedev / test / prod
Group同环境内的进一步分组DEFAULT_GROUP(Dubbo 默认)
Service服务名——包含接口名 + 版本 + 分组providers:org.example.OrderService:::1.0.0
Instance具体的 Provider 实例IP + Port + 元数据

2.3 本地地址缓存 —— Registry 宕机的底气

Consumer 拿到 Provider 地址列表后——缓存到本地内存 + 磁盘文件

缓存的存储位置(默认):
  ~/.dubbo/dubbo-registry-{applicationName}-{registryAddress}.cache

文件内容示例:
  org.example.OrderService=192.168.1.10:20880,192.168.1.11:20880

Registry 宕机时:
  Consumer 用缓存文件中的地址继续调用——不受影响
  只有新 Provider 上线 / 老 Provider 下线时才感知不到

这就是 Dubbo 说"Registry 挂了不影响调用"的原因——本地缓存兜底

# 缓存文件路径可以自定义
dubbo:
  registry:
    address: nacos://localhost:8848
    file: /data/dubbo/cache/registry-cache

三、Nacos vs Zookeeper 选型

3.1 本质区别

维度NacosZookeeper
定位注册中心 + 配置中心——一体化分布式协调服务——CP 强一致性
CAPAP(优先可用性)——可选择 CPCP(优先一致性)——不可动摇
一致性协议Distro(AP 模式)+ Raft(CP 模式)ZAB(类似 Raft)
健康检查客户端心跳 + 服务端主动探测(TCP/HTTP/MySQL)客户端 TCP 长连接——断开即剔除
配置管理原生支持——实时推送不支持——需要额外组件
多数据中心原生支持不原生支持
运维复杂度低——单机即可(开发环境)中——至少 3 台才能用(奇数个)
Dubbo 3.x 推荐✅ 首选✅ 兼容——存量迁移

3.2 Nacos 的 AP vs CP 模式

# AP 模式(默认)——优先可用性
# 网络分区时:各分区的 Nacos 节点独立工作——可能出现短暂不一致
# 适用场景:一般微服务——容忍几秒的注册信息不一致
dubbo:
  registry:
    address: nacos://localhost:8848

# CP 模式——优先一致性
# 网络分区时:只有 Leader 能写——牺牲可用性保证一致
# 适用场景:支付、金融——不能有"某个节点看到的地址列表和别的节点不一样"
dubbo:
  registry:
    address: nacos://localhost:8848?nacos.cp=true

3.3 Zookeeper 在 Dubbo 中的使用

# Zookeeper 作为注册中心
dubbo:
  registry:
    address: zookeeper://192.168.1.10:2181?backup=192.168.1.11:2181,192.168.1.12:2181

Zookeeper 的存储结构:

/dubbo
  └── /org.example.OrderService
       └── /providers
            ├── /dubbo%3A%2F%2F192.168.1.10%3A20880...  (临时节点)
            ├── /dubbo%3A%2F%2F192.168.1.11%3A20880...
            └── /dubbo%3A%2F%2F192.168.1.12%3A20880...
       └── /consumers
            ├── /consumer%3A%2F%2F192.168.1.20...
            └── /consumer%3A%2F%2F192.168.1.21...

ZK 使用临时节点做健康检查——Provider 和 ZK 之间是一个 TCP 长连接。连接断开 → 临时节点自动删除 → Consumer 收到变更通知 → 从地址列表中移除。

3.4 选型建议

Nacos(推荐):
  - Dubbo 3.x 的默认和推荐注册中心
  - 同时需要注册中心 + 配置中心 → Nacos 一个搞定
  - AP 模式满足大多数微服务场景

Zookeeper(兼容):
  - 公司已有 ZK 集群——不想多运维一套系统
  - 需要强一致性(CP 模式)
  - Dubbo 2.x 的老项目——ZK 是默认注册中心

四、配置中心 —— Nacos 的第二个身份

4.1 为什么需要配置中心

微服务有几十个实例——改一个超时时间,逐个改 yml 然后重启?Nacos 配置中心解决这个问题:

# 把 timeout 从 yml 移到 Nacos 配置中心
# Nacos 中发布配置变更 → 所有 Dubbo 实例实时生效 → 不需要重启

4.2 SpringBoot 集成 Nacos 配置中心

<!-- 额外依赖——Nacos 配置中心 -->
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-spring-context</artifactId>
    <version>2.3.0</version>
</dependency>
# application.yml——保持连接信息等不变配置
dubbo:
  application:
    name: order-provider
  registry:
    address: nacos://localhost:8848
  protocol:
    name: dubbo
    port: 20880

# Nacos 配置中心连接信息
nacos:
  config:
    server-addr: localhost:8848
    namespace: dev              # 命名空间——隔离不同环境
    group: DEFAULT_GROUP
    data-id: dubbo-order-provider-config  # 配置文件的 dataId

在 Nacos 控制台创建配置(http://localhost:8848/nacos):

  • Data ID: dubbo-order-provider-config
  • Group: DEFAULT_GROUP
  • 配置内容:
# Nacos 中的动态配置
dubbo:
  provider:
    timeout: 5000           # RPC 调用超时——5s
    retries: 1              # 重试 1 次
    loadbalance: leastactive  # 负载均衡策略
    actives: 200            # 最大并发调用数

修改 Nacos 中的 timeout: 3000 → 所有 Provider 实例实时生效 → Consumer 下次调用就在 3 秒内超时。

4.3 什么配置放 Nacos、什么配置留 yml

放 Nacos(动态)留 yml(静态)
超时时间 timeout注册中心地址 registry.address
重试次数 retries协议端口 protocol.port
负载均衡策略 loadbalance应用名称 application.name
并发限制 actives序列化方式 serialization
线程池大小协议名称 protocol.name
限流阈值Nacos 连接信息

原则:运行时可能需要调整的值放 Nacos,连接基础设施的值留 yml。

五、多注册中心

5.1 什么时候需要多注册中心

场景示例
双活部署两个数据中心各有一个 Nacos 集群——注册到离自己最近的
注册中心迁移从 Zookeeper 迁移到 Nacos——过渡期双注册
跨环境调用Consumer 在 dev 环境,需要同时调 devtest 的 Provider
消费者跨注册中心订单服务需要调商品服务(Nacos A)和支付服务(Nacos B)

5.2 双注册中心配置

dubbo:
  registries:
    beijing:
      address: nacos://nacos-bj.internal:8848
      default: true           # 默认注册中心——Provider 向这里注册
    shanghai:
      address: nacos://nacos-sh.internal:8848
// Provider——同时注册到两个注册中心
@DubboService(registry = {"beijing", "shanghai"})
public class OrderServiceImpl implements OrderService { ... }

// Consumer——只从北京注册中心订阅(优先同机房)
@DubboReference(registry = "beijing")
private OrderService orderService;

// Consumer——从上海注册中心订阅另一个服务
@DubboReference(registry = "shanghai")
private PaymentService paymentService;

5.3 从 Zookeeper 迁移到 Nacos 的过渡方案

# 过渡期——Consumer 同时订阅两个注册中心
dubbo:
  registries:
    zk-legacy:
      address: zookeeper://zk.internal:2181
    nacos-new:
      address: nacos://nacos.internal:8848
      default: true
// Provider 从 ZK → Nacos 迁移过程:
// 第一阶段:老 Provider 只注册到 ZK,新 Provider 只注册到 Nacos
// 第二阶段:Consumer 同时订阅 ZK 和 Nacos——合并两个地址列表
// 第三阶段:Consumer 切到只订阅 Nacos → 老 Provider 下线
@DubboReference(registry = {"zk-legacy", "nacos-new"})
private OrderService orderService;

六、常见故障与排查

故障现象排查
Consumer 报 No provider available启动时报错(check=true)或调用时报错(check=false① Nacos 服务列表中 Provider 是否存在 ② Provider 是否和 Consumer 在同一个 Namespace ③ versiongroup 是否匹配
Provider 已注册但 Consumer 列表里没有Nacos 里看得到 Provider,但 Consumer 调不到① 检查 dubbo.registry.address 是否和 Nacos 控制台中看到的地址一致 ② Consumer 缓存没刷新——删掉 ~/.dubbo/ 下的缓存文件
注册中心宕机后 Consumer 报错本来正常,Nacos 宕机后就调不通Consumer 的本地缓存文件被清理了——删掉后重启时 Registry 不可用就无法发现服务。保留缓存文件
Provider 频繁上下线Nacos 服务列表里 Provider 反复出现/消失① Provider 的心跳是否稳定——检查网络 ② nacos.naming.clean.empty-service.interval 是否太短 ③ GC 停顿超 15s 导致心跳丢失
Nacos 1.x 升级到 2.x 后 Dubbo 连不上Dubbo 3.x + Nacos 2.x 需要 gRPC 端口Nacos 2.x 新增了 gRPC 端口(默认偏移 1000,即 9848)——Dubbo 需要这个端口。确认 -p 9848:9848 已映射

🎯 总结

  1. Registry 是"黄页",不是"中转站":Provider 注册、Consumer 发现——之后直连调用。Registry 宕机不影响已有连接的调用(本地缓存兜底),只影响新服务的发现和变更通知。

  2. Nacos 是 Dubbo 3.x 的首选:同时做注册中心 + 配置中心——一个组件替代 Zookeeper + Apollo/Spring Cloud Config。AP 模式默认满足大多数场景,CP 模式可选。

  3. 配置中心让参数动态生效timeoutretriesloadbalance 等运维参数放在 Nacos 控制台——修改后实时生效,不需要重启应用。但连接性参数(端口、注册中心地址)留在 yml。

  4. 多注册中心用于过渡和双活:同时注册到多个注册中心——支持从 ZK 迁移到 Nacos、跨数据中心双活、跨环境调用。

📖 下一步阅读:注册中心的底层搞清楚了。接下来是 Dubbo 3.x 的两大革新——Triple 协议(HTTP/2 + Protobuf)和应用级服务发现。继续阅读 Dubbo 3.x 新特性