Spring Boot 2.3.0配置Graceful-Shutdown,Readiness和Liveness

简介: Spring Boot 2.3.0配置Graceful-Shutdown,Readiness和Liveness

目录

背景:容器被广泛使用

优雅停机( Gracefully Shutdown )

存活状态( Liveness )

就绪状态( Readiness )

1.如何更新状态?

2.如何获取应用状态?

示例:Spring Boot 2.3.0配置Readiness和Liveness

代码示例

测试:Readiness和Liveness


Spring Boot团队最近发布了2.3.0版本,该版本具有许多增强功能,升级功能。(具体可以参考,Spring Boot 2.3.0 发行说明)。

在早些时候,Spring团队就已经宣布2.3版本将专注于Kubernetes。考虑到这一点,本文我们将尝试探索其中一些功能。


背景:容器被广泛使用

众所周知,容器是独立的单元,它是将应用程序及其依赖项打包为一个单元。因此,应用程序可以实现从一个环境快速可靠地迁移运行到另一个环境。*只要不同环境中存在兼容的容器运行时,就可以满足容器的可移植性,。

容器是操作系统虚拟化的一种,它包含运行应用程序所需的一切:可执行二进制文件,类库,配置文件,配置文件和系统库。与服务器虚拟化相比,容器不为每个虚拟环境提供单独的操作系统,容器使用主机上的操作系统。

由于对容器的前所未有的使用,对诸如KubernetesDocker Swarm之类的容器编排和管理工具的需求也在增加。这些工具通过许多功能简化了我们管理容器的工作,这些功能包括:

  • 容器分组 ( Container grouping )
  • 自我修复
  • 自动扩展
  • DNS管理
  • 负载均衡
  • 滚动更新或回滚
  • 资源监控和记录

几乎所有功能都围绕应用程序(容器)提供以下方面的状态:

  • 优雅停机( Gracefully Shutdown )
  • 存活状态( Liveness )
  • 就绪状态( Readiness )

让我们详细研究它们中的每一个,以及如何在启动Spring Boot 2.3.0中实现它们。


优雅停机( Gracefully Shutdown )

通常,优雅停机意味着在关闭应用程序之前,应设置超时期限,以允许仍在进行中的请求操作完成。在此超时期间,将不允许新请求。这将使你在应用请求处理方面保持一致,即没有未处理请求。

Spring Boot 2.3.0.RELEASE引入了Graceful Shutdown的功能。其中所有四个嵌入式Web服务器(Tomcat,Undertow,Netty和Jetty)都为响应式和基于Servlet的Web应用程序提供优雅停机功能。优雅停机是关闭应用程序上下文的一部分,并且在SmartLifecycle bean停止的最早阶段执行。

应用程序在宽限期内停止新请求的恰当方式,取决于所使用的服务器。根据官方文档Tomcat,Jetty和Reactor Netty将在网络层停止接受请求。Undertow将接受请求,但立即会以HTTP 503(服务不可用)来响应。

请注意,Tomcat 9.0.33或更高版本,才具备优雅停机功能。

在Spring Boot 2.3.0中,优雅停机非常容易实现,并且可以通过在应用程序配置文件中设置两个属性来进行管理。

  1. server.shutdown:此属性可以支持的值有
  1. immediate:这是默认值,将导致服务器立即关闭。
  2. graceful:启用优雅停机,并遵守spring.lifecycle.timeout-per-shutdown-phase属性中给出的超时。
  1. spring.lifecycle.timeout-per-shutdown-phase:采用java.time.Duration格式的值。

例如:

Properties 文件

# Enable gracefule shutdown
server.shutdown=graceful
# Allow grace timeout period for 20 seconds
spring.lifecycle.timeout-per-shutdown-phase=20s
# Force enable health probes. Would be enabled on kubernetes platform by default
management.health.probes.enabled=true

现在,当我们配置了优雅停机时,可能会有两种可能性:

  1. 应用中没有正在进行的要求。在这种情况下,应用程序将会直接关闭,而无需等待宽限期结束后才关闭。
  2. 如果应用中有正在处理的请求,则应用程序将等待宽限期结束后才能关闭。如果应用在宽限期之后仍然有待处理的请求,应用程序将抛出异常并继续强制关闭。

 


存活状态( Liveness )

就应用程序而言,存活状态是指应用程序的状态是否正常。如果存活状态不正常,则意味着应用程序本身已损坏,无法恢复。在Kubernetes中,如果存活探针检测失败,则kubelet将杀死Container,并且Container将接受其重新启动策略。如果容器未提供存活探针,则默认状态为“ Success ”。

Spring Boot 2.3.0引入了org.springframework.boot.availability.LivenessState。可用状态为

  1. CORRECT :该应用程序正在运行,并且其内部状态正常。
  2. BROKEN:应用程序正在运行,但内部状态被打破。


就绪状态( Readiness )

就绪状态,指的是应用程序是否已准备好接受并处理客户端请求。出于任何原因,如果应用程序尚未准备好处理服务请求,则应将其声明为繁忙,直到能够正常响应请求为止。如果“Readiness”状态尚未就绪,则不应将流量路由到该实例。

例如,在Kubernetes中,如果就绪探针失败,则 Endpoints 控制器将从与Endpoints中删除Pod的IP地址。设置就绪状态为“Failure”。如果容器未提供就绪探针,则默认状态为“Success”。

Spring Boot在ReadinessState的帮助下引入了就绪状态。可以设置的值有:

  1. ACCEPTING_TRAFFIC:应用程序准备好接收流量。这是默认值。
  2. REFUSING_TRAFFIC:应用程序拒绝接收流量。

现在,当我们了解概念后,脑海中会有两个问题。


1.如何更新状态?

Spring Boot选择了Spring应用程序事件模型来更改可用性状态。Spring Boot还配置了ApplicationAvailabilityBean类型的Bean,它是ApplicationAvailability接口的实现。该bean监听这些事件并保持最新状态。因此,我们使用ApplicationAvailability来获取应用程序的状态

// Available as a component in the application context
ApplicationAvailability availability;
LivenessState livenessState = availability.getLivenessState();
ReadinessState readinessState = availability.getReadinessState();

我们还可以使用AvailabilityChangeEvent来更新状态。


2.如何获取应用状态?

最常见的用例是部署支持探针的Web应用程序。Spring boot Actuator是唯一需要的依赖项。因为Spring Boot Actuator已经公开了应用程序运行状况的端点( endpoint )。

启动Spring Boot 2.3.0 Actuator还将在Health指示器中公开可用性状态。这些指标将全部显示在“/actuator/health*”上。这些健康状况端点也可以作为单独的HTTP端点使用:“ /actuator/health/liveness ”和“ /actuator/health/readiness ”。

在Kubernetes平台上运行时,默认情况下这些指标( indicators)包括在actuator/health的endpoint中,而在另一个平台上则不可用。但是,你始终可以通过将management.health.probes.enabled属性设置为true来覆盖此行为。

Properties 文件

# Force enable health probes. Enabled on Kubernetes platform by default
management.health.probes.enabled=true

请注意,所有与可用性相关的组件都org.springframework.boot.availability软件包的一部分。


示例:Spring Boot 2.3.0配置Readiness和Liveness

在我们编写代码之前,请记住

  • 使用ApplicationAvailability获取应用程序的状态。
  • 发布AvailabilityChangeEvent来更新状态。

出于演示的目的,我将在单个RestController中操作,并使用HTTP GET端点调用它们。在理想情况下,这些将由负责管理应用程序不同组件的bean完成。例如缓存,如果缓存失败,则你的缓存bean可以发布ReadinessState.REFUSING_TRAFFIC以拒绝请求到达此应用程序。


代码示例

下面的代码仅用于演示如何根据需要更改状态。不能在生产中使用。

package org.sk.ms.probes;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/** 
 * This is sample code to display how to use probes available in spring boot 2.3.0. Not to be used in production. This must be updated by {@link Component} beans for example caching or connection revalidators
 */
@RestController
public class ExampleController {
    private final Logger logger = org.slf4j.LoggerFactory.getLogger(ExampleController.class);
    @Autowired
    private  ApplicationEventPublisher eventPublisher;
    public ExampleController(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    @GetMapping("/complete-normally")
    public String completeNormally() throws Exception {
        return "Hello from Controller";
    }
    @GetMapping("/i-will-sleep-for-30sec")
    public String destroy() throws Exception {
        logger.info("------------------ Sleeping for 30 sec");
        Thread.sleep(30000);
        return "sleep complete";
    }
    @GetMapping("/readiness/accepting")
    public String markReadinesAcceptingTraffic() {
        AvailabilityChangeEvent.publish(eventPublisher, this, ReadinessState.ACCEPTING_TRAFFIC);
        return "Readiness marked as ACCEPTING_TRAFFIC";
    }
    @GetMapping("/readiness/refuse")
    public String markReadinesRefusingTraffic() {
        AvailabilityChangeEvent.publish(eventPublisher, this, ReadinessState.REFUSING_TRAFFIC);
        return "Readiness marked as REFUSING_TRAFFIC";
    }
    @GetMapping("/liveness/correct")
    public String markLivenessCorrect() {
        AvailabilityChangeEvent.publish(eventPublisher, this, LivenessState.CORRECT);
        return "Liveness marked as CORRECT";
    }
    @GetMapping("/liveness/broken")
    public String markLivenessBroken() {
        AvailabilityChangeEvent.publish(eventPublisher, this, LivenessState.BROKEN);
        return "Liveness marked as BROKEN";
    }
}


测试:Readiness和Liveness

1.检查可用端点

检查可用端点的初始值:

 


2.宽限期(没有正在进行中的请求)

我们将宽限期设置为20秒。而且没有正在进行中的请求。观察日志。

 


3.宽限期已过

我们有20秒的宽限期。让我们发出一个需要30秒才能完成的请求,然后尝试停止该应用程序。

在这种情况下,应用程序将因错误而关闭。注意观察日志。

 


4.将存活状态更新为“BROKEN”,然后将其设置为“CORRECT”

默认情况下,存活状态是由Spring应用程序上下文设置的。

存活状态,一旦标记为 correct ,它将反映在运行状况端点中,并且容器管理器将知道此实例。

例如,你的应用程序依赖于缓存,并且无法刷新缓存,应用程序的存活状态就会被标记为 broken ,容器管理器会基于配置采取适当的措施处理。

 


5.将就绪状态设置为REFUSING_TRAFFIC,并在恢复后返回ACCEPTING_TRAFFIC

一旦你的应用程序准备好处理请求,可以将就绪状态设置为REFUSING_TRAFFIC。

例如,在缓存更新时,应该将应用程序标记为REFUSING_TRAFFIC,否则可能会处理过时的数据。在这种情况下,容器管理器应停止向该实例发送流量。

但请记住,恢复后应将状态标记回ACCEPTING_TRAFFIC,以便可以将流量再次路由到该实例。

 

你可以在此GitHub仓库找到以上示例的完整代码。


译文链接: https://dzone.com/articles/configuring-graceful-shutdown-readiness-and-livene



相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
3月前
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
|
3月前
|
Java 关系型数据库 MySQL
Spring Boot自动配置:魔法背后的秘密
Spring Boot 自动配置揭秘:只需简单配置即可启动项目,背后依赖“约定大于配置”与条件化装配。核心在于 `@EnableAutoConfiguration` 注解与 `@Conditional` 系列条件判断,通过 `spring.factories` 或 `AutoConfiguration.imports` 加载配置类,实现按需自动装配 Bean。
|
3月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
1216 0
|
5月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 > Java系统属性 > application.properties > application.yml > application.yaml。
980 0
|
2月前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
3月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
567 5
|
8月前
|
安全 Java API
深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题
本文深入解析了Spring Security配置中CSRF启用与`requestMatchers`报错的常见问题。针对CSRF,指出默认已启用,无需调用`enable()`,只需移除`disable()`即可恢复。对于`requestMatchers`多路径匹配报错,分析了Spring Security 6.x中方法签名的变化,并提供了三种解决方案:分次调用、自定义匹配器及降级使用`antMatchers()`。最后提醒开发者关注版本兼容性,确保升级平稳过渡。
943 2
|
3月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
187 0
探索Spring Boot的@Conditional注解的上下文配置
|
9月前
|
缓存 Java API
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
本文介绍了在Spring Boot中配置Swagger2的方法。通过创建一个配置类,添加`@Configuration`和`@EnableSwagger2`注解,使用Docket对象定义API文档的详细信息,包括标题、描述、版本和包路径等。配置完成后,访问`localhost:8080/swagger-ui.html`即可查看接口文档。文中还提示了可能因浏览器缓存导致的问题及解决方法。
1031 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
|
4月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
1008 10