gin框架如何实现不停止服务的重启

在 Go 的 Gin 框架中实现 “不停止服务的重启”(即 零停机重启 / Graceful Restart),核心目标是:

在启动新进程的同时,让旧进程继续处理完已有请求后再退出,从而实现无缝更新。

这通常通过 “平滑重启(Graceful Restart)” + “进程替换” 实现。Go 本身不直接支持 fork,但可通过以下方式达成。


使用 fvbock/endless

endless 是一个专为 Gin/HTTP 服务设计的 零停机重启库,兼容标准 http.Server,用法几乎和原生一样。

步骤:

1. 安装

go get github.com/fvbock/endless

2. 修改主程序

gin.Run() 替换为 endless.ListenAndServe()

package main

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

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "pong"})
    })

    // 使用 endless 启动,而不是 r.Run()
    if err := endless.ListenAndServe(":8080", r); err != nil {
        log.Fatalf("Failed to start server: %v", err)
    }
}

3. 重启服务(发送信号)

编译后运行你的程序(假设 PID 是 12345):

# 查看当前进程 PID
ps aux | grep your-app

# 发送 USR2 信号触发平滑重启
kill -USR2 12345

效果:

  • 旧进程继续处理已建立的连接;
  • 新进程启动并监听相同端口;
  • 旧进程在空闲后自动退出;
  • 用户无感知,无 502/503 错误

endless 内部使用 SO_REUSEPORT(Linux)或子进程继承监听套接字(跨平台)实现端口复用。


以下是自动化脚本:

#!/bin/bash
APP_NAME="myapp"
BUILD_TMP="${APP_NAME}_new"

# 1. 编译新版本
echo "Building new version..."
go build -o "$BUILD_TMP" .

# 2. 原子替换
echo "Replacing binary..."
mv "$BUILD_TMP" "$APP_NAME"

# 3. 发送 USR2 信号重启
PID=$(pgrep -f "$APP_NAME" | head -n 1)
if [ -n "$PID" ]; then
    echo "Sending USR2 to PID $PID..."
    kill -USR2 "$PID"
else
    echo "No running process, starting fresh..."
    ./$APP_NAME &
fi

Comments

No comments yet. Why don’t you start the discussion?

发表回复