【前车之鉴】通用解决Nacos Open API手动上下线不生效,创建实例后先被设置不健康而后被自动剔除集群,以及控制台无法删除实例Instance 超详细解决方案

文章目录

    • 问题再现
    • 前提认知
    • 解决方案
      • 1. 控制台
      • 2. REST API
        • 服务注册
        • 服务下线
      • 3. SDK
        • 服务注册
        • 服务下线

问题再现

最近在搞公司的技术组件,提供一种灵活的流量灰度方式【敬请期待后续开源项目,我们完全基于Nacos自研,在开发过程中发现诸多问题:

  1. 通过REST API 创建好实例后15秒先被设置不健康然后自动被清除

  2. 控制台可以上下线,但是不能删除实例:提示

  3. 使用SDK上下线不生效

其他背景:Nacos Client SDK: 2.0.3

本文接下来针对这三个问题进行逐个击破,提供思路之前得明确当前是使用什么方式是什么,以及注意事项


前提认知

在解决之前,首先我们要明确几个官方的概念:大家无论是通过控制台还是SDK,都应该具备一个共同认知:

关键认知 说明
唯一实例标准 服务名+ip + 端口 + ephemeral【是否临时实例,默认true】 + cluster name可定位唯一一个实例
实例下线 通过控制台操作就是指进入实例详情对目标ip点击上下线按钮在这里插入图片描述REST API方式就是操作URI:/nacos/v1/ns/instance
服务下线 通过控制台搜索实例,直接点击删除在这里插入图片描述REST API方式就是操作URI:/nacos/v1/ns/service,同时服务下线有个严格条件就是其下的实例数为0,说白了你看不到任何实例的前提下才能操作

解决方案

1. 控制台

通过前提我已经说明控制台操作删除服务失败的原因,那解决就自然需要通过接口或者SDK方式去保证实例为0,下面直接探讨REST 和 SDK之间的差异

2. REST API

服务注册

有些同学在第一步就有问题,贴出来给大家参考【标红部分有些可选但是如果你是公司级项目肯定是不能使用默认值,因为SRE一般会自定义

【前车之鉴】通用解决Nacos Open API手动上下线不生效,创建实例后先被设置不健康而后被自动剔除集群,以及控制台无法删除实例Instance 超详细解决方案_第1张图片
那么使用这个API进行注册,的确可以立刻看到结果,但是细心的你如果观察15秒左右【Nacos默认心跳周期15s】,就会发现没有心跳,被设置为不健康 随后被自动清除任务扫描不健康实例 直接删除

那么为什么?

因为临时实例强制发送心跳包,你如果只是简单实用API进行接口调用,是没有发送心跳包,究其根本是没有有使用官方推荐SDK的方式, 只有SDK提供这种携带心跳注册的方式,保证了后续的心跳探活没问题。

服务下线

【前车之鉴】通用解决Nacos Open API手动上下线不生效,创建实例后先被设置不健康而后被自动剔除集群,以及控制台无法删除实例Instance 超详细解决方案_第2张图片

你会发现,当你尝试通过API进行服务下线,也会出现两个问题

  1. 接口返回ok,但是没有生效

有两个情况:
A.你注册是时候设置临时实例为fase,下线的时候却没有设置临时实例ephemeral 为false,因为不满足唯一性,但是官方并没有提供校验程序,虽然返回ok但是nothing happen

B. 告诉你用DELETE请求操作,但是你使用其他请求方式

  1. 接口返回ok,只是将实例上线两个字 变为 “下线”, 想要彻底清除怎么办。

注意你看到这个结果你肯定是用PUT那个方式进行update enable字段才会这样,可本来你用的就是update 接口,自然无法剔除,所以使用DELETE接口【不好意思,还是因为心跳包没有释放,所以操作无效】,所以建议直接使用SDK方式提供注册添加心跳,注销释放心跳方式


3. SDK

【前车之鉴】通用解决Nacos Open API手动上下线不生效,创建实例后先被设置不健康而后被自动剔除集群,以及控制台无法删除实例Instance 超详细解决方案_第3张图片
这里就说明了为啥SDK 可以确保注册实例无论是临时还有非临时,都可以一直存在nacos服务端根本,就是心跳啊老铁

服务注册
 @Resource private InetUtils inetUtils;
 public String getIp() {
     return inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
 }
 public void regist(){
 Instance instance = new Instance();
 instance.setIp(getIp);
 instance.setPort(port);
 // use http method to register or deregister instance
 instance.setEphemeral(false);
 instance.setClusterName(Constants.DEFAULT_CLUSTER_NAME);

  namingService.registerInstance(serverName, instance);
 }

这里要分类讨论两种触发方式,也是本文写作的根本来源,当然无论以下哪种,都是使用上述代码

  1. 本服务发起注册和注销

最为正常的方式,都没问题, 只是我并未使用这个场景

  1. 通过在其他服务里模拟SDK调用方式传入目标服务注册和注销

如果直接使用默认的临时为例为true情况下,会失败,但失败原因我暂未查询到,可以确定是服务端问题,因为在使用sdk上下线的时候,内部通过ephemeral 是否为true 来决定使用 GrpcClient 还是Http client方式

最初我使用默认即GRPC去对目标服务发起注册,发现结果成功,但实际并没有发生变化,于是ephemeral改成false就解决了该问题,猜想是服务端Grpc方式有什么问题,因为nacos是运维同学在管理且这个组件是我们部门自研,所以排查起来不太方便,但是解决问题为主,特记录于此

【前车之鉴】通用解决Nacos Open API手动上下线不生效,创建实例后先被设置不健康而后被自动剔除集群,以及控制台无法删除实例Instance 超详细解决方案_第4张图片
【前车之鉴】通用解决Nacos Open API手动上下线不生效,创建实例后先被设置不健康而后被自动剔除集群,以及控制台无法删除实例Instance 超详细解决方案_第5张图片


服务下线

同理,只是要确保操作唯一性

 Instance instance = new Instance();
 instance.setIp(ip);
 instance.setPort(port);
 instance.setEphemeral(false); # 注意和注册保持一致
 instance.setClusterName(Constants.DEFAULT_CLUSTER_NAME);
 namingService.deregisterInstance(tempService, instance);

你可能感兴趣的:(前车之鉴,java,Nacos,服务注册与注销)