一、服务下线方案
(一)粗鲁下线
粗鲁下线应该绝对禁止
kill -n <pid> # n为信号变量
例:
kill -9 <pid> # 强制停止
kill -15 <pid> # 如果程序正在IO,可能不会立刻做出反映
在停止的那一霎那,应用中正在处理的业务逻辑会被中断,导致产生业务异常情形。
# 查看linux常见的信号变量
$ kill -l
参考:Linux kill -9 和 kill -15 的区别
普通服务优雅下线
(1)web容器优雅停止
在 Spring Boot 2.3 中增加了新特性优雅停止。下面都支持优雅停止
(1)Spring Boot 内置的四钟嵌入式 Web 服务器(Jetty、Reactor Netty、Tomcat 和 Undertow)
(2)反应式框架
(3)基于 Servlet 的 Web 应用程序
大概逻辑就是先停止外部的所有新请求,然后再处理关闭前收到的请求
application.yml 中添加一些配置来启用优雅停止
# 开启优雅停止 Web 容器,默认为 IMMEDIATE:立即停止
server:
shutdown: graceful
# 最大等待时间
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
(2)SpringApplication.exit(context);
(3)acturator 的 shutdown 端点
原理:执行 doClose() 方法,关闭并销毁 applicationContext
(4)自定义 ApplicationListener
Nacos 服务下线
(1) 创建脚本
k8s 容器生命周期中的prestop阶段配置一个执行脚本:
lifecycle:
preStop:
exec:
command:
- /bin/sh
- '-c'
- 'curl -X POST ''http://localhost:8080/actuator/stopService'';\' #
- sleep 30;
(2) 暴露出关闭接口
/** 使用了nacos注册中心的服务关闭端点配置 */
@ConditionalOnClass(NacosAutoServiceRegistration.class)
@RestController
@RequestMapping("actuator")
@RequiredArgsConstructor
@Slf4j
public class NacosStopEndpoint {
private final NacosAutoServiceRegistration nacosAutoServiceRegistration;
private final ApplicationContext context;
/** 注销服务后关闭应用前等待的时间(毫秒) */
@Value("${stopService.waitTime:10000}")
private int waitTime;
/**
* 关闭服务 <br>
* 只接收localhost发起的请求
*
* @param request
* @return
*/
@PostMapping("stopService")
public ResponseEntity<Boolean> stopNacosService(HttpServletRequest request) {
//只接受本机请求
if (!request.getServerName().equalsIgnoreCase("localhost")){
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(false);
}
//开启异步线程:先从Nacos注销,等待1000毫秒后,关闭容器
new Thread(
() -> {
log.info("Ready to stop service");
nacosAutoServiceRegistration.stop(); // 一、从Nacos注销
log.info("Nacos instance has been de-registered");
log.info("Waiting {} milliseconds...", waitTime);
try {
Thread.sleep(waitTime); // 二、等待1000毫秒后
} catch (InterruptedException e) {
log.info("interrupted!", e);
}
log.info("Closing application...");
SpringApplication.exit(context); // 三、关闭容器
((ConfigurableApplicationContext) context).close();
})
.start();
return ResponseEntity.ok(true);
}
}
二、服务注销 原理
(一)Eureka 注销服务
Eureka Server 存在三个变量:(registry、readWriteCacheMap、readOnlyCacheMap) 保存服务注册信息
ReadWriteMap 读写缓存
ReadOnlyMap 只读缓存
定时任务
(1)定时任务每 30s 将 readWriteCacheMap 同步至 readOnlyCacheMap
(2)每 60s 清理超过 90s 未续约的节点
(3)Eureka Client 每 30s 从 readOnlyCacheMap 更新服务注册信息
(二)Nacos 注销服务-待续
nacos收到注销请求,如何注销服务?