一、什么是优雅停止?
顾名思义,优雅停止就是优雅地停止正在运行的程序,目的是为了让程序停止的时候尽可能完成还没完成的逻辑,对于一个HTTP服务来说就是尽可能完成还没完成的请求并且不再接收新请求。
反之,如果不优雅停止,程序会将提供HTTP服务的goroutine协程直接中断,当前还没完成的请求也会被粗暴地停止。
二、如何优雅停止?
在Go中要做到优雅停止,核心是捕获停止信号量,再通过通道channel来完成协程间通信和控制。
优雅停止的大概流程如下:
- 捕获进程停止信号,如
SIGINT、SIGTERM - 捕获到信号后,需要在n秒后强制停止进程(足够让进程优雅停止了)
- 停止接收新的请求
- 等待进程中正在进行的请求完成
- 请求全部完成/倒计时n秒技术,进程正式停止
简单代码如下:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
// ...
// 创建错误通道
errChan := make(chan error)
// 监听ctrl+c kill
go func() {
s := make(chan os.Signal, 1)
// 后面信号量不传默认全部
signal.Notify(s, syscall.SIGINT, syscall.SIGTERM)
errChan <- fmt.Errorf("%s", <-s)
}()
// ...
}
完成代码可查看基于Go kit+Gin开发一个Web项目Demo
三、什么是信号量?
信号量是并发编程中常见的一种同步机制,它是一种变量活着抽象数据类型,用于控制并发系统中多个进程对公共资源的访问(原子性)。
1、信号量跟优雅停止有什么关系?
程序的停止实际上是接收到了某种信号量,比如:
- linux下
ctrl+c实际上是发送了一个SIGINT信号(mac下是control+c) kill pid实际上是发送了一个SIGTERM信号kill -9 pid实际上是发送了一个SIGKILL信号(SIGKILL无法被捕获、阻塞或忽略)docker stop实际上是向容器内进程发送了一个SIGTERM信号,10s后再发送一个SIGKILL信号(足够让程序做优雅停止了)
2、信号量有哪些?
