数据库响应慢、连接数暴涨、偶发 connection reset,多因连接池参数超数据库实际能力;应先查 max_connections,再设 setmaxopenconns 为其实值的 60%~80%,并监控 openconnections 是否长期超 90%。

Go 应用数据库响应变慢、连接数暴涨、偶发 read: connection reset by peer,八成不是 SQL 写得差,而是连接池参数没对上数据库实际能力。
查清数据库最大连接数再设 SetMaxOpenConns
硬套“CPU 核数 × 2 + 磁盘数”或“设 100”是线上翻车第一原因。MySQL 默认 max_connections=151,PostgreSQL 常为 100 或 200,你设 db.SetMaxOpenConns(200),数据库直接拒绝新连接,错误日志里满屏 ERROR 1040 (HY000): Too many connections。
- 先执行
SHOW VARIABLES LIKE 'max_connections';(MySQL)或SELECT setting FROM pg_settings WHERE name = 'max_connections';(PostgreSQL)拿到真实上限 -
SetMaxOpenConns推荐设为该值的60%~80%,留余量给后台任务、DBA 操作、突发流量 - 观察
db.Stats().OpenConnections:长期 > 90%MaxOpenConns,说明不够用;长期
SetMaxIdleConns 和 SetConnMaxLifetime 必须配对调
只调 SetMaxOpenConns 不碰 idle 和 lifetime,等于只装了油没点火——连接池看着在跑,实际请求一多就报 ERROR 2013 (HY000): Lost connection 或 context deadline exceeded。
-
SetMaxIdleConns一般设为SetMaxOpenConns的1/2~1/3(例如最大开 50,空闲保持 15~25) -
SetConnMaxLifetime必须略小于数据库侧的超时设置:MySQL 默认wait_timeout=28800(8 小时),但生产常调为300(5 分钟),那你就得设4 * time.Minute;PostgreSQL 的tcp_keepalives_idle或idle_in_transaction_session_timeout也得对齐 - Go 1.15+ 务必加
SetConnMaxIdleTime(5 * time.Minute),防 NAT、LB、防火墙静默断连
事务不提交,连接就永远卡住
*sql.Tx 对象本身不等于连接,但它会独占一个连接直到 Commit() 或 Rollback()。忘了调这两个方法,连接就不会归还池中,db.Stats().OpenConnections 会持续上涨,WaitCount 开始飙升。
- 所有
db.Begin()后必须有明确的defer tx.Rollback()+ 显式tx.Commit(),不能只靠 defer - 避免在循环里反复
Begin()/Commit(),高频小事务不如批量操作 + 单次事务 - 用
db.Stats().WaitCount和db.Stats().WaitDuration监控排队情况:非零即说明连接被长期占用或泄漏
rows.Close() 不是可选项,是强制项
db.Query() 返回的 *sql.Rows 必须显式 Close(),否则连接不会释放回池——这是最隐蔽的连接泄漏来源,比忘关事务还难排查。
- 正确写法:
rows, err := db.Query("..."); if err != nil { ... }; defer rows.Close() - 别信“GC 会回收”,
rows.Close()才真正触发连接归还;GC 只能回收*Rows对象本身,不碰底层连接 - 用
db.Stats().Idle配合压测观察:如果并发查询后Idle长期不回升,大概率有rows没关
连接池参数不是一次配完就高枕无忧的配置项,它和数据库负载、网络中间件、SQL 执行时长强耦合。上线后盯紧 db.Stats() 输出,比任何理论公式都管用。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











