Graceful Shutdown in Kubernetes and Spring Boot Microservices: Best Practices and Optimizations
This article explains the concept of graceful shutdown, outlines essential steps, examines Kubernetes pod termination and Spring Boot integration with Nacos, and provides practical optimizations—including PreStop hooks, terminationGracePeriod settings, and actuator shutdown—to ensure reliable service termination without data loss.
Graceful shutdown refers to the process of safely stopping a device, system, or application by executing a series of actions that protect data, prevent errors, and maintain overall stability.
Typical steps include backing up data, stopping new requests, processing in‑flight requests, notifying dependent components, and finally shutting down after all elements have exited safely.
In microservice environments, the exact steps vary by platform; for example, when a user runs kubectl delete pod , Kubernetes initiates two parallel processes:
Network rules are updated: the kube‑apiserver marks the pod as terminating, the endpoint controller removes the pod IP, and kube‑proxy updates iptables to stop routing traffic to the pod.
Container deletion: kube‑apiserver marks the pod as terminating, kubelet cleans up storage and network resources, a PreStop hook is invoked, SIGTERM is sent to the container, and if it does not exit within the default 30 seconds, SIGKILL forces termination.
A concrete case using Spring Boot, Nacos, and Kubernetes demonstrates common pitfalls: the Spring Boot shutdown time (≈2 s) is insufficient to finish asynchronous tasks, MQ messages, or scheduled jobs, especially when the PreStop hook sleeps for 35 seconds, exceeding the pod’s terminationGracePeriodSeconds and causing an extra 2 second grace period before a forced kill.
The article suggests several optimizations:
Reduce or eliminate the 35 second sleep after Nacos deregistration by enabling UDP discovery or listening to Nacos change notifications to refresh Ribbon caches promptly.
Set terminationGracePeriodSeconds slightly larger than the total time spent in PreStop plus the Spring Boot shutdown duration; a practical value is 10 seconds plus the default 30‑second Spring Boot grace period.
Enable Spring Boot’s graceful shutdown and implement custom shutdown logic to handle MQ listeners, scheduled tasks, and thread‑pool termination.
Example code for a Nacos instance change listener (kept unchanged) is shown below:
/**
* 订阅 nacos 实例变更通知
* 手动刷新 ribbon 服务实例缓存
* nacos client 1.4.6 【1.4.1有重大缺陷,要注意】
*/
@Component
@Slf4j
public class NacosInstancesChangeEventListener extends Subscriber
{
@Resource
private SpringClientFactory springClientFactory;
@PostConstruct
public void registerToNotifyCenter() {
NotifyCenter.registerSubscriber(this);
}
@Override
public void onEvent(InstancesChangeEvent event) {
String service = event.getServiceName();
// service: DEFAULT_GROUP@@demo ribbonService: demo
String ribbonService = service.substring(service.indexOf("@@") + 2);
log.info("##### 接收到微服务nacos实例变更事件:{} ribbonServiceName: {}", event.getServiceName(), ribbonService);
ILoadBalancer loadBalancer = springClientFactory.getLoadBalancer(ribbonService);
if (loadBalancer != null) {
((ZoneAwareLoadBalancer
) loadBalancer).updateListOfServers();
log.info("刷新 ribbon 服务实例:{} 缓存成功", ribbonService);
}
}
@Override
public Class
subscribeType() {
return InstancesChangeEvent.class;
}
/**
* nacos 1.4.4 ~ 1.4.6 需要加这个方法的实现, 2.1.2以后版本修复了该问题
* 多注册中心时,变更事件没有隔离,因此需要实现该方法来判断事件是否需要处理
* @see
ISSUE #8428 - Nacos InstancesChange Event Scope
*/
@Override
public boolean scopeMatches(InstancesChangeEvent event) {
return true;
}
}When using Spring Boot’s actuator shutdown, the process may be interrupted by a SIGTERM (kill ‑15) before the graceful shutdown completes; therefore, configure the thread pool to wait for tasks to finish, e.g., threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true); threadPoolTaskExecutor.setAwaitTerminationSeconds(30); .
Further improvements include having the shutting‑down service listen to its own Nacos deregistration event to stop MQ listeners and scheduled tasks, and ensuring that gateway services also refresh Ribbon caches to cut off traffic to the terminating instance.
In summary, a robust graceful shutdown strategy for Kubernetes‑based Spring Boot microservices involves proper PreStop hook design, appropriate terminationGracePeriodSeconds configuration, Nacos deregistration handling, thread‑pool shutdown settings, and optional actuator shutdown, all aimed at preserving data integrity and minimizing disruption.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.