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



相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
1月前
|
Java 开发者 微服务
手写模拟Spring Boot自动配置功能
【11月更文挑战第19天】随着微服务架构的兴起,Spring Boot作为一种快速开发框架,因其简化了Spring应用的初始搭建和开发过程,受到了广大开发者的青睐。自动配置作为Spring Boot的核心特性之一,大大减少了手动配置的工作量,提高了开发效率。
50 0
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
58 4
|
2月前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
42 0
|
2天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
30 14
|
1天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
18 3
|
2月前
|
Java API Spring
在 Spring 配置文件中配置 Filter 的步骤
【10月更文挑战第21天】在 Spring 配置文件中配置 Filter 是实现请求过滤的重要手段。通过合理的配置,可以灵活地对请求进行处理,满足各种应用需求。还可以根据具体的项目要求和实际情况,进一步深入研究和优化 Filter 的配置,以提高应用的性能和安全性。
|
1月前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
42 2
|
2月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
71 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
35 1
|
3月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
244 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)