数据库连接与连接池

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
});

性能调优

参数建议值说明
maxCPU核数 × 2 + 磁盘数最大连接数
minmax 的 1/4最小连接数
idleTimeoutMillis30000空闲回收
acquireTimeoutMillis10000获取超时

常见问题与踩坑

问题原因解决方案
连接泄漏忘记 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') 保活检测。


相关链接: