微服务架构:Nacos本地缓存 PK 微服务优雅下线

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 微服务架构:Nacos本地缓存 PK 微服务优雅下线

前言

在上篇文章《微服务:剖析一下源码,Nacos的健康检查竟如此简单》中讲了当微服务突然挂掉的解放方案:调整健康检查周期和故障请求重试。朋友看了文章,建议再聊聊正常关闭服务时如何让微服务优雅下线。

为什么说是优雅下线?我们知道在分布式应用中为了满足CAP原则中的A(可用性),像Nacos、Eureka等注册中心的客户端都会进行实例列表的缓存。当正常关闭应用时,虽然可以主动调用注册中心进行注销,但这些客户端缓存的实例列表还是要等一段时间才会失效。

上述情况就有可能导致服务请求到已经被关闭的实例上,虽然通过重试机制可以解决掉这个问题,但这种解决方案会出现重试,在一定程度上会导致用户侧请求变慢。这时就需要进行优雅的下线操作了。

下面我们先从通常关闭进程的几种方式聊起。

方式一:基于kill命令

Spring Cloud本身对关闭服务是有支持的,当通过kill命令关闭进程时会主动调用Shutdown hook来进行当前实例的注销。使用方式:

kill Java进程ID

这种方式是借助Spring Cloud的Shutdown hook机制(本质是Spring Boot提供,Spring Cloud服务发现功能进行具体注销实现),在关闭服务之前会对Nacos、Eureka等服务进行注销。但这个注销只是告诉了注册中心,客户端的缓存可能需要等几秒(Nacos默认为5秒)之后才能感知到。

这种Shutdown hook机制不仅适用于kill命令,还适用于程序正常退出、使用System.exit()、终端使用Ctrl + C等。但不适用于kill -9 这样强制关闭或服务器宕机等场景。

这种方案虽然比直接挂掉要等15秒缩短了时间,相对好一些,但本质上并没有解决客户端缓存的问题,不建议使用。

方式二:基于/shutdown端点

在Spring Boot中,提供了/shutdown端点,基于此也可以实现优雅停机,但本质上与第一种方式相同,都是基于Shutdown hook来实现的。在处理完基于Shutdown hook的逻辑之后,也会进行服务的关闭,但同样面临客户端缓存的问题,因此,也不推荐使用。

这种方式首先需要在项目中引入对应的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

然后在项目中配置开启/shutdown端点:

management:
  endpoint:
    shutdown:
      enabled: true
  endpoints:
    web:
      exposure:
        include: shutdown

然后停服时请求对应的端点,这里采用curl命令示例:

curl -X http://实例服务地址/actuator/shutdown

方式三:基于/pause端点

Spring Boot同样提供了/pause端点(Spring Boot Actuator提供),通过/pause端点,可以将/health为UP状态的实例修改为Down状态。

基本操作就是在配置文件中进行pause端点的开启:

management:
  endpoint:
    # 启用pause端点
    pause:
      enabled: true
    # pause端点在某些版本下依赖restart端点
    restart:
      enabled: true
  endpoints:
    web:
      exposure:
        include: pause,restart

然后发送curl命令,即可进行服务的终止。注意这里需要采用POST请求。

关于/pause端点的使用,不同的版本差异很大。笔者在使用Spring Boot 2.4.2.RELEASE版本时发现根本无法生效,查了Spring Boot和Spring Cloud项目的Issues发现,这个问题从2.3.1.RELEASE就存在。目前看应该是在最新版本中Web Server的管理改为SmartLifecycle的原因,而Spring Cloud对此貌似放弃了支持(有待考察),最新的版本调用/pause端点无任何反应。

鉴于上述版本变动过大的原因,不建议使用/pause端点进行微服务的下线操作,但使用/pause端点的整个思路还是值得借鉴的。

基本思路就是:当调用/pause端点之后,微服务的状态会从UP变为DOWN,而服务本身还是可以正常提供服务。当微服务被标记为DOWN状态之后,会从注册中心摘除,等待一段时间(比如5秒),当Nacos客户端缓存的实例列表更新了,再进行停服处理。

这个思路的核心就是:先将微服务的流量切换掉,然后再关闭或重新发布。这就解决了正常发布时客户端缓存实例列表的问题。

基于上述思路,其实自己也可以实现相应的功能,比如提供一个Controller,先调用该Controller中的方法将当前实例从Nacos中注销,然后等待5秒,再通过脚本或其他方式将服务关闭掉。

方式四:基于/service-registry端点

方式三中提到的方案如果Spring Cloud能够直接支持,那就更好了。这不,Spring Cloud提供了/service-registry端点。但从名字就可以知道专门针对服务注册实现的一个端点。

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

management:
  endpoints:
    web:
      exposure:
        include: service-registry
      base-path: /actuator
  endpoint:
    serviceregistry:
      enabled: true

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

{
    "_links": {
        "self": {
            "href": "http://localhost:8081/actuator",
            "templated": false
        },
        "serviceregistry": {
            "href": "http://localhost:8081/actuator/serviceregistry",
            "templated": false
        }
    }
}

通过curl命令来进行服务状态的修改:

curl -X "POST" "http://localhost:8081/actuator/serviceregistry?status=DOWN" -H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8"

执行上述命令之前,查看Nacos对应实例状态为:image.png上述命令就相当于我们在Nacos管理后台手动的操作了实例的上下线。

当然,上述情况是基于Spring Cloud和Nacos的模式实现的,本质上Spring Cloud是定义了一个规范,比如所有的注册中心都需要实现ServiceRegistry接口,同时基于ServiceRegistry这个抽象还定义了通用的Endpoint:

@Endpoint(id = "serviceregistry")
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集成的注册中心,本质上都是支持这种方式的服务下线的。

小结

很多项目都逐步在进行微服务化改造,但一旦因为微服务系统,将面临着更复杂的情况。本篇文章重点基于Nacos在Spring Cloud体系中优雅下线来为大家剖析了一个微服务实战中常见的问题及解决方案。你是否在使用微服务,你又是否注意到这一点了?想学更多微服务实战,啥也不说,关注吧。


目录
相关文章
|
5天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
3天前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
8天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
41 6
|
8天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
24 1
|
14天前
|
弹性计算 Kubernetes Cloud Native
云原生架构下的微服务设计原则与实践####
本文深入探讨了在云原生环境中,微服务架构的设计原则、关键技术及实践案例。通过剖析传统单体架构面临的挑战,引出微服务作为解决方案的优势,并详细阐述了微服务设计的几大核心原则:单一职责、独立部署、弹性伸缩和服务自治。文章还介绍了容器化技术、Kubernetes等云原生工具如何助力微服务的高效实施,并通过一个实际项目案例,展示了从服务拆分到持续集成/持续部署(CI/CD)流程的完整实现路径,为读者提供了宝贵的实践经验和启发。 ####
|
4天前
|
Dubbo Java 应用服务中间件
服务架构的演进:从单体到微服务的探索之旅
随着企业业务的不断拓展和复杂度的提升,对软件系统架构的要求也日益严苛。传统的架构模式在应对现代业务场景时逐渐暴露出诸多局限性,于是服务架构开启了持续演变之路。从单体架构的简易便捷,到分布式架构的模块化解耦,再到微服务架构的精细化管理,企业对技术的选择变得至关重要,尤其是 Spring Cloud 和 Dubbo 等微服务技术的对比和应用,直接影响着项目的成败。 本篇文章会从服务架构的演进开始分析,探索从单体项目到微服务项目的演变过程。然后也会对目前常见的微服务技术进行对比,找到目前市面上所常用的技术给大家进行讲解。
14 1
服务架构的演进:从单体到微服务的探索之旅
|
3天前
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
20 5
|
5天前
|
监控 API 微服务
后端技术演进:从单体架构到微服务的转变
随着互联网应用的快速增长和用户需求的不断演化,传统单体架构已难以满足现代软件开发的需求。本文深入探讨了后端技术在面对复杂系统挑战时的演进路径,重点分析了从单体架构向微服务架构转变的过程、原因及优势。通过对比分析,揭示了微服务架构如何提高系统的可扩展性、灵活性和维护效率,同时指出了实施微服务时面临的挑战和最佳实践。
24 7
|
4天前
|
Kubernetes 负载均衡 Cloud Native
云原生架构下的微服务治理策略
随着云原生技术的不断成熟,微服务架构已成为现代应用开发的主流选择。本文探讨了在云原生环境下实施微服务治理的策略和方法,重点分析了服务发现、负载均衡、故障恢复和配置管理等关键技术点,以及如何利用Kubernetes等容器编排工具来优化微服务的部署和管理。文章旨在为开发者提供一套实用的微服务治理框架,帮助其在复杂的云环境中构建高效、可靠的分布式系统。
18 5
|
4天前
|
负载均衡 监控 Cloud Native
云原生架构下的微服务治理策略与实践####
在数字化转型浪潮中,企业纷纷拥抱云计算,而云原生架构作为其核心技术支撑,正引领着一场深刻的技术变革。本文聚焦于云原生环境下微服务架构的治理策略与实践,探讨如何通过精细化的服务管理、动态的流量调度、高效的故障恢复机制以及持续的监控优化,构建弹性、可靠且易于维护的分布式系统。我们将深入剖析微服务治理的核心要素,结合具体案例,揭示其在提升系统稳定性、扩展性和敏捷性方面的关键作用,为读者提供一套切实可行的云原生微服务治理指南。 ####