微服务如何实现主动下线?
作者:程序员马丁
在线博客:https://open8gu.com
note
大话面试,技术同学面试必备的八股文小册,以精彩回答应对深度问题,助力你在面试中拿个offer。
回答话术
1. 微服务主动下线
主动下线就是服务停机时先到注册中心注销,拒绝新的请求后,将旧的业务处理完成再停止进程。
在微服务架构中,单考虑优雅停机还不能实现平滑的发布,还需要要考虑主动下线。这个过程尤其需要考虑到服务发现和负载均衡的机制,一旦操作不够平滑,客户调用就会出现 503 或者 500 的情况。
2. 可能出现的问题
如果没有考虑优雅停机或主动下线场景,在发布新老版本或者重启服务时,可能会出现以下几种情况:
- 服务进程已经收到的请求没有运行完成,JVM 就执行了进程中断,导致业务产生影响。
- 未向注册中心发送注销本服务节点就停机了,这个时候网关调用到下线节点,就会出现 500。
- 服务已经向注册中心发送了注销服务实例请求,但是等待时间不够,同样出现 500。
3. 主动下线流程
微服务架构下,常规主动下线流程如下:
- 注销服务实例:当一个服务实例准备关闭时,首先需要从服务发现的注册表中注销或标记为不可用。注册中心会通知到网关和各个服务列表监听者,需要等待监听者都得到了下线的消息并刷新了路由缓存;
- 完成未完成请求:服务实例继续处理已接收但未完成的请求。这确保了这些请求不会因为服务实例的关闭而中断,从而维持了服务的完整性和数据的一致性。也就是优雅停机的业务范畴;
- 停止路由新请求:因为第一步已经注销了自己在注册中心的实例,那么接下来的服务实例将不会再接受新的请求。在微服务架构中,这通常意味着负载均衡器将新的请求会路由到其他健康(或新启动)的服务实例。
问题详解
1. 基于 Nacos 注册中心的服务代码下线实现
Spring 也是基于 JVM 的停机钩子技术实现了自己的停机逻辑,然后调用 doClose 方法来关闭容器。
在 SpringBoot 2.3.0+ 版本里,新增优雅停机配置项。在框架层面即可实现优雅停机,并自动实现上述优雅停机步骤,低版本的解决办法也在后文给出了解决方案。
# 开启优雅停机,默认值:immediate 为立即关闭
server.shutdown=graceful
# 设置缓冲期,最大等待时间,默认:30秒
spring.lifecycle.timeout-per-shutdown-phase=60s
另外,还可以使用 actuator 的 shutdown 端点来实现停机操作,但是不建议在生产环境中使用,除非做好安全措施。