mysql 连接数太多

108 阅读3分钟

1. 定位问题

登录数据库后执行:


SHOW PROCESSLIST;

找出 Sleep 状态连接,判断是否存在大量无操作但未关闭的连接。 按如下条件过滤:

  • Command = "Sleep"Time > 300
  • Host 归类出哪些 Pod/服务泄漏连接

临时解决:强制关闭空闲连接:

sql
KILL <id>;  -- 或者脚本批量 kill

2. 长久解决

你用的是 GoFrame 框架,建议检查你的连接池配置,特别是:

go
CopyEdit
// gcfg.yaml
database:
  default:
    link: "mysql:..."
    maxIdle: 10         # 建议设置   # 最大空闲连接,防止闲置太多浪费连接
    maxOpen: 50         # 连接数上限(需低于 mysql max_connections)
    maxLifetime: "300s" # 避免长连接泄漏, 单个连接最大生存时间,避免长时间持有连接
  • maxOpen 不要无限放大;
  • maxLifetime 防止连接泄漏卡死;
  • maxIdle 控制闲置连接数量,建议设置为比 maxOpen 小一截。

✅ 2. 是否有连接未释放?

GoFrame 使用 g.DB().Ctx(ctx).Model(...).All() 时,一般不会显式释放连接,因为它由连接池托管。但如果你用原始 driver/sql 查询、或未关闭 Rows,会造成泄漏!

例如这个就会泄漏:

go
rows, err := db.Query(...)
defer rows.Close() // ❗️必须调用

✅ 3. 慢查询 + 高并发 也会导致连接堆积

你提到的这条 SQL:

sql
SELECT ... FROM `case` WHERE status IN (1, 2) ORDER BY start_time ASC

是否涉及大表?慢查询?排序?分页?

可执行:

sql
EXPLAIN SELECT ...

如果扫描行数很大、没有索引或排序使用 filesort,很容易堆积连接。

🔧 建议:

  • 确保 statusstart_time 有联合索引;
  • 分页查询(LIMIT 分段)而不是一次性查全。

✅ 4. 检查是否使用了事务但没有提交或回滚

go
tx, err := g.DB().Begin()
...
// ❗️必须最终 commit 或 rollback

事务未提交或回滚,连接会被占住,无法释放。


✅ 5. 观察慢查询 & 连接数走势

Azure MySQL

  1. 打开慢查询日志(slow_query_log=ON, long_query_time=1);
  2. 使用 MySQL Insights 查看连接数变化;
  3. 设置 connection_threshold_alert 告警。

✅ 如何缓解连接爆满问题?

方法说明
降低 max_connections 设置压力阈值避免服务无限制抢连接
配置合理连接池上限(maxOpen)不让 Go 应用吃光连接
开启连接复用、生命周期避免连接泄漏或悬挂
慢查询优化 + 分页查询减少每次请求占用时间
使用连接中间件(如 ProxySQL)控流或池化更高级别的连接管理
限流访问拦截过多请求,保护数据库

Bonus: 多副本服务怎么安全配置连接池?

总连接上限你的 Azure 配置(341)
应用副本数假设 10 个
每个实例最大连接数341 / 10 = 34(推荐)

可以把 maxOpen 设置为 30 左右,避免服务间相互抢连接。

默认值(GoFrame 使用 Go 的默认):

参数默认值说明
maxIdle2最大空闲连接数(太小可能导致频繁创建销毁连接)
maxLifetime0(永不过期)每个连接可用多久,0 表示连接永不关闭(⚠️可能导致连接泄漏)
maxOpen无限(但 GoFrame 默认设为了 100)限制最大打开连接数,GoFrame 自己加了限制