> 技术文档 > 微服务(Nacos、eureka、consul)优雅上下线方案汇总_nacos下线服务

微服务(Nacos、eureka、consul)优雅上下线方案汇总_nacos下线服务


前提

   必须是集群,多个实例

优雅的本质

一个服务有多个(如A、B 两个实例)实例提供服务时,客户端请求服务时会访问此服务的多个实例,当进行A实例进行部署时将流量切换到B实例,然后再关闭或重新发布 ;如何实现这个功能呢?

所以本质就是模拟人工在控制台触发“下线”功能(此实例还是提供服务),过一会儿等流量全部切到其他实例再部署&Kill实例;可以理解为此实例说:“我即将要先下线了,请访问另外实例”。

为什么要过一会儿?

可能客户端缓存的服务提供的实例Ip列表导致无效的请求或服务挂掉后瞬间的访问不到服务的情况

在部署脚本里面植入1、下线脚本;2  增加缓冲时间(如60s),默认Nacos客户端缓存实例列表是30s;

方案1  注册中心自带的方法

我们使用的这个方式,简单无需配置,默认支持;

下线

curl -X PUT \"http://nacos服务ip:port/nacos/v1/ns/instance?serviceName=服务名&ip=172.25.135.221&port=8667&namespaceId=preprod&weight=0&enabled=false\"

上线

curl -X PUT \"http:/nacos服务ip:port/nacos/v1/ns/instance?serviceName=服务名&ip=172.25.135.221&port=8667&namespaceId=preprod&weight=1&enabled=true\"

方案2  基于/service-registry端点

如果应用支持Spring Cloud部署那就更好了。Spring Cloud提供了/service-registry端点。但从名字就可以知道专门针对服务注册实现的一个端点。

在配置文件中开启/service-registry端点:

1

2

3

4

5

6

7

8

9

management:

  endpoints:

    web:

      exposure:

        include: service-registry

      base-path: /actuator

  endpoint:

    serviceregistry:

      enabled: true

  

访问http://localhost:8667/actuator 端点可以查看到开启了如下端点:

1

2

3

4

5

6

7

8

9

10

11

12

{

    \"_links\": {

        \"self\": {

            \"href\"\"http://localhost:8667/actuator\",

            \"templated\"false

        },

        \"serviceregistry\": {

            \"href\"\"http://localhost:8667/actuator/service-registry\",

            \"templated\"false

        }

    }

}

  

通过curl命令来进行服务状态的修改:上线是UP,下线是DOWN

curl -X \"POST\" \"http://172.25.129.191:8667/actuator/service-registry?status=DOWN\" -H \"Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8\"

执行上述命令之前,查看Nacos对应实例状态为:

比方案1 多了一个步骤 需要配置一下开启一下才行;

其本质就是如下代码,去关闭了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

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

@Endpoint(id = \"service-registry\")

public class ServiceRegistryEndpoint {

    private final ServiceRegistry serviceRegistry;

    private Registration registration;

    public ServiceRegistryEndpoint(ServiceRegistry serviceRegistry) {

        this.serviceRegistry = serviceRegistry;

    }

    public void setRegistration(Registration registration) {

        this.registration = registration;

    }

    @WriteOperation

    public ResponseEntity setStatus(String status) {

        Assert.notNull(status, \"status may not by null\");

        if (this.registration == null) {

            return ResponseEntity.status(HttpStatus.NOT_FOUND)

                    .body(\"no registration found\");

        }

        this.serviceRegistry.setStatus(this.registration, status);

        return ResponseEntity.ok().build();

    }

    @ReadOperation

    public ResponseEntity getStatus() {

        if (this.registration == null) {

            return ResponseEntity.status(HttpStatus.NOT_FOUND)

                    .body(\"no registration found\");

        }

        return ResponseEntity.ok()

                .body(this.serviceRegistry.getStatus(this.registration));

    }

}

  

调用的Endpoint便是通过上面代码实现的。所以不仅Nacos,只要基于Spring Cloud集成的注册中心,本质上都是支持这种方式的服务下线的。

方案3  个性化定义下线方式,本质还是调用方案2的

不需要配置,实现钩子方法即可

在实例启动的时默认都会进行注册实例到注册中心,如下官方实现方式:NacosServiceRegistryAutoConfiguration

@Configuration(proxyBeanMethods = false)@EnableConfigurationProperties@ConditionalOnNacosDiscoveryEnabled@ConditionalOnProperty(value = \"spring.cloud.service-registry.auto-registration.enabled\", matchIfMissing = true)@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class })public class NacosServiceRegistryAutoConfiguration { @Bean public NacosServiceRegistry nacosServiceRegistry( NacosDiscoveryProperties nacosDiscoveryProperties) { return new NacosServiceRegistry(nacosDiscoveryProperties); } @Bean @ConditionalOnBean(AutoServiceRegistrationProperties.class) public NacosRegistration nacosRegistration( NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) { return new NacosRegistration(nacosDiscoveryProperties, context); } @Bean @ConditionalOnBean(AutoServiceRegistrationProperties.class) public NacosAutoServiceRegistration nacosAutoServiceRegistration( NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) { return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); }}

复制代码

你只需要知道如何拿到注册实例即可,默认就可以获取,实现自己的对外接口即可

@Resource

    private NacosServiceRegistry nacosServiceRegistry;

    @Resource

    private NacosRegistration nacosRegistration;

    @GetMapping(value = \"/api/nacos/{status}\")

    public String deregisterInstanceStatus(@PathVariable String status) {

        if (!status.equalsIgnoreCase(\"UP\") && !status.equalsIgnoreCase(\"DOWN\")) {

            log.warn(\"can\'t support status {},please choose UP or DOWN\", status);

            return \"please choose UP or DOWN,can\'t support status: \"+status;

        }

        try {

            nacosServiceRegistry.setStatus(nacosRegistration,status);

        } catch (Exception e) {

            log.error(\" deregisterInstanceStatus nacos error\", e);

            return \"error:\"+e.getMessage();

        }

        return \"success\";

    }

  

参考资源:

https://zhuanlan.zhihu.com/p/586909971  部分可以参考,他是直接注销实例,不是下线

微服务架构:Nacos本地缓存 PK 微服务优雅下线_nacos下线相当于kill服务吗-CSDN博客  Nacos本地缓存 PK 微服务优雅下线

https://blog.51cto.com/u_9177933/3013415  eureka、consul的其他注册中心的方案

[微服务]nacos停服方案实践(nacos多个微服务实例) - 站长素材网

https://segmentfault.com/a/1190000043819832#item-3-9  spring boot 2.2.1以上版本的方式