SetMaxOpenConns应设为MySQL max_connections的60%~80%,如查得max_connections=200,则设120~160;过高致Too many connections,过低致WaitCount上升、P99延迟毛刺。

SetMaxOpenConns 应该设多少才不爆 Too many connections
这个值必须和 MySQL 服务端的 max_connections 对齐,不能凭经验或 QPS 硬算。查真实上限最准:
SHOW VARIABLES LIKE 'max_connections';
假设返回 200,SetMaxOpenConns 就该设成 120~160(60%~80%)。留余量给备份、监控、其他服务,也防突发毛刺。
设成 0 或 500:MySQL 很快报 ERROR 1040: Too many connections,P99 延迟可能从 50ms 拉到 800ms+;设太低(比如 10):20 个 goroutine 并发查用户,每个都卡在等连接,QPS 上不去,平均延迟反而升高。
云数据库(如阿里云 RDS)建议更保守:按每核 ≈20 连接估算,别硬套物理机配置。
SetMaxIdleConns 必须 ≤ SetMaxOpenConns,否则 panic
SetMaxIdleConns 是空闲连接上限,它不是独立参数——它必须 ≤ SetMaxOpenConns,否则 Go 1.12+ 会直接 panic,错误是:"max idle conns exceeds max open conns"。
常见误配:
-
SetMaxOpenConns(5)却SetMaxIdleConns(10)→ 立即 panic - 只设
SetMaxIdleConns没设SetMaxOpenConns→ 默认SetMaxOpenConns = 0(无限制),实际受 DB 上限制约,不可控
稳妥做法:先设 SetMaxOpenConns,再设 ≤ 它的 SetMaxIdleConns;生产建议设为 SetMaxOpenConns × 0.5 左右,比如最大 100 → 空闲设 40~60。
SetConnMaxLifetime 和 SetConnMaxIdleTime 必须配对用
只调 SetMaxIdleConns 不设 SetConnMaxLifetime 是错的。空闲连接长期赖着不走,云环境 NAT 网关或防火墙会在 3~5 分钟后静默断连,下次复用直接报 read: connection reset by peer。
SetConnMaxLifetime 控制连接从创建起最多活多久(到期强制关闭),推荐设 2~5 分钟:
- 云数据库主备切换快,设
2分钟更安全 - 自建 MySQL 可设
5分钟 - 千万别设
0或time.Hour:长期存活连接容易在 DB 侧积压idle in transaction,锁资源、占内存、触发上下文切换风暴
SetConnMaxIdleTime(Go 1.15+)管空闲时长:设 30m~1h,让没人用的连接主动释放,比靠 SetConnMaxLifetime 更精细。
初始化后漏掉 db.Ping() 是线上首屏白屏的元凶
gorm.Open() 或 sql.Open() 只是初始化结构,不建真实连接。很多服务日志里写着 “DB initialized”,其实第一笔查询才真正拨号——这时候网络不通、密码错、DNS 解析失败,全堆在首请求上。
必须紧接 db, err := gorm.Open(...) 后面加:
if err := db.Ping(); err != nil {
log.Fatal("failed to ping DB:", err)
}
同样适用于 sql.Open() 场景,否则无法提前暴露底层驱动问题。配合 db.Stats() 定期打点,重点关注 InUse(是否长期 >95%)、Idle(是否长期接近 0)、WaitCount(是否持续上涨)。
最容易被忽略的是:GORM v2 的 gorm.Open() 返回 *gorm.DB,它底层封装了 *sql.DB,但连接池参数不会自动透传——你得手动调 db.DB().SetXXX,且必须在 db.Ping() 之前完成设置。


















