Spring环境下如何仅将Liveness Probe移至独立端口或线程池?
解决方案
方案一:为Liveness端点分配独立线程池(无需修改端口)
这种方式无需额外端口,仅让Liveness探针请求使用独立线程池,避免被主线程池的高负载阻塞;同时Readiness探针仍使用主线程池,能准确反映应用的负载状态。
- 定义独立线程池Bean
创建专门处理Liveness探针请求的线程池:
@Bean(name = "livenessTaskExecutor") public TaskExecutor livenessTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(2); // 根据实际需求调整核心线程数 executor.setMaxPoolSize(5); // 最大线程数 executor.setQueueCapacity(10); // 任务队列容量 executor.setThreadNamePrefix("liveness-probe-"); // 线程名前缀,便于排查问题 executor.initialize(); return executor; }
- 配置MVC路由,仅对Liveness端点应用该线程池
通过WebMvc配置,限定只有Liveness端点的请求使用上述独立线程池:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired @Qualifier("livenessTaskExecutor") private TaskExecutor livenessTaskExecutor; @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setTaskExecutor(livenessTaskExecutor); // 拦截请求,仅对Liveness端点启用异步线程池 configurer.registerCallableInterceptors(new CallableProcessingInterceptor() { @Override public <T> boolean isAsyncRequest(HttpServletRequest request, Callable<T> task) { return request.getRequestURI().equals("/actuator/health/liveness"); } }); } }
配置后,主线程池高负载时,Readiness探针会因响应缓慢被判定为未就绪,Pod被移出流量池;而Liveness探针使用独立线程池,能快速响应,避免Pod被误杀。
方案二:将Liveness端点单独部署到独立端口
如果业务场景要求必须将Liveness探针放在独立端口,可通过Spring Boot多WebServer配置实现:主应用端口承载Readiness探针,独立端口仅提供Liveness端点服务。
- 添加自定义配置属性
在application.properties中定义Liveness端口:
management.liveness.server.port=9091
- 配置独立WebServer用于Liveness端点
创建配置类,启动第二个WebServer,仅注册Liveness相关的Actuator端点:
@Configuration public class LivenessServerConfig { @Value("${management.liveness.server.port:9091}") private int livenessPort; @Bean public ServletWebServerFactory livenessServerFactory() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(livenessPort); factory.addInitializers(servletContext -> { // 初始化仅用于Liveness端点的DispatcherServlet DispatcherServlet dispatcherServlet = new DispatcherServlet(); AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(LivenessEndpointConfig.class); dispatcherServlet.setApplicationContext(context); // 仅映射Liveness端点路径 servletContext.addServlet("livenessDispatcher", dispatcherServlet) .addMapping("/actuator/health/liveness"); }); return factory; } // 仅配置Liveness所需的Actuator组件 @Configuration static class LivenessEndpointConfig { @Bean public HealthEndpoint healthEndpoint(HealthAggregator healthAggregator, HealthIndicatorRegistry registry) { return new HealthEndpoint(healthAggregator, registry); } @Bean public LivenessHealthIndicator livenessHealthIndicator() { return new LivenessHealthIndicator(); } @Bean public EndpointMapping endpointMapping() { return new EndpointMapping("/actuator"); } @Bean public WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping(EndpointMapping endpointMapping, List<ExposableEndpoint<?>> endpoints, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties) { return new WebMvcEndpointHandlerMapping(endpointMapping, endpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), webEndpointProperties); } } }
配置完成后,Kubernetes的Readiness探针指向主应用端口的/actuator/health/readiness,Liveness探针指向9091端口的/actuator/health/liveness,两者完全独立,互不影响。
内容的提问来源于stack exchange,提问作者Shachar Levy
相关产品推荐
相关产品推荐

