使用Air 热重载及平滑重启实践分享

☁️ 热重载 Go 应用的工具,官方介绍 | 项目地址

1. 前言

由于golang属于静态型语言,它编写的业务代码或者文件发生更改就需要重新编译运行项目,而在其它动态编译语言里这算是一大痛点。如果项目比较大,编译阶段很耗时间,比较影响开发跟测试效率。

所以今天笔者来介绍三个小妙招(热重载、平滑重启),这些技术通常一起使用,以确保开发、部署和关闭应用程序时,能够平滑、安全地进行操作,最大程度地减少对用户和客户端影响。

1.1 热重载(Hot ReLoading)

热重载是指在应用程序运行期间动态加载新的代码或资源。

1.2 平滑重启(Graceful Restart)

平滑重启是指在应用程序运行时,通过air 重新启动新的实例来替代旧实例。Golang的os/signal包可用于优雅地处理信号并实现平滑重启。通过捕获信号( CTRL + C ),例如SIGTERMSIGINT,确保所有正在进行的操作都能够完成,而不是强制性地立即终止。在接收到信号时触发关闭操作。此过程通常包括等待尚未完成的请求完成,释放资源,最终使应用程序平稳退出。从而实现零停机时间的更新。

2. Air介绍

Air 是为 Go 应用开发设计的另外一个热重载的命令行工具。只需在你的项目根目录下输入 air,然后把它放在一边,专注于你的代码即可。

注意:该工具与生产环境的热部署无关。

3. Air安装

3.1 Golang Tools Install

进入项目的根目录,使用 Go 的版本为 1.16 或更高执行:

go install github.com/cosmtrek/air@latest

我们找到我们的go install安装的air目录

笔者GOPATH目录地址是(若是不知道请自行百度):/home/liang/goprojects

然后把这个 air 二进制可执行文件做软连接映射到 bin 目录下(便于全局调度使用)

sudo ln -s /home/liang/goprojects/bin/air /usr/bin/air

打开一个新的 terminal 控制台,输入 air -v 检查 air 是否安装成功,如下图:

3.2 Shell Install(没试过)

# 安装在 ./bin/ 路径下
curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s
air -v

4. Air热重载

新建一个 go 项目,并在项目的根目录下创建一个 .air.conf 文件,复制air安装目录下 air_example.toml 文件里的内容到创建的 .air.conf 文件中

# [Air](https://github.com/cosmtrek/air) TOML 格式的配置文件

# 工作目录
# 使用 . 或绝对路径,请注意 `tmp_dir` 目录必须在 `root` 目录下
root = "."
tmp_dir = "tmp"

[build]
# 只需要写你平常编译使用的shell命令。你也可以使用 `make`
# Windows平台示例: cmd = "go build -o tmp\main.exe ."
cmd = "go build -o ./tmp/main ."
# 由`cmd`命令得到的二进制文件名
# Windows平台示例:bin = "tmp\main.exe"
bin = "tmp/main"
# 自定义执行程序的命令,可以添加额外的编译标识例如添加 GIN_MODE=release
# Windows平台示例:full_bin = "tmp\main.exe"
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
# 监听以下文件扩展名的文件.
include_ext = ["go", "tpl", "tmpl", "html"]
# 忽略这些文件扩展名或目录
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
# 监听以下指定目录的文件
include_dir = []
# 排除以下文件
exclude_file = []
# 如果文件更改过于频繁,则没有必要在每次更改时都触发构建。可以设置触发构建的延迟时间
delay = 1000 # ms
# 在杀死进程之前发送中断信号(windows不支持此功能)
send_interrupt = true
# 发送中断信号后的延迟
kill_delay = 120000000000 # ms
# 发生构建错误时,停止运行旧的二进制文件。
stop_on_error = true
# air的日志文件名,该日志文件放置在你的`tmp_dir`中
log = "air_errors.log"

[log]
# 显示日志时间
time = true

[color]
# 自定义每个部分显示的颜色。如果找不到颜色,使用原始的应用程序日志。
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

[misc]
# 退出时删除tmp目录
clean_on_exit = true

之后我们创建一个 main.go 文件,并编写一个简单的gin 项目

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	// 初始化Gin框架
	r := gin.Default()
	// 定义路由
	r.GET("/api/resource", func(c *gin.Context) {
		c.JSON(200, gin.H{"message": "你好 欢迎使用 air 热重载"})
	})

	r.Run(":8080")
}

4.1 运行

运行的时候,不需要执行 go run mian.go 这样的命令了,而是在项目的根目录地址输入 air ,项目便可以热重载自动运行。

当main.go文件发生代码更改时,air 会根据配置文件自动重新编译及重新运行。

5. 关于平滑重启

当服务关闭时,它应该停止接收新的请求,同时完成正在进行的请求,返回其响应,然后关闭。这里使用air + 捕捉信号包的方式实现平滑重启。

5.1 代码实现

// 等待中断信号来优雅关掉服务器
quit := make(chan os.Signal, 1)
// 此处不会阻塞
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) 


<-quit              

log.Println("ShutDown Server ...")
// 创建一个120秒超时的context
ctx, cancel := context.WithTimeout(context.Background(), time.Second*120)
defer cancel()
// 120秒内优雅关闭服务, (将未处理完的请求处理完再关闭服务), 超过120秒就强制退出
if err := server.Shutdown(ctx); err != nil {
   log.Fatal("shut down:", err)
}
log.Println("Server exiting success")

上述代码中,当程序被中断时,signal.Notify将向quit通道发送一个信号。

syscall.SIGHUPsyscall.SIGINTsyscall.SIGTERM是什么意思?

syscall.SIGINT是用来在Ctrl+C时优雅地关闭的,它也相当于os.Interrupt

syscall.SIGTERM是常用的终止信号,也是docker容器的默认信号,Kubernetes也使用它。

syscall.SIGHUP用于热重载配置。

5.2 其它信号常量介绍

信号动作说明
SIGHUP1Term终端控制进程结束(终端连接断开)
SIGINT2Term用户发送INTR字符(Ctrl+C)触发,它也相当于os.Interrupt
SIGQUIT3Core用户发送QUIT字符(Ctrl+/)触发
SIGILL4Core非法指令(程序错误、试图执行数据段、栈溢出等)
SIGABRT6Core调用abort函数触发
SIGFPE8Core算术运行错误(浮点运算错误、除数为零等)
SIGKILL9Term无条件结束程序(不能被捕获、阻塞或忽略)
SIGSEGV11Core无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作)
SIGPIPE13Term消息管道损坏(FIFO/Socket通信时,管道未打开而进行写操作)
SIGALRM14Term时钟定时信号
SIGTERM15Term结束程序(可以被捕获、阻塞或忽略)
SIGUSR130,10,16Term用户保留
SIGUSR231,12,17Term用户保留
SIGCHLD20,17,18Ign子进程结束(由父进程接收)
SIGCONT19,18,25Cont继续执行已经停止的进程(不能被阻塞)
SIGSTOP17,19,23Stop停止进程(不能被捕获、阻塞或忽略)
SIGTSTP18,20,24Stop停止进程(可以被捕获、阻塞或忽略)
SIGTTIN21,21,26Stop后台程序从终端中读取数据时触发
SIGTTOU22,22,27Stop后台程序向终端中写数据时触发
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇