前言

优雅关机就是服务端关机命令发出后不是立即关机,而是等待当前还在处理的请求全部处理完毕后再退出程序,是一种对客户端友好的关机方式。而执行Ctrl+C关闭服务端时,会强制结束进程导致正在访问的请求出现问题。

实现原理

Go 1.8版本之后, http.Server 内置的 Shutdown() 方法就支持优雅地关机,说明一下Shutdown工作的机制:当程序检测到中断信号时,我们调用http.server种的shutdown方法,该方法将阻止新的请求进来,同时保持当前的连接,知道当前连接完成则终止程序!

实现优雅重启

package mainimport ("context""fmt""github.com/spf13/viper""go.uber.org/zap""log""net/http""os""os/signal""syscall""time"
)func main() {//启动服务(优雅关机)srv := &http.Server{Addr:    fmt.Sprintf(":%d", viper.GetInt("app.port")),Handler: r,}go func() {// 开启一个goroutine启动服务if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {log.Fatalf("listen: %s\n", err)}}()// 等待中断信号来优雅地关闭服务器,为关闭服务器操作设置一个5秒的超时quit := make(chan os.Signal, 1) // 创建一个接收信号的通道// kill 默认会发送 syscall.SIGTERM 信号// kill -2 发送 syscall.SIGINT 信号,我们常用的Ctrl+C就是触发系统SIGINT信号// kill -9 发送 syscall.SIGKILL 信号,但是不能被捕获,所以不需要添加它// signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 信号转发给quitsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此处不会阻塞<-quit                                               // 阻塞在此,当接收到上述两种信号时才会往下执行zap.L().Info("Shutdown Server ...")// 创建一个5秒超时的contextctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()// 5秒内优雅关闭服务(将未处理完的请求处理完再关闭服务),超过5秒就超时退出if err := srv.Shutdown(ctx); err != nil {zap.L().Fatal("Server Shutdown: ", zap.Error(err))}zap.L().Info("Server exiting")
}

实现平滑重启

import ("log""net/http""time""github.com/fvbock/endless""github.com/gin-gonic/gin"
)func main() {router := gin.Default()router.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "hello xiaosheng !")})// 默认endless服务器会监听下列信号:// syscall.SIGHUP,syscall.SIGUSR1,syscall.SIGUSR2,syscall.SIGINT,syscall.SIGTERM和syscall.SIGTSTP// 接收到 SIGHUP 信号将触发`fork/restart` 实现优雅重启(kill -1 pid会发送SIGHUP信号)// 接收到 syscall.SIGINT或syscall.SIGTERM 信号将触发优雅关机// 接收到 SIGUSR2 信号将触发HammerTime// SIGUSR1 和 SIGTSTP 被用来触发一些用户自定义的hook函数if err := endless.ListenAndServe(":8080", router); err!=nil{log.Fatalf("listen: %s\n", err)}log.Println("Server exiting...")

测试

我们通过执行kill -1 pid命令发送syscall.SIGINT来通知程序优雅重启,具体做法如下:

  • 打开终端,go build -o graceful_restart编译并执行./graceful_restart,终端输出当前pid(假设为43682)
  • 将代码中处理请求函数返回的hello gin!修改为hello q1mi!,再次编译go build -o graceful_restart
  • 打开一个浏览器,访问127.0.0.1:8080/,此时浏览器白屏等待服务端返回响应。
  • 在终端迅速执行kill -1 43682命令给程序发送syscall.SIGHUP信号
  • 等第3步浏览器收到响应信息hello gin!后再次访问127.0.0.1:8080/会收到hello q1mi!的响应。
  • 在不影响当前未处理完请求的同时完成了程序代码的替换,实现了优雅重启。

但是需要注意的是,此时程序的PID变化了,因为endless 是通过fork子进程处理新请求,待原进程处理完当前请求后再退出的方式实现优雅重启的。所以当你的项目是使用类似supervisor的软件管理进程时就不适用这种方式了。

总结

无论是优雅关机还是优雅重启归根结底都是通过监听特定系统信号,然后执行一定的逻辑处理保障当前系统正在处理的请求被正常处理后再关闭当前进程。使用优雅关机还是使用优雅重启以及怎么实现,这就需要根据项目实际情况来决定了。

以上就是使用go如何优雅关机和平滑重启 的详细内容,更多关于go关机重启 的内容请关注博主的其它相关文章!

Go实现优雅关机与平滑重启相关推荐

  1. Go项目实现优雅关机与平滑重启

    Demo快速上手 优雅关机 package mainimport ("context""github.com/gin-gonic/gin""log&q ...

  2. java jar包 平滑重启,nginx 平滑重启的实现方法

    一.背景 在服务器开发过程中,难免需要重启服务加载新的代码或配置,如果能够保证server重启的过程中服务不间断,那重启对于业务的影响可以降为0.最近调研了一下nginx平滑重启,觉得很有意思,记录下 ...

  3. php:php-fpm平滑重启为什么无效

    一.问题 今天修改了fpm一些配置,需要上线重启fpm,但是发现一瞬间出现很多502的错误请求,查看日志发现以下错误 fpm:重启日志 nginx:错误日志 2023/04/23 15:19:00 [ ...

  4. Golang服务平滑重启

    与重载配置相同的是我们也需要通过信号来通知server重启,但关键在于平滑重启,如果只是简单的重启,只需要kill掉,然后再拉起即可.平滑重启意味着server升级的时候可以不用停止业务. 我们先来看 ...

  5. Spring Boot 2.3.0 发布:支持Java14、打包Docker镜像、优雅关机配置...

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | 冷冷gg 来源 | https://www.oschin ...

  6. Nginx 的启动、停止、平滑重启、信号控制和平滑升级

    Nginx 的启动          假设 nginx 安装在 /usr/local/nginx 目录中,那么启动 nginx 的命令就是: [root@localhost ~]# /usr/loca ...

  7. Linux的关机命令和重启命令

    Linux的关机命令和重启命令 文章目录: 1 关机命令 2 重启命令 : 1 关机命令 1.halt :立刻关机(一般加-p 关闭电源) 2.poweroff: 立刻关机 3.shutdown -h ...

  8. Nginx的平滑重启和升级

    Nginx的平滑重启和升级 Nginx平滑重启 如果修改了Nginx的配置文件(nginx.conf),想要重启Nginx,同样通过发送系统信号给Nginx的主进程的方式. 但是,重启之前,需要确认N ...

  9. supervisor 重启_Golang HTTP服务平滑重启及升级

    Golang HTTP服务在上线时,需要重新编译可执行文件,关闭正在运行的进程,然后再启动新的运行进程.对于访问频率比较高的面向终端用户的产品,关闭.重启的过程中会出现无法访问(nginx表现为502 ...

最新文章

  1. Linux下的一个图形管理工具webmin
  2. Java.util包中常用的类
  3. linux 文件系统覆盖目录,Linux内核裁减及根文件系统定制
  4. memcached 使用 java_java中Memcached的使用(包括与Spring整合)
  5. wpf: DataGridTextColumn 数字格式显示,编辑时取消格式(StringFormat)
  6. Exchange 企业邮件与Windows安全应用 — Exchange 2007 收件人管理
  7. C++中XMLHTTPRequest异步使用onreadystatuschange
  8. 查找某节点的所有祖先☆
  9. linux中内存挂载到目录下
  10. string和wstring相互转换
  11. [Android疑难杂症]动态设置TextView的width不起作用
  12. mysql添加序列触发器_在Oracle中创建自增序列之触发器
  13. JCE, Java Cryptography Extension
  14. JPress v2.0-rc.6 发布,新增 Java 插件的在线升级功能
  15. 火狐firebug和firepath插件安装
  16. vue3结合element-plus实现标签手动标注效果
  17. js 实现通过身份证获取年龄
  18. wordpress采集插件自动采集伪原创免费插件
  19. 计算机职高会考知识,高职考试语文基础知识
  20. 随机展示一个汉字,可以用来让一二年级孩子识字

热门文章

  1. css网格_使用CSS网格构建的澳大利亚初创企业的周期表
  2. 【转】评估类型 评估类别 评估类
  3. Oracle数据库系统管理与运维 | 项目案例
  4. 上海亚商投顾:两市缩量微涨,数字经济概念全线走强
  5. 数字孪生制造:数字孪生技术在制造业可视化中的实践与挑战
  6. 低成本 汉朔 墨水屏 msp430g2553主控 改造完整案例
  7. android dismiss方法,Android编程之DialogFragment源码详解(一)注:对 dismissAllowingStateLoss()理解...
  8. 基于 librosa 的 LFCC 和 CQCC 特征提取
  9. 阿尔·里斯-市场营销的22条法则(22条商规)-22
  10. 生成对抗网络(GAN)详解与实例