06|重启:如何进行优雅关闭?
叶剑峰
该思维导图由 AI 生成,仅供参考
你好,我是轩脉刃。
通过前面几节课的学习,我们已经能启动一个按照路由规则接收请求、进入控制器计算逻辑的服务器了。
但是,在实际业务开发过程中,功能和需求一定是不断迭代的,在迭代过程中,势必需要重启服务,这里的重启就是指一个关闭、启动进程的完成过程。
目前所有服务基本都无单点问题,都是集群化部署。对一个服务的关闭、启动进程来说,启动的流程基本上问题不大,可以由集群的统一管理器,比如 Kubernetes,来进行服务的启动,启动之后慢慢将流量引入到新启动的节点,整个服务是无损的。
但是在关闭服务的过程中,要考虑的情况就比较复杂了,比如说有服务已经在连接请求中怎么办?如果关闭服务的操作超时了怎么办?所以这节课我们就来研究下如何优雅关闭一个服务。
如何优雅关闭
什么叫优雅关闭?你可以对比着想,不优雅的关闭比较简单,就是什么都不管,强制关闭进程,这明显会导致有些连接被迫中断。
或许你并没有意识到这个问题的严重性,不妨试想下,当一个用户在购买产品的时候,由于不优雅关闭,请求进程中断,导致用户的钱包已经扣费了,但是商品还未进入用户的已购清单中。这就会给用户带来实质性的损失。
所以,优雅关闭服务,其实说的就是,关闭进程的时候,不能暴力关闭进程,而是要等进程中的所有请求都逻辑处理结束后,才关闭进程。按照这个思路,需要研究两个问题“如何控制关闭进程的操作” 和 “如何等待所有逻辑都处理结束”。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了如何在Golang中实现优雅关闭服务的方法。通过控制关闭进程的操作和等待所有逻辑处理结束,可以确保服务重启过程中不会影响用户体验。文章首先讨论了如何捕获信号并使用os/signal库的Notify方法来实现对信号量的控制。其次,介绍了在Golang 1.8版本之后引入的net/http的server.Shutdown方法,该方法可以阻塞当前Goroutine,并在所有连接请求都结束后才继续执行。通过对server.Shutdown源码的解析,读者可以了解其实现原理和细节。最后,通过验证和小结,读者可以加深对优雅关闭服务的理解,并在实际应用中进行相应的修改和控制。整体而言,本文内容详实,逻辑清晰,对于Golang开发者来说是一篇有价值的技术文章。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《手把手带你写一个 Web 框架》,新⼈⾸单¥59
《手把手带你写一个 Web 框架》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(15)
- 最新
- 精选
- The brain is a good thing收到结束信号后,还会接受新的请求吗,这样无限请求进来是不是结束不了?
作者回复: 不会的,有个inShutdown的标记位,标记了就没有请求进来了
2023-02-20归属地:广东 - 友ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 即可
作者回复: yes,u are right
2021-12-03 - 安喆||工程师||电器技术咨询...老师,这个课程的开发环境是什么,如何搭建?
编辑回复: 第1节课有详细说明,Golang 源码的版本是 1.15.5,实现的步骤就是按文章顺序读,代码可以参考文中的代码和GitHub地址。
2021-09-24 - 贺鹏quit := make(chan os.Signal) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT) <-quit ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("server shutdown error:", err) } select { case <-ctx.Done(): log.Println("timeout of 5 seconds") } log.Println("server exiting")2021-09-2626
- void“它们发送的信号是进入 main 函数的,即只有 main 函数所在的 Goroutine 会接收到,所以必须在 main 函数所在的 Goroutine 监听信号。” 这个说法不太对吧? 别的goroutine里也是可以收到信号的,只不过在主协程里接收信息比较容易收尾后退出整个进程。2021-11-125
- 陈亦凡第一节已经值回票价,希望老师快点更新2021-09-264
- Geek_5244fa必须在 main 函数所在的 Goroutine 监听信号吗?在另一个 goroutine 理处理也可以吧: func main() { done := make(chan struct{}) go func() { quit := make(chan os.Signal) signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT) fmt.Printf("singal %v", <-quit) close(done) }() <-done }2021-09-243
- 语法糖"10s 内在控制台执行 Ctrl+C 关闭程序观察控制台程序是否不会立刻结束,而是在 10s 后结束" 前提是请求开始到ctrl+c 之间超过5s, 否则留给剩余请求的时间大于5s, 超过了服务器关闭的最大超时5s, 会强制关闭服务器2022-10-15归属地:江苏12
- 芒果少侠自己的答案,看完后发现skyhackvip同学的写法似乎更好,不用多起一个协程 quitSig := make(chan os.Signal) signal.Notify(quitSig, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM) <-quitSig cancelableCtx, cancel := context.WithCancel(context.Background()) inAdvance := time.After(time.Second * 5) go func() { select { case <-inAdvance: log.Print("server shutdown exceeds timeout") cancel() } }() if err := server.Shutdown(cancelableCtx); err != nil { log.Fatal("server shutdown failed: ", err) }2021-10-031
- Geek_eebc7ffunc mian(){ .... cancelContext, _ := context.WithTimeout(context.Background(), time.Second*5) if err := server.Shutdown(cancelContext); err != nil { log.Fatal("Server Shutdown:", err) } }2023-06-06归属地:俄罗斯
收起评论