阅读 591

springboot-nacos注册中心优雅停服方案

这是我参与更文挑战的第9天,活动详情查看: 更文挑战

在系统生命周期中, 免不了要做升级部署, 对于关键服务, 我们应该能做到不停服务完成升级。另外服务的SLA标准一般都要在四个9以上所以对于优雅停服的需要就十分有必要了。

最开始的构想

我们服务用到的技术栈是springboot2.0、springcloud2.0、nacos。一开始我们想到一种方案,在slb配置上所有服务器的健康检查端口,每个项目的健康检查地址修改为不一样,通过域名来转发到每台服务器。方案如下图所示:

image.png

如上图就有几个问题:

  1. 集群多,服务器数量多。目前线上集群有20个左右,服务器数量几百台。每一台服务器都要录入到slb,有增加或者删减都需要去维护一次。工作量很大,且风险也很大。
  2. 服务发版的时候,如果sla正好检测到发版的服务器,服务质量就会下降。

第一个问题的解决,我们考虑通过脚本定时更新slb(slb有相关api接口)。第二个问题,发版是经常性的操作,有需求发布或者bugfix都需要发版,并不能避免或者减少。就需要引入优雅停机,不影响接口服务,但是还需要操作slb发版前先offline,发版后再online。

看似问题都有解决方案,但是我们既然有了网关,为什么还要多此一举在slb上再维护一套服务器信息,并且发版还需要再维护slb,如果slb有多个或者以后要做迁移就又得修改。后来就考虑健康检查端口与应用端口合并,或者在应用端口提供健康检查接口。经验证两个端口不能合并,那就尝试应用端口提供健康检查接口。就需要翻actuator组件源码 ,网上资料很多,就不在此赘述。

actuator对外输出信息代码主要是以下代码:

image.png

于是我们照猫画虎自定义的健康检查接口

image.png

或者可以使用调用健康检查接口的形式把数据透传过来

image.png

以上方法只适用于微服务的服务模块,对于网关、注册中心并不适用。因为网关不仅在微服务的管理之下,还要挂在slb下面,网关在发版的同时需要维护slb online、offline。具体api接口参考slb文档。

微服务优雅停机最后方案

官方提供优雅停机方式:actuator/shutdown,在进行调研停机的时候发现两个问题:

  1. 可以正常停止应用,不再提供服务,注册中心的服务下线。但是grep进程,发现进程还是存在。

  2. 微服务ribbon调用依然会请求到关闭的服务器上,直到异常熔断或者ribbon更新服务列表。

第一个问题是由于应用中的依赖中存在ScheduledExecutor没有被应用上下文关闭,这个对象会使JVM保持存活,需要在代码中显式关闭对应的ScheduledExecutor。很多应用没有显式使用ScheduledExecutor,应该是spring框架内部有依赖,比如ribbon刷新微服务列表就使用到了定时器。去掉spring cloud相关的依赖,再次使shutdown就可以关闭掉进程。

第二个问题由于ribbon获取服务列表机制是通过定时任务拉取,并非注册中心主动通知。使用shutdown在springcloud做不到优雅停机了,就需要另辟蹊径。根据现有状况要做到优雅停机,需要满足两点:

  • 停机前先给注册中心发送通知,某台服务器要将下线,各个微服务ribbon更新服务列表后就不能再调用了给注册中心发送下线信号后,要确保没有请求后才能终止服务。

  • nacos控台对每个微服务有“下线”功能,对应接口可以使用nacos/v1/ns/instance (需要指定服务名、应用ip、端口)接口操作下线,

image.png

或者使用http://ip:port/service-registry?status=DOWN 进行通知(为方便配置脚本,尽量使用后面这种方式。如果注册中心为eureka,还需要在应用发布后进行UP操作,nacos则无需此操作)

注意此处有坑:

ribbon刷新服务列表默认时间是30s,可以通过参数:ribbon.ServerListRefreshInterval 调整为10s。这样最多10s后每个微服务都能更新到最新的可用服务列表。

文章分类
后端
文章标签