我正在尝试在 Spring Boot 2 应用程序中实现优雅关闭,以在 Pod 缩小时消除 5xx 错误
我已经定了
management:
endpoints:
jmx:
exposure:
include: "*"
web:
exposure:
include: "*"
endpoint:
shutdown:
enabled: true
server.shutdown: graceful
在我的
application.yaml
文件中,我使用 /actuator/health
端点作为我的 deployment.yaml
文件中的活跃性和就绪性探测器。
我在 preStopHook 中设置了 50 秒的睡眠时间,而我的终止GracePeriod 是 120 秒
我的deployment.yaml文件
lifecycle:
preStop:
exec:
command: ["/bin/sh","-c","sleep 50;","rm -rf /mnt/bixby/log/$HOSTNAME"]
terminationGracePeriod: 120
livenessProbe:
httpGet:
port: 8080
path: /actuator/health
initialDelaySeconds: 45
periodSeconds: 5
readinessProbe:
httpGet:
port: 8080
path: /actuator/health
initialDelaySeconds: 45
periodSeconds: 5
奇怪的是,这个东西在一个环境(我们称之为 dev1)中工作,但在其他环境(dev2)中却不起作用。
当我删除 pod 并向 /actuator/health 端点发送curl 请求时,它会在 dev1 中返回
{"status":"DOWN","groups":["liveness","readiness"]}
,但不会在 dev2 env 中返回任何响应。 50 秒后我得到以下输出 curl: (52) Empty reply from server
,这也是我的 prestopHook
睡眠时间。奇怪的是,我们之前使用的自定义健康检查端点在此期间返回了正确的响应
之后,如果我再次执行curl请求,我会得到以下输出
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /actuator/health HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 503 Service Unavailable
< Connection: keep-alive
< Content-Length: 0
同样奇怪的是,在 dev1 env 中,优雅关闭似乎可以正常工作,pod 在 50 秒后退出,这很奇怪,因为终止GracePeriod 是 120 秒
我在我的 Spring Boot 应用程序中添加了以下预销毁代码
@PreDestroy
public void tearDown() {
logger.log("Application shutting down");
}
两个环境中的所有配置、Spring Boot 应用程序的 docker 镜像、kubernetes 版本都是相同的。
我还添加了这个 swagger 配置,以便执行器与 swagger 一起工作
@Bean // This bean is required when you want swagger and actuator to work together
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider
|| bean instanceof RequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(
List<T> mappings) {
List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
一些事情:Springboot 提供了 liveness 和 readiness 探针,所以你不必使用
/actuator/health
在您的 application.yaml 中,执行以下操作:
management:
health:
livenessState:
enabled: true
readinessState:
enabled: true
然后在您的部署 yaml 中:
livenessProbe:
httpGet:
port: 8080
path: /actuator/health/liveness
initialDelaySeconds: 45
periodSeconds: 5
readinessProbe:
httpGet:
port: 8080
path: /actuator/health/readiness
initialDelaySeconds: 45
periodSeconds: 5
此外,pod 在 50 秒后退出是正确的。如果正常关闭只需要 50 秒,那么 pod 就没有理由等待超过这个时间。如果它总是等待 120 秒,则说明正常关闭没有正常进行。您应该在日志末尾看到“正常关闭已完成”,因此请像这样验证它。
至于在 1 个环境中正常关闭但在另一个环境中不起作用,这确实很奇怪。使用的部署文件是否完全相同?您如何开始申请?如果您想真正验证关闭是否有效,最好的选择是查看应用程序日志。