← 中文资源

简体中文版本

负载均衡后面的优雅关闭

先让 readiness 探针返回 503,等待负载均衡停止路由,再用带超时的 Shutdown 排空在途 HTTP 请求,避免下线时切断正在处理的调用。

阅读英文原文

功能说明

示例演示负载均衡后面的优雅下线:收到终止信号后先把 /readyz 置为 503,让负载均衡停止把新流量路由进来;等待一段传播时间,再用独立的超时上下文调用 server.Shutdown,等待在途请求完成。这样既不会切断正在处理的请求,也不会在探针仍显示就绪时突然关闭监听。

关键代码

<-ctx.Done()
ready.Store(false)
fmt.Println("readiness probe now fails; waiting for load balancers to stop routing")
time.Sleep(100 * time.Millisecond)

shutdownCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
	fmt.Println("shutdown:", err)
	return
}

ready 用 atomic.Bool 保存,处理探针的 goroutine 与主协程并发读写不需要额外加锁。

使用注意

  • 探针传播时间取决于负载均衡配置,示例的 100 毫秒只是演示值,生产环境应大于健康检查周期。
  • 在等待传播期间服务仍然接受请求,只是探针返回失败;这依赖负载均衡真正尊重 readiness。
  • Shutdown 不会取消正在执行的请求上下文,慢处理器需要自己监听 r.Context()。
  • 必须给 Shutdown 单独设置超时,否则异常请求可能让进程一直不退出。
  • 容器编排的宽限期应覆盖“传播等待 + 排空时间”,否则进程会被 SIGKILL。

验证方式

运行示例,客户端应收到 200 和 finished,随后依次打印探针失败、等待路由撤销、服务排空完成。可以把传播等待改为 0,观察探针与关闭几乎同时发生;把处理时间改成 3 秒、关闭超时改成 100 毫秒,可验证强制超时分支。