setmaxopenconns应设为数据库max_connections的60%~80%,如mysql默认151则设100;过高致too many connections,过低致waitcount上升、p99延迟毛刺;需监控openconnections长期>90%则扩容。

SetMaxOpenConns 设太高或太低都会翻车
默认值 0(无上限)在生产环境等于直接开闸放水,MySQL 一报 Too many connections 就全挂;设太低则 db.Stats().WaitCount 持续上涨,请求排队、P99 延迟毛刺明显。
- 先查数据库真实上限:
SHOW VARIABLES LIKE 'max_connections';(MySQL)或SELECT setting FROM pg_settings WHERE name = 'max_connections';(PostgreSQL) - 线上推荐值 = 数据库上限 × 60%~80%,留余量给备份、监控、其他服务——比如 MySQL 默认 151,设
100是稳妥起点 - 别信“QPS × 耗时”硬算:300 QPS × 20ms = 6 并发?实际要乘安全系数 1.5~2,再向上取整,起步至少
15~20 - 观察
db.Stats().OpenConnections:长期 > 90%MaxOpenConns→ 加;长期
SetMaxIdleConns 和 SetConnMaxIdleTime 必须配对生效
只设 SetMaxIdleConns 不设 SetConnMaxIdleTime,空闲连接会堆着不动,等数据库侧 wait_timeout(如 MySQL 默认 300s)静默断连后,Go 还拿它发请求,直接报 ERROR 2013: Lost connection。
-
SetMaxIdleConns建议为SetMaxOpenConns的 1/2~1/3(如 Open=100 → Idle=30~50) -
SetConnMaxIdleTime必须 wait_timeout,云环境(RDS/PolarDB)建议缩到5 * time.Minute - 注意:
SetConnMaxIdleTime仅 Go 1.15+ 支持;低版本只能靠SetConnMaxLifetime间接控制
事务里调 db.Query() 就等于主动泄漏连接
事务中混用 db.Query() 和 tx.Query() 是最隐蔽的泄漏源:前者从全局池另取连接,不参与事务、不随事务释放,db.Stats().InUse 居高不下但 WaitCount 不涨,排查极难。
- 所有事务内 SQL 必须统一走
tx.Query()、tx.Exec(),禁用db.Query() - 开启事务必须带
context超时:db.BeginTx(ctx, &sql.TxOptions{}),其中ctx建议设5 * time.Second -
*sql.Tx对象必须显式Commit()或Rollback(),否则连接永不归还 - 漏写
rows.Close()同样泄漏——defer rows.Close()是底线,不是可选项
db.Stats() 是唯一可信的实时体检报告
db.Ping() 只测“门铃响不响”,不反映池内连接是否真实可用、是否被卡死、是否在排队。依赖它等于闭眼开车。
- 重点关注三个字段的持续趋势:
WaitCount(排队次数)、WaitDuration(总排队时长)、MaxIdleClosed(因空闲被关掉的连接数) -
WaitCount持续上涨 → 优先调高SetMaxOpenConns -
MaxIdleClosed高 →SetMaxIdleConns设太高,或SetConnMaxIdleTime没生效 - 把
db.Stats()接入 Prometheus,设告警:当OpenConnections / MaxOpenConns > 0.9且持续 1 分钟,立刻通知
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











