优雅下线

本文主要介绍优雅下线的基本步骤和使用说明

优雅下线

背景

在稳定生产的过程中,容器调度完全由 k8s 管控,微服务治理完全由服务框架或者运维人员进行维护和管理。而在发布新版本,或者扩缩容的场景下,会终止旧的容器实例,并使用新的容器实例进行替换,对于承载高流量的线上生产环境,这个替换过程的衔接如果不合理,将在短时间内造成大量的错误请求,触发报警甚至影响正常业务。对于体量较大的厂家,发布过程出现问题所造成的损失会是巨大的。 因此,优雅下线的诉求被提出。这要求服务框架在拥有稳定服务调用能力、传统服务治理能力的基础之上,应当提供服务下线过程中稳定的保障,从而减少运维成本,提高应用稳定性。

特性说明

在一次完整的RPC调用过程中,中间服务往往充当服务提供者和服务消费者两个角色。中间服务在接收到来自上游服务的请求之后,处理请求得到结果返回给上游服务,然后根据需要调用下游服务提供的接口使用下游服务。因此优雅下线功能需要兼顾服务作为服务提供者和服务消费者两侧的稳定性,具体可以分为以下几步:

  1. 向注册中心进行反注册,销毁在注册中心注册的服务信息
  2. 作为服务提供者,要等待一段时间,保证客户端成功更新服务信息以及上游任务请求处理完毕,然后拒绝接收新的请求
  3. 作为服务消费者,要等待一段时间,保证使用下游服务的请求得到响应,然后取消对注册中心的订阅
  4. 销毁对下游任务的引用,销毁对外提供服务暴露的端口
  5. 执行用户的自定义回调操作

通过以上步骤,可以保证dubbo-go服务实例安全平稳停止,不对进行中的业务产生影响。

注意:取消对注册中心的订阅不能在步骤1中执行,这是因为中间服务对下游服务发送请求的时候可能存在下游服务信息的变动

使用场景

对dubbo-go实例使用kill pid命令停止实例

使用方式

以下是在yaml配置文件中,用户可以自定义的配置

  • 作为服务提供者,dubbo-go实例下线时需要等待客户端成功更新服务信息,这段时间在配置中对应的字段为consumer-update-wait-time,默认3s
  • 作为服务提供者,dubbo-go实例下线时如果来自上游任务的请求暂未处理完毕,需要等待上游任务请求处理完毕。作为服务消费者,dubbo-go实例需要等待对下游的请求收到回复。这段时间在配置中对应的字段为step-timeout,默认3s
  • 作为服务提供者,dubbo-go实例下线时如果来自上游任务的请求已经处理完毕,需要等待一段窗口时间,如果在窗口时间内没有接收到新的请求,再执行后续步骤。这段时间在配置中对应的字段为offline-request-window-timeout,默认0s
  • 用户可以自定义是否开启优雅下线功能,在配置中对应的字段为internal-signal,默认开启。
  • dubbo-go实例在优雅下线过程中可能因为异常导致卡死,在配置中可以配置超时时间,实例在超时之后强制关闭。这在配置中对应的字段为timeout,默认60s
dubbo:
  shutdown:
    timeout:60
    step-timeout:3
    consumer-update-wait-time:3
    internal-signal:true
    offline-request-window-timeout:0

此外,如果用户希望在下线逻辑彻底结束后,执行一些自定义的回调操作,可以使用如下代码

extension.AddCustomShutdownCallback(func() {
        // 用户自定义操作
    })

参考资料

【Dubbo-go 优雅上下线的设计与实践】