我说下我最终的方案:
首先,dubbo 获取 service provider hosts 信息时,调用了 InstanceController 里的 list 方法,而 nacos client sdk 在解析时,如果 hosts 为空,则会清空本地缓存数据,这个 问题虽然修复了,但需要 client 升级到 1.4.1,且需要 dubbo 配置 dubbo.registry.parameters.namingPushEmptyProtection=true,另外,nacos server 还会主动推送 空的 hosts 给 client,client 收到后,也会清空本地缓存,要解决 no provider 问题,就需要解决这两个问题,方案有两个:
1、修改 nacos 2.0.3 源码,使其不返回空 hosts,即 hosts 为空时不推送,若调用接口则返回 null,然后部署三个节点,数据库和旧版 nacos server 共享。
2、瞬间停掉 旧的 nacos 集群,此时 client 本地缓存还在,业务没影响;
3、修改 slb,由于 nacos 2.0.3 不会返回 空 hosts 也不会推送(因为我们改了源码),所以也没影响。
但该方案影响 心跳,会有一堆心跳失败,配置监听失败的报错。
还有一个方案:
1、同上,修改 nacos 2.0.3 源码,部署一套新集群,且数据库和旧版 nacos server 共享。
2、通过 jvm-sandbox 修改 旧版 nacos 的逻辑(运行时 aop 技术,不需要重启 nacos 集群)使其不推送,且 如果InstanceController.doSrvIpxt 返回 空 hosts,则返回 null 然后加载 jvm-sandbox 以及写的模块
3、修改 slb
这两个方案都会影响服务发布,如果不想影响服务发布,则需要 nacos 2.0.3 具有从 nacos 1.3.2 同步服务 hosts 的能力,也很简单,不过影响发布问题也不大。
我已通过方案二 升级了我们的集群,接近 3000个 dubbo 服务,接近 300 个微服务。沙箱模块代码可以如下:
@MetaInfServices(Module.class)
@Information(id = "nacosUpdater")
public class NacosUpdater implements Module {
@Resource
private ModuleEventWatcher moduleEventWatcher;
@Command("cacheIp")
public void cacheIps() {
new EventWatchBuilder(moduleEventWatcher)
.onClass("com.alibaba.nacos.naming.controllers.InstanceController")
.onBehavior("doSrvIpxt")
.onWatch(new AdviceListener() {
@Override
protected void afterReturning(Advice advice) throws Throwable {
Object object = advice.getReturnObj();
if (!(object instanceof ObjectNode)) {
System.out.println("this is a bug return not ObjectNode");
return;
}
ObjectNode objectNode = (ObjectNode) object;
JsonNode jsonNode = objectNode.get("hosts");
if (!(jsonNode instanceof ArrayNode)) {
System.out.println("this is a bug return not ArrayNode");
return;
}
ArrayNode arrayNode = (ArrayNode) jsonNode;
if (!arrayNode.isEmpty()) {
return;
}
ProcessController.returnImmediately(null);
}
});
new EventWatchBuilder(moduleEventWatcher)
.onClass("com.alibaba.nacos.naming.push.PushService")
.onBehavior("onApplicationEvent")
.onWatch(new AdviceListener() {
@Override
protected void before(Advice advice) throws Throwable {
ProcessController.returnImmediately(null);
}
});
new EventWatchBuilder(moduleEventWatcher)
.onClass("com.alibaba.nacos.naming.push.PushService")
.onBehavior("udpPush")
.onWatch(new AdviceListener() {
@Override
protected void before(Advice advice) throws Throwable {
ProcessController.returnImmediately(null);
}
});
}
}
最后补充一句,修改后的 nacos 2.0.3 即使三个节点都宕机也不影响已有业务(但影响服务发布)这个 issue 关闭。