Fork me on GitHub

【坑】Dubbo重复的注册中心配置静默去重合并

背景信息:dubbo3.1.11

image

 

 

解决:

根因(有日志和源码双重证据)

  1. 15:21:46 真正的启动失败:
 
java.lang.IllegalStateException: Registry not found: zone_map_registry
  1. 但 Nacos 里 4 个注册中心其实都配了、也都解析成功了(15:21:23~24 四条 Refreshing RegistryConfig:base_data_registry、oc_registry、zone_map_registry、default_registry,地址全是 nacos://10.196.46.9:8848)。

  2. 可是 ConfigManager 里最终只剩 2 个(15:21:24.356 那次 "effective configurations" 只列了 base_data_registry 和 default_registry)——oc_registry、zone_map_registry 被丢掉了。

  3. 原因在 Dubbo 3.1.11 源码 AbstractConfigManager#addConfig:

java
 
// fast check duplicated equivalent config before write lock
if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) {
    for (AbstractConfig value : configsMap.values()) {
        if (value.equals(config)) {
            return (T) value;   // 视为重复,静默丢弃,无任何日志
        }
    }
}

而 AbstractConfig#equals() 遍历所有 getter 比较,唯独忽略 id。所以在 PRE 环境里,base_data_registry / oc_registry / zone_map_registry 三个配置字段完全一样(同地址、同 timeout=30000、同 parameters[namespace]=public、同 check=false)→ 只有第一个 base_data_registry 存活,另外两个被无声吞掉;default_registry 多了个 username=nacos,字段不同所以侥幸保留。

修复:让 4 个注册中心配置互不相同

改 PRE 环境 Nacos 的 rpc(yaml),给重复项加一个区分字段,用 timeout 最安全(不影响 nacos 服务发现的 group/namespace 语义):

yaml
 
dubbo:
  registries:
    default_registry:
      address: nacos://10.196.46.9:8848?username=app&password=1
      username: nacos
      parameters:
        namespace: public
    base_data_registry:
      address: nacos://10.196.46.9:8848?username=app&password=1
      timeout: 30000
      parameters:
        namespace: public
    zone_map_registry:
      address: nacos://10.196.46.9:8848?username=app&password=1
      timeout: 31000          # 与 base_data 区分,否则会被去重丢弃
      parameters:
        namespace: public
    oc_registry:
      address: nacos://10.196.46.9:8848?username=app&password=1
      timeout: 32000          # 与 base_data 区分
      parameters:
        namespace: public

注意:oc_registry 跟 base_data_registry 也是完全一样的,只改 zone_map_registry 的话,下一个报错就是 Registry not found: oc_registry,两个要一起改。同理 UAT 环境如果这几个注册中心也指向同一个 nacos 且参数一致,会踩同一个坑,一并检查。

 

 

 

147: public final <T extends AbstractConfig> T addConfig(AbstractConfig config) { 173: return (T) addIfAbsent(config, configsMap); 194: private <C extends AbstractConfig> C addIfAbsent(C config, Map<String, C> configsMap) 479: public <T extends AbstractConfig> List<T> loadConfigsOfTypeFromProps(Class<T> cls) { 506: this.addConfig(config); 532: this.addConfig(config); 575: this.addConfig(config); --- deployer --- 193: startConfigCenter(); 225: configManager.loadConfigs(); 228: private void startConfigCenter() { 231: configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class); 239: configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class); 321: configManager.loadConfigsOfTypeFromProps(RegistryConfig.class);
 

去重(合并)发生在 org.apache.dubbo.config.context.AbstractConfigManager。

  • 方法:AbstractConfigManager#addConfig(AbstractConfig)(dubbo-3.1.11-sources.jar,第 147 行起)
  • 判定依据:org.apache.dubbo.config.AbstractConfig#equals()(第 976 行)——遍历所有 getter 逐一比较,唯独跳过 getId()

关键代码(AbstractConfigManager.java:162-169):

java
 
// fast check duplicated equivalent config before write lock
if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) {
    for (AbstractConfig value : configsMap.values()) {
        if (value.equals(config)) {
            return (T) value;   // 命中即丢弃新配置,无任何日志
        }
    }
}

调用链(PRE 日志能一一对上):

code
 
DefaultApplicationDeployer#startConfigCenter()      (:228)
  → ConfigManager#loadConfigsOfTypeFromProps(RegistryConfig.class)  (:321)
    → AbstractConfigManager#loadConfigsOfTypeFromProps               (:479)
      → AbstractConfig#refresh()   ← 日志里 4 条 "Refreshing RegistryConfig[id=xxx]"
      → AbstractConfigManager#addConfig(config)                      (:506 → :147)
        → equals 命中 → 静默丢弃 oc_registry / zone_map_registry

补充两点:

  • 真正入库是 addIfAbsent(config, configsMap)(:194),按 id 作 key;但因为前面 equals 快检已经返回了旧对象,压根走不到这里。
  • 这个去重只排除 ReferenceConfigBase / ServiceConfigBase,RegistryConfig 不在豁免名单里,所以注册中心之间会互相吞并——只要两个 registry 除 id 外所有字段一致就会被合并成一个。
posted @ 2026-09-28 16:23  勇往无前的康康  阅读(6)  评论(0)    收藏  举报