生产环境的性能优化很重要,合理的配置能让应用更稳定高效。
package main
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello")
})
srv := &http.Server{
Addr: ":8080",
Handler: r,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
MaxHeaderBytes: 1 << 20,
}
srv.ListenAndServe()
}
数据库连接池:
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func setupDB() *sql.DB {
db, err := sql.Open("mysql", dsn)
if err != nil {
panic(err)
}
db.SetMaxOpenConns(100)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(time.Hour)
db.SetConnMaxIdleTime(10 * time.Minute)
return db
}
Redis 连接池:
import "github.com/go-redis/redis/v8"
func setupRedis() *redis.Client {
return redis.NewClient(&redis.Options{
Addr: "localhost:6379",
PoolSize: 100,
MinIdleConns: 10,
MaxRetries: 3,
DialTimeout: 5 * time.Second,
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
PoolTimeout: 4 * time.Second,
})
}
跳过不需要的中间件:
func SkipLogger(skipPaths []string) gin.HandlerFunc {
return func(c *gin.Context) {
for _, path := range skipPaths {
if c.Request.URL.Path == path {
c.Next()
return
}
}
start := time.Now()
c.Next()
log.Printf("%s %s - %v", c.Request.Method, c.Request.URL.Path, time.Since(start))
}
}
r.Use(SkipLogger([]string{"/health", "/metrics"}))
import "github.com/gin-contrib/gzip"
func main() {
r := gin.Default()
r.Use(gzip.Gzip(gzip.DefaultCompression))
r.GET("/data", func(c *gin.Context) {
c.JSON(200, largeData)
})
r.Run(":8080")
}
func CacheMiddleware(duration time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.Method != "GET" {
c.Next()
return
}
key := c.Request.URL.String()
if cached, found := cache.Get(key); found {
c.Data(200, "application/json", cached.([]byte))
c.Abort()
return
}
c.Next()
if c.Writer.Status() == 200 {
cache.Set(key, c.Writer.(*bytesBuffer).Bytes(), duration)
}
}
}
复用对象:
var bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func processRequest(c *gin.Context) {
buf := bufferPool.Get().(*bytes.Buffer)
buf.Reset()
defer bufferPool.Put(buf)
buf.WriteString("processing...")
c.String(200, buf.String())
}
func parallelFetch(c *gin.Context) {
var wg sync.WaitGroup
results := make(chan interface{}, 3)
wg.Add(3)
go func() {
defer wg.Done()
results <- fetchUser()
}()
go func() {
defer wg.Done()
results <- fetchOrders()
}()
go func() {
defer wg.Done()
results <- fetchProducts()
}()
go func() {
wg.Wait()
close(results)
}()
var data []interface{}
for r := range results {
data = append(data, r)
}
c.JSON(200, data)
}
func withTimeout(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
defer cancel()
result, err := fetchDataWithContext(ctx)
if err != nil {
c.JSON(500, gin.H{"error": "timeout"})
return
}
c.JSON(200, result)
}
# 减小二进制大小
go build -ldflags="-w -s" -o main .
# 静态编译
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
import (
"net/http/pprof"
)
func main() {
r := gin.Default()
if gin.Mode() == gin.DebugMode {
r.GET("/debug/pprof/*profile", gin.WrapH(http.DefaultServeMux))
}
r.Run(":8080")
}
分析 CPU:
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=30
分析内存:
go tool pprof http://localhost:8080/debug/pprof/heap
# 使用 ab
ab -n 10000 -c 100 http://localhost:8080/api
# 使用 wrk
wrk -t12 -c400 -d30s http://localhost:8080/api
性能优化从配置开始:合理的超时、连接池大小、内存复用。使用 pprof 分析性能瓶颈,用压力测试验证优化效果。生产环境记得关闭调试日志,使用 Release 模式。