数据库连接与连接池
What — 是什么
连接池是管理数据库连接的缓存机制,预先创建一定数量的连接并复用,避免每次请求都建立和销毁连接的开销。
核心概念:
- 连接池原理:预先创建 N 个数据库连接放入池中,请求时从池中获取,用完归还
- 核心参数:最小连接数(min)、最大连接数(max)、获取超时(acquireTimeoutMillis)、空闲超时(idleTimeoutMillis)
- 泄漏检测:连接被获取后长时间未归还,通过超时机制检测和回收
- pg-pool:PostgreSQL 官方连接池
- generic-pool:通用连接池库,适用于任何资源
关键特性:
- 连接建立耗时 50-200ms,池化后获取连接 <1ms
- 最大连接数受数据库
max_connections限制 - 空闲连接定期清理,减少数据库负担
Why — 为什么
适用场景:
- 所有频繁访问数据库的 Node.js 服务
- 高并发 API 服务
- 长连接应用(数据库连接建立成本高)
对比方案:
| 维度 | 每次新建连接 | 连接池 |
|---|---|---|
| 延迟 | 50-200ms | <1ms |
| 数据库压力 | 高(频繁握手) | 低(复用连接) |
| 并发支持 | 差 | 好(max 控制) |
| 资源消耗 | 高 | 低 |
How — 怎么用
代码示例
// pg-pool PostgreSQL 连接池
const { Pool } = require('pg');
const pool = new Pool({
host: 'localhost',
port: 5432,
database: 'mydb',
user: 'postgres',
password: process.env.DB_PASSWORD,
max: 20, // 最大连接数
min: 5, // 最小连接数
idleTimeoutMillis: 30000, // 空闲超时
connectionTimeoutMillis: 5000, // 连接超时
});
async function query(text, params) {
const client = await pool.connect();
try {
const result = await client.query(text, params);
return result.rows;
} finally {
client.release(); // 必须释放!
}
}
// mysql2 连接池
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
database: 'mydb',
waitForConnections: true,
connectionLimit: 20,
queueLimit: 0
});
性能调优
| 参数 | 建议值 | 说明 |
|---|---|---|
| max | CPU核数 × 2 + 磁盘数 | 最大连接数 |
| min | max 的 1/4 | 最小连接数 |
| idleTimeoutMillis | 30000 | 空闲回收 |
| acquireTimeoutMillis | 10000 | 获取超时 |
常见问题与踩坑
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 连接泄漏 | 忘记 release() | 用 try/finally 确保释放 |
| 连接池耗尽 | 并发超过 max | 排查慢查询 + 增加 max |
| 数据库连接数爆满 | 多服务共享数据库 | 全局连接数控制 |
最佳实践
- 始终用
try/finally释放连接 - max 不超过数据库
max_connections / 服务实例数 - 监控连接池使用率和等待时间
- 慢查询排查,减少连接占用时间
面试题
Q1: 连接池的工作原理?核心参数如何调优?
连接池维护一个连接队列。请求时:有空闲连接直接返回,无空闲且未达 max 则新建,已达 max 则等待。归还时:连接放回池中复用。核心参数:
max= CPU核数 × 2 + 磁盘数(一般 10-50),min= max 的 1/4(减少冷启动延迟),idleTimeoutMillis= 30s(回收空闲连接),acquireTimeoutMillis= 10s(获取超时报错而非无限等待)。
Q2: 如何检测和处理连接泄漏?
泄漏特征:连接池活跃连接数持续增长不下降。检测:① 连接池库的泄漏检测(generic-pool 的
softIdleTimeout);② 日志记录连接获取和释放时间,超时未释放的记录告警;③ 监控pool.totalCount - pool.idleCount - pool.waitingCount是否增长。处理:try/finally确保释放、设置获取超时自动回收、定期执行pool.query('SELECT 1')保活检测。
相关链接: