前言

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

实现原理

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

实现优雅重启

package main

import (
"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 信号转发给quit
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此处不会阻塞
<-quit // 阻塞在此,当接收到上述两种信号时才会往下执行
zap.L().Info("Shutdown Server ...")
// 创建一个5秒超时的context
ctx, 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. nginx 平滑重启的实现方法

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

  2. Gong服务实现平滑重启分析

    平滑重启是指能让我们的程序在重启的过程不中断服务,新老进程无缝衔接,实现零停机时间(Zero-Downtime)部署: 平滑重启是建立在优雅退出的基础之上的,之前一篇文章介绍了相关实现:Golang中 ...

  3. yarn关于app max attempt深度解析,针对长服务appmaster平滑重启

    在YARN上开发长服务,需要注意fault-tolerance,本篇文章对appmaster的平滑重启的一个参数做了解析,如何设置可以有助于达到appmaster平滑重启. 在yarn-site.xm ...

  4. node.js cluster多进程、负载均衡和平滑重启

    1 cluster多进程 cluster经过好几代的发展,现在已经比较好使了.利用cluster,可以自动完成子进程worker分配request的事情,就不再需要自己写代码在master进程中rob ...

  5. nginx平滑重启与平滑升级的方法

    如何实现nginx平滑重启与平滑升级? 平滑重启 kill -HUP `cat /usr/local/www/nginx/logs/nginx.pid` 平滑升级nginx: cd /yujialin ...

  6. Nginx启动、停止与平滑重启

    如何启动Nginx:/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf 停止Nginx:可以发送向通信号给Nginx主进程的 ...

  7. Nginx的平滑重启和平滑升级

    一,Nginx的平滑重启如果改变了Nginx的配置文件(nginx.conf),想重启Nginx,可以发送系统信号给Nginx主进程的方式来进行.在重启之前,要确认Nginx配置文件的语法是正确的. ...

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

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

  9. Apache和Nginx平滑重启

    之前修改了服务器配置都是简单粗暴的用restart重启apache/nginx,据说这样不好.需要平滑重启服务器,避免重启时打断用户行为.然后就根据官方文档了解了一下平滑重启的命令.本文根据Apach ...

随机推荐

  1. CF1381B Unmerge(位运算的作用)

    题目大意: 给定长度为 \(2n\) 的排列 \(p\) .确定是否存在两个数组 \(a\) 和 \(b\) ,每个数组的长度都为 \(n\) ,并且没有相等的元素,使得 \(p = \operato ...

  2. 从零开始搭建Vue2.0项目(一)之快速开始

    从零开始搭建Vue2.0项目(一)之项目快速开始 前言 该样板适用于大型,严肃的项目,并假定您对Webpack和有所了解vue-loader.确保还阅读vue-loader的文档,了解常见的工作流程配 ...

  3. 清北学堂 2020 国庆J2考前综合强化 Day5

    目录 1. 题目 T1 a 题目描述 Sol T2 b 题目描述 Sol T3 c 题目描述 Sol T4 d 题目描述 Sol 2. 算法 - 贪心 & 数学 1. 贪心 2. 数学 2.1 ...

  4. Modbus的设备怎么对接华为云 使用金鸽BL100只需要5步

    BL100是一款高性价比的Modbus转MQTT网关支持一键对接阿里云.华为云. BL100将Modbus串口设备的数据上传至华为云只需要简单五步 第一步.首先将Modbus的设备通过RS485接上M ...

  5. Odoo14 OWL 如何访问model方法和res_id

    首先OWL是Odoo14版本新加的功能. 因为是新加的所以并没有太多的说明文档,包括英文板文档也没有:所以你要用它再没有更详细的文档之前你得自己去看源码. 注意owl是没有do_action函数给你跳 ...

  6. Docker容器网络配置

    Docker容器网络配置 1.Linux内核实现名称空间的创建 1.1 ip netns命令 可以借助ip netns命令来完成对 Network Namespace 的各种操作.ip netns命令 ...

  7. 巨变!a16z 关于新一代数据基础设施架构的深度洞察

    点击上方 蓝字关注我们 来源 | a16z 作者 | Matt Bornstein, Martin Casado,Jennifer Li 翻译 | 夕颜 作为未来最重要的基础设施之一,数据正在成为各行 ...

  8. Bert不完全手册7. 为Bert注入知识的力量 Baidu-ERNIE & THU-ERNIE & KBert

    借着ACL2022一篇知识增强Tutorial的东风,我们来聊聊如何在预训练模型中融入知识.Tutorial分别针对NLU和NLG方向对一些经典方案进行了分类汇总,感兴趣的可以去细看下.这一章我们只针 ...

  9. Word 文字错乱,接收方显示的字体与原版不一直

    原版文档使用字体的不是电脑上自带的常规字体,比如,黑软雅黑.黑体.宋体等字体.当把文档发送给其他人查阅时,字体发生了错乱,也就是字体与原版字体不一致. 需要打开"选项"设置,把非常 ...

  10. JS的简介

    JS式JavaScript的简称,它是一门弱语言,它可以实现让网页动起来 JS的构成 核心(ECMAScript) 文档对象模型(DOM)-- Document Object  Module 浏览器对 ...