优雅停机
所谓的优雅停机指的是(一方面可以在停机的时候通过背板挡住外来正在发送的请求,另一方面已经接受的请求能够很好的执行完接下来的业务 )。服务在关闭的时候,不能通过强制kill进程的方式进行停止,这样的话,对于有些未处理完成的业务会造成数据的补偿.
一. 优雅停机
1. 如果是springboot2.3版本之前可以通引入如下jar
<dependency>
<groupId>com.github.timpeeters</groupId>
<artifactId>spring-boot-graceful-shutdown</artifactId>
<version>X.X.X</version>
</dependency>
版本可参考: 就可以实现优雅停机了
2、如果springboot是2.3版本之后,则可以直接在application.yml做如下配置即可
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
二. 健康检查配置
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置application.yml,如下
management:
endpoint:
shutdown:
enabled: true
health:
enabled: true
endpoints:
web:
base-path: /actuator
exposure:
include: shutdown,health
访问http://127.0.0.1:8083/actuator/health进行健康检测
http://127.0.0.1:8083/actuator/shutdown进行优雅停机
另外,其他端点的路径如下表格,注意,前面需要添加/actuator根路径 ,如下
三. springboot在docker容器中如何进行优雅关闭
如果在Dockerfile做如下配置
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
是没法实现优雅关闭的效果。其原因是使用 docker stop 关闭容器时, 只有 init(pid 1)进程能收到中断信号, 如果容器的pid 1 进程是 sh 进程, 它不具备转发结束信号到它的子进程的能力, 所以我们真正的java程序得不到中断信号, 也就不能实现优雅关闭. 解决思路是: 让pid 1 进程具备转发终止信号, 或者将 java 程序配成 pid 1 进程. 因此只需对Dockerfile做如下改造就行
ENTRYPOINT [ "sh", "-c", "exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
其实就是在java前边加上exec即可。其实现机理可以参考如下链接 https://spring.io/guides/topicals/spring-boot-docker
在k8s中如何进行优雅关闭
1、配置preStop Hook钩子
preStop Hook 是一个发送到 Pod 中的容器特殊命令或 Http 请求。如果您的应用程序在接收 SIGTERM 时没有正常关闭,您可以使用 preStop Hook 来触发正常关闭。接收 SIGTERM 时大多数 程序都会正常关闭,但如果您使用的是第三方代码或管理的系统无法控制,则 preStop Hook 是在不修改应用程序的情况下触发正常关闭的好方法。 2、适当延长terminationGracePeriodSeconds时间
其配置参考如下
apiVersion: v1
kind: Pod
metadata:
name: demopod
spec:
containers:
- image: springboot-demo:v1.10
name: demo-container
ports:
- containerPort: 8080
lifecycle:
preStop:
exec:
command: ["curl", "-XPOST", "127.0.0.1:8083/actuator/shutdown"]
总结
优雅关闭正常都是会配置一定的处理时间,超过该时间没处理完,就会进行强杀。因此对于核心业务,我们还得考虑万一进行强杀时,还要考虑是否需要对业务进行补偿操作
|