跳到主要内容

数据库连接与连接池

问题

什么是数据库连接池?Serverless 场景下连接管理有什么问题?

面试速答版

什么是数据库连接池? 连接池是「提前创建、复用、后续还回」的连接管理机制:

  • 为什么需要:每个连接要 TCP 握手 + 身份认证 + 分配服务器内存,冷创建要 30~50ms,高并发下创建销毁开销极大。
  • 核心参数:max(最大连接数)、min(最小闲置数)、idleTimeout(闲置超时回收)、connectionTimeout(获取连接超时)。
  • 大小计算经验公式:连接数 ≈ (核心数 × 2) + 磁盘数,大多数场景 10~20 已够;连接数太多反而会让 DB 上下文切换加重。
  • 应用侧连接数 × 实例数要 < DB 的 max_connections,否则会被拒连。

Serverless 场景下连接管理有什么问题? Serverless 函数是「随用随启动」,连接池会遇到三大问题:

  • 连接数爆炸:函数冷启动会创建新连接,1000 个函数实例可能轻松打爆 PG 默认 100 连接上限。
  • 连接复用低:函数结束就销毁连接,连接池进化不出来。
  • 冷启动额外延迟:每次建连增加几十 ms。
  • 解法:用连接池中间件,如 PgBouncer、Prisma Accelerate、Supabase Pooler、Neon Pooler,把函数的短连接代理成后端的长连接;或选用 HTTP/Edge 原生驱动(Neon Serverless Driver、Cloudflare D1 HTTP API)避开 TCP 连接。

答案

为什么需要连接池

每个数据库连接需要 TCP 握手、认证、分配内存。频繁创建销毁连接开销很大。

连接池配置

connection-pool.ts
// Prisma 连接池
const prisma = new PrismaClient({
datasources: {
db: {
url: `${process.env.DATABASE_URL}?connection_limit=20&pool_timeout=10`,
},
},
});

// TypeORM 连接池
const dataSource = new DataSource({
type: 'postgres',
host: 'localhost',
port: 5432,
extra: {
max: 20, // 最大连接数
min: 5, // 最小连接数
idleTimeoutMillis: 30000, // 空闲连接超时
connectionTimeoutMillis: 5000, // 连接超时
},
});

// node-postgres 原生连接池
import { Pool } from 'pg';
const pool = new Pool({
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 5000,
});

连接池大小计算

连接数=CPU 核心数×2+有效磁盘数\text{连接数} = \text{CPU 核心数} \times 2 + \text{有效磁盘数}

经验公式:对于大多数应用,10-20 个连接足以处理数千 QPS。

常见误区

连接池越大越好?。数据库总连接数有限(MySQL 默认 151),过多连接导致上下文切换开销增大,性能反而下降。

Serverless 连接问题

serverless-db.ts
// Neon Serverless Driver(HTTP/WebSocket)
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL!);

// 无需连接池,每次都是 HTTP 请求
const users = await sql`SELECT * FROM users WHERE id = ${userId}`;

// Prisma Accelerate(连接池代理服务)
const prisma = new PrismaClient({
datasources: {
db: { url: process.env.PRISMA_ACCELERATE_URL },
},
});

常见面试问题

Q1: 连接池满了怎么办?

答案

  1. 排查:是否有连接泄漏(未释放)
  2. 优化:减少查询耗时,快速归还连接
  3. 扩容:适当增大连接池
  4. 降级:设置请求排队超时,超时返回错误

Q2: 连接泄漏怎么排查?

答案

// 检查活跃连接数
// PostgreSQL
SELECT count(*) FROM pg_stat_activity;

// MySQL
SHOW PROCESSLIST;

常见原因:事务未提交/回滚、未使用 try/finally 释放连接。

Q3: Serverless 场景下的数据库选型?

答案

方案说明
NeonServerless PostgreSQL,自动扩缩容
PlanetScaleServerless MySQL(基于 Vitess)
Turso边缘 SQLite
SupabasePostgreSQL + 连接池
Prisma Accelerate连接池代理

相关链接