乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

    • Golang基础知识

    • Golang进阶知识

    • Golang常用包

    • Gin框架

      • 安装
      • gin路由
      • 请求数据参数绑定
      • gin渲染
      • 使用模板渲染
      • 静态文件的使用
      • 数据渲染
      • gin重定向
      • gin同步和异步
      • go中间件
      • 会话保持
      • 文件上传
      • JWT的简单使用
      • 模板函数
      • Swagger
      • API访问控制
      • 常见的应用中间件
      • 应用配置管理
      • 优雅停止与重启
        • 遇到问题
        • 解决方法
          • 信号定义
          • 支持的信号
        • 实现
          • 目的
          • 流程
          • 实现
      • 集成Casbin进行访问权限控制
  • AIOps

  • Python

  • DevOps

  • 专栏
  • Golang
  • Gin框架
乔克
2025-07-19
目录

优雅停止与重启

在开发完成应用程序后,即可将其部署到测试、预发布或生产环境中,这时又涉及一个问题,即持续集成。简单来说,开发人员需要关注的是这个应用程序是不断地进行更新和发布的,也就是说,这个应用程序在发布时,很可能某客户正在使用这个应用。如果直接硬发布,就会造成客户的行为被中断。

# 遇到问题

为了避免这种情况的发生,我们希望在应用更新或发布时,现有正在处理既有连接的应用不要中断,要先处理完既有连接后再退出。而新发布的应用在部署上去后再开始接收新的请求并进行处理,这样即可避免原来正在处理的连接被中断的问题。

# 解决方法

想要解决这个问题,目前最经典的方案就是通过信号量的方式来解决。

# 信号定义

信号是 UNIX、类 UNIX,以及其他 POSIX 兼容的操作系统中进程间通信的一种有限制的方式。

它是一种异步的通知机制,用来提醒进程一个事件(硬件异常、程序执行异常、外部发出信号)已经发生。当一个信号发送给一个进程时,操作系统中断了进程正常的控制流程。此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则执行默认的处理函数。

# 支持的信号

我们可以通过 kill-l 查看系统中所支持的所有信号,如下:

 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 2) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
3) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
4) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
5) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
6) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
7) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
8) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
9) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
10) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
11) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
12) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
13) SIGRTMAX-1	64) SIGRTMAX

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 实现

# 目的

  • 不关闭现有连接(正在运行中的程序)
  • 新的进程启动并替代旧进程
  • 新的进程接管新的连接
  • 连接要随时响应用户的请求。当用户仍在请求旧进程时要保持连接,新用户应请求新进程,不可以出现拒绝请求的情况

# 流程

  • 替换可执行文件或修改配置文件
  • 发送信号量 SIGHUP
  • 拒绝新连接请求旧进程,保证正在处理的连接正常
  • 启动新的子进程
  • 新的子进程开始 Accept
  • 系统将新的请求转交新的子进程
  • 旧进程处理完所有旧连接后正常退出

# 实现

回到项目的 main.go 文件,对该项目进行改造,使其支持优雅重启和停止,修改代码如下:

func main() {
	gin.SetMode(global.ServerSetting.RunMode)
	router := routers.NewRouter()
	//log.Fatal("开始启动")
	s := &http.Server{
		Addr:              ":" + global.ServerSetting.HttpPort,
		Handler:           router,
		TLSConfig:         nil,
		ReadTimeout:       global.ServerSetting.ReadTimeout,
		ReadHeaderTimeout: 0,
		WriteTimeout:      global.ServerSetting.WriteTimeout,
		IdleTimeout:       0,
		MaxHeaderBytes:    1 << 20,
		TLSNextProto:      nil,
		ConnState:         nil,
		ErrorLog:          nil,
		BaseContext:       nil,
		ConnContext:       nil,
	}

	go func() {
		err := s.ListenAndServe()
		if err !=nil && err !=http.ErrServerClosed {
			log.Fatalf("s.ListenAndServer err: %v",err)
		}
	}()
	// 等待中断信号
	quit := make(chan  os.Signal)
	// 接收syscall.SIGINT和syscall.SIGTERM信号
	signal.Notify(quit,syscall.SIGINT,syscall.SIGTERM)
	<-quit
	log.Fatalf("Shuting down server ......")

	// 最大时间控制,用于通知该服务端它有5秒的时间来处理原请求
	ctx,cancel := context.WithTimeout(context.Background(),5*time.Second)
	defer cancel()
	if err := s.Shutdown(ctx);err !=nil{
		log.Fatalf("Server force to shutdown: %v",err)
	}
	log.Fatalf("Server existing ......")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

作者:乔克

本文链接:https://jokerbai.com

版权声明:本博客所有文章除特别声明外,均采用 署名-非商业性-相同方式共享 4.0 国际 (CC-BY-NC-SA-4.0) 许可协议。转载请注明出处!

上次更新: 2025/07/19, 09:17:41
应用配置管理
集成Casbin进行访问权限控制

← 应用配置管理 集成Casbin进行访问权限控制→

最近更新
01
使用 Generic Webhook Trigger 触发 Jenkins 多分支流水线自动化构建
07-19
02
使用Zadig从0到1实现持续交付平台
07-19
03
基于Jira的运维发布平台
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式