共计 1813 个字符,预计需要花费 5 分钟才能阅读完成。
应用了注册核心的服务集群,各个业务节点通过 RestTemplate、openFeign 进行外部调用时,或者 gateway 做服务转发时,个别会应用从注册核心获取的服务节点列表进行负载路由,而当一个服务节点被暴力敞开时,从注册核心检测到节点处在不衰弱状态,到注册核心将该节点从保护列表中移除,再到其余业务节点将失效节点从本身保护的节点列表缓存数据中移除(定时拉取或播送告诉形式),两头个别会经验数秒时长,这时如果有转向失效节点的新申请,就会不得不等满一个 timeout 周期,而后再反馈回调用端去做下一步是重试还是标记熔断的解决。总之,有异样产生,不优雅。
(伪装有流程图)
现成的有不少优雅敞开服务的计划,比方应用 actuator 的 shutdown 端点、提供入口调用 SpringApplication 的 exit() 静态方法等,不过重要的是在做这些之前要能先被动的将节点从注册核心中下线,而后期待一个适合的时间段之后再敞开服务,这样能多给正在解决中的申请执行实现的机会。
上面是应用了 nacos 的服务下线示例代码:
/** 应用了 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);
new Thread(() -> {log.info("Ready to stop service");
nacosAutoServiceRegistration.stop();
log.info("Nacos instance has been de-registered");
log.info("Waiting {} milliseconds...", waitTime);
try {Thread.sleep(waitTime);
} catch (InterruptedException e) {log.info("interrupted!", e);
}
log.info("Closing application...");
SpringApplication.exit(context);
((ConfigurableApplicationContext) context).close();})
.start();
return ResponseEntity.ok(true);
}
}
这段代码提供了一个 /actuator/stopService
的 POST 端点,调用它即可优雅将服务下线,先把本身从 nacos 注册核心中移除,期待 10 秒后敞开 spring 利用。
接下来,还须要找一个适合的机会来调用这个接口。如果应用了 k8s,能够在容器生命周期中的 prestop 阶段配置一个执行脚本:
lifecycle:
preStop:
exec:
command:
- /bin/sh
- '-c'
- 'curl -X POST''http://localhost:8080/actuator/stopService'';\'
- sleep 30;
其中的 sleep 工夫能够配置的比下线节点之后的等待时间稍长一些即可。