一、为什么要实现优雅停机 + 不停服更新?
-
提升用户体验:避免服务中断,减少用户困扰;
-
增强系统稳定性:确保服务在停止前处理完现有请求,减少错误,避免数据异常;
-
支持持续交付:实现频繁部署而不影响业务连续性;
-
降低成本:减少因服务中断带来的经济损失和维护成本;
二、如何实现优雅停机?
1、项目自身的配置:
其实,在Spring Boot 2.3 及以上版本中,已经内置了对优雅停机的支持,但是前提是确保我们服务中,已经已经正确引入了actuator依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
我们可以在 application.yml 或 application.properties 中进行如下配置:
server: shutdown: graceful spring: lifecycle: timeout-per-shutdown-phase: 30s
2、K8s中对的配置:
在 Kubernetes 中,我们需要确保 Pod 在停止之前有足够的时间来完成优雅停机,可对terminationGracePeriodSeconds参数进行如下配置:
apiVersion: v1 kind: Pod metadata: name: example-pod spec: terminationGracePeriodSeconds: 60 # 设置为合适的值,确保应用有足够的时间完成优雅停机 containers: - name: example-container image: your-spring-boot-app:latest ports: - containerPort: 8080
3、对于没有内置优雅停机的程序,我们可以通过自定义优雅停机的端口,配合k8s的preStop钩子,完成优雅停机:
apiVersion: v1 kind: Pod metadata: name: example-pod spec: terminationGracePeriodSeconds: 60 containers: - name: example-container image: your-spring-boot-app:latest ports: - containerPort: 8080 lifecycle: preStop: exec: # command: ["sh", "-c", "sleep 10"] # 预处理操作,例如等待 10 秒 command: ["curl", "-XPOST", "127.0.0.1:50000/actuator/shutdown"] # 调用优雅停机接口
4、进行了以上配置,我们的程序就可以实现优雅停机的效果了:
调试期间,重点观察:pod是否是在 Graceful shutdown complete 成功打印后,才被删除的?
但是,光实现优雅停机,服务的高可用性还是没有得到完全保障的,我们好需要实现,服务的不停服更新才可以!
三、如何实现不停服更新?
不停服更新的关键点就在于:要实现 滚动更新 + 就绪/存活探针 的配置!
1、如何配置滚动更新:
对于滚动更新策略,正常时候我们使用k8s管理面板的页面操作会更方便一点,因为市面上,所有的面板都会提供这一块的配置:
apiVersion: apps/v1 kind: Deployment metadata: name: my-spring-boot-app spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 也可以使用 25% 表示 maxUnavailable: 0
maxSurge: "25%" :在更新过程中最多可以创建当前副本数的 25% 的额外 Pod,从而加快更新速度。
maxUnavailable: 0 :确保在更新过程中没有 Pod 不可用,保持服务高可用性。
2、如何配置就绪/存活探针:
配置就绪/存活探针的关键就是,我们的系统有提供对应的探针,巧了,如果我们的 springboot 项目已经引入了actuator依赖,就是已经待了对应的探针的;
但是记得要把这两个探针加入登录认证的白名单哦!
之后,在k8s上配置时候,正常时候我们也会选择在k8s管理面板上进行配置:
在滚动更新,且新pod未就绪的状态下,k8s会为此pod标记为特殊状态,并不会为其分配流量:
当上述 “优雅停机 + 不停服更新”都进行了合理配置的情况下,我们应用程序的可靠性,将大大提升!