用nacos下使用dubbo会连接旧的服务ip情况

问题

nacos服务器所在IP进行了更换,dubbo consumers启动依然请求旧的providers服务地址。

  • 首先排除dubbo缓存,找到文件夹:$用户名$/.dubbo 删除文件夹下文件。问题依然重现。

  • 删除nacos注册缓存,找到文件夹: $用户名$/nacos 删除文件夹下所有文件,问题解决。

思考

dubbo缓存

  • 根据官方图,dubbo调用者需要通过注册中心(例如:ZK、nacos)注册信息,获取提供者,但是如果频繁往ZK获取信息,肯定会存在单点故障问题,所以dubbo提供了将提供者信息缓存在本地的方法。
  • Dubbo在订阅注册中心的回调处理逻辑当中会保存服务提供者信息到本地缓存文件当中(同步/异步两种方式),以url纬度进行全量保存。
  • Dubbo在服务引用过程中会创建registry对象并加载本地缓存文件,会优先订阅注册中心,订阅注册中心失败后会访问本地缓存文件内容获取服务提供信息。

nacos缓存

查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void init() {
executorService.scheduleWithFixedDelay(new SwitchRefresher(), 0L, 5000L, TimeUnit.MILLISECONDS);
executorService.scheduleWithFixedDelay(new DiskFileWriter(), 30, DAY_PERIOD_MINUTES, TimeUnit.MINUTES);
// backup file on startup if failover directory is empty.
executorService.schedule(new Runnable() {
@Override
public void run() {
try {
File cacheDir = new File(failoverDir);

if (!cacheDir.exists() && !cacheDir.mkdirs()) {
throw new IllegalStateException("failed to create cache dir: " + failoverDir);
}

File[] files = cacheDir.listFiles();
if (files == null || files.length <= 0) {
new DiskFileWriter().run();
}
} catch (Throwable e) {
LogUtils.LOG.error("NA", "failed to backup file on startup.", e);
}

}
}, 10000L, TimeUnit.MILLISECONDS);}

创建定时器,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class SwitchRefresher implements Runnable {
long lastModifiedMillis = 0L;
@Override
public void run() {
try {
File switchFile = new File(failoverDir + UtilAndComs.FAILOVER_SWITCH);
if (!switchFile.exists()) {
switchParams.put("failover-mode", "false");
LogUtils.LOG.debug("failover switch is not found, " + switchFile.getName());
return;
}
long modified = switchFile.lastModified();
if (lastModifiedMillis < modified) {
lastModifiedMillis = modified;
String failover = ConcurrentDiskUtil.getFileContent(failoverDir + UtilAndComs.FAILOVER_SWITCH, Charset.defaultCharset().toString());
if (!StringUtils.isEmpty(failover)) {
List<String> lines = Arrays.asList(failover.split(DiskCache.getLineSeperator()));
for (String line : lines) {
String line1 = line.trim();
if ("1".equals(line1)) {
switchParams.put("failover-mode", "true");
LogUtils.LOG.info("failover-mode is on");
new FailoverFileReader().run();
} else if ("0".equals(line1)) {
switchParams.put("failover-mode", "false");
LogUtils.LOG.info("failover-mode is off");
}
}
} else {
switchParams.put("failover-mode", "false");
}
}
} catch (Throwable e) {
LogUtils.LOG.error("NA", "failed to read failover switch.", e);
}
}}

首先判定下容灾开关是否有,容灾开关是一个磁盘文件的形式存在,通过容灾开关文件名字,判定容灾开关是否打开,1表示打开,0为关闭,读取到容灾开关后,将值更新到内存中,后续解析地址列表时,首先会判定一下容灾开关是否打开,如果打开了,就读缓存的数据,否则从服务端获取最新数据。

猜测是容灾开关打开状态,所以一直取的缓存的数据。