Skip to content

第26章:高性能与优雅关闭 ​

本章目标 ​

学完本章后,你将能够:

  1. 理解 Gin 高性能的原因
  2. 实现服务优雅关闭(Graceful Shutdown)
  3. 配置超时控制
  4. 在生产环境安全地停止和重启服务

前置知识 ​

  • 需要先学习:第03章(路由基础)、第08章(路由树)

26.1 Gin 为什么快 ​

  1. Radix Tree 路由:O(路径长度) 匹配,不随路由数量增长
  2. 零内存分配:httprouter 对路径参数做了零分配优化
  3. 轻量设计:只做路由和中间件,没有 ORM、模板引擎等重组件

性能数据(官方 benchmark):

Gin:      ~50,000 QPS/ms
Echo:     ~48,000 QPS/ms
net/http: ~10,000 QPS/ms

26.2 优雅关闭 ​

直接 Ctrl+C 停止服务会中断正在处理的请求。优雅关闭让你:

  1. 停止接收新请求
  2. 处理完已有请求
  3. 关闭数据库连接等资源
go
package main

import (
	"context"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		time.Sleep(5 * time.Second)  // 模拟慢请求
		c.String(200, "done")
	})

	// 创建 http.Server
	srv := &http.Server{
		Addr:    ":8080",
		Handler: r,
	}

	// 在 goroutine 中启动服务
	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("启动失败: %v", err)
		}
	}()
	log.Println("服务已启动 :8080")

	// 等待中断信号
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit  // 阻塞,直到收到 Ctrl+C
	log.Println("正在关闭服务...")

	// 优雅关闭:5 秒超时
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := srv.Shutdown(ctx); err != nil {
		log.Fatalf("关闭失败: %v", err)
	}
	log.Println("服务已关闭")
}

26.3 超时控制 ​

go
srv := &http.Server{
	Addr:         ":8080",
	Handler:      r,
	ReadTimeout:  10 * time.Second,   // 读取请求超时
	WriteTimeout: 10 * time.Second,   // 写响应超时
	IdleTimeout:  60 * time.Second,   // 空闲连接超时
}

26.4 性能优化建议 ​

建议说明
用 gin.New() + 自定义中间件按需加载,不用 Default
数据库连接池配置MaxOpenConns/MaxIdleConns(见 GORM 教程)
接口返回只查需要的字段不要 SELECT *
合理使用缓存Redis 缓存热点数据
Gzip 压缩传输量减少 70%+

本章小结 ​

  • Gin 的快来自 Radix Tree + 零内存分配 + 轻量设计
  • 优雅关闭 = 等正在处理的请求完成再退出
  • signal.Notify 监听 SIGINT/SIGTERM
  • srv.Shutdown(ctx) 平滑关闭
  • 生产必须配置 ReadTimeout/WriteTimeout

练习题 ​

  1. 将你的 Gin 服务改造为优雅关闭模式。
  2. 测试:启动服务,发一个慢请求,同时 Ctrl+C,观察慢请求是否能正常完成。
  3. 配置 ReadTimeout 和 WriteTimeout,测试超时行为。
  4. (思考题)优雅关闭的 5 秒超时时间到了但请求还没处理完,会发生什么?

把零散知识,整理成可以反复走的路。