应用了注册核心的服务集群,各个业务节点通过RestTemplate、openFeign进行外部调用时,或者gateway做服务转发时,个别会应用从注册核心获取的服务节点列表进行负载路由,而当一个服务节点被暴力敞开时,从注册核心检测到节点处在不衰弱状态,到注册核心将该节点从保护列表中移除,再到其余业务节点将失效节点从本身保护的节点列表缓存数据中移除(定时拉取或播送告诉形式),两头个别会经验数秒时长,这时如果有转向失效节点的新申请,就会不得不等满一个timeout周期,而后再反馈回调用端去做下一步是重试还是标记熔断的解决。总之,有异样产生,不优雅。
(伪装有流程图)
现成的有不少优雅敞开服务的计划,比方应用actuator的shutdown端点、提供入口调用SpringApplication的exit()静态方法等,不过重要的是在做这些之前要能先被动的将节点从注册核心中下线,而后期待一个适合的时间段之后再敞开服务,这样能多给正在解决中的申请执行实现的机会。
上面是应用了nacos的服务下线示例代码:
/** 应用了nacos注册核心的服务敞开端点配置 */@ConditionalOnClass(NacosAutoServiceRegistration.class)@RestController@RequestMapping("actuator")@RequiredArgsConstructor@Slf4jpublic 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工夫能够配置的比下线节点之后的等待时间稍长一些即可。