微信小程序云开发虽然屏蔽了大量底层运维工作,但当业务量上来之后,很多团队还是会在自建的服务端通过Node.js访问云数据库或自建数据库,这时候连接池的状态就成了一个容易被忽视的隐患。连接池的活跃数持续攀升意味着数据库压力增大,空闲数长期为零则预示着池子即将耗尽,请求会开始排队甚至超时。本文将详细介绍如何用Prometheus对这些指标进行采集、暴露和告警。

一、为什么要监控连接池的活跃数与空闲数
连接池的本质是一个连接的缓存池。应用启动时预先建立若干数据库连接放在池中,请求到来时从池里借出一个连接执行SQL,用完后再归还。如果没有监控,连接池就像一个黑盒:你不知道当前有多少连接正在被使用(活跃数),也不知道还有多少连接可供分配(空闲数)。
举一个典型的故障场景:某次线上发布后,一段代码在异常分支中忘记调用release归还连接,活跃数缓慢爬升,几个小时后池子被占满,所有新请求阻塞在获取连接这一步,接口大面积超时。如果当时有活跃数指标和告警,问题在爬升阶段就能被发现,而不是等到服务完全不可用。
需要重点关注的核心指标包括:totalConnections(池内总连接数)、activeConnections(正在使用的连接数)、idleConnections(空闲连接数)、waitingClients(等待获取连接的排队请求数)。其中waitingClients尤其重要,它一旦大于零,说明池子已经供不应求,是容量不足或连接泄漏的强烈信号。
二、在Node.js服务端接入Prometheus暴露指标
Prometheus采用拉取模式采集数据,服务端只需要暴露一个metrics接口。Node.js生态中最常用的是prom-client这个库,配合express可以快速搭建。先安装依赖:
npm install prom-client express mysql2 generic-pool
接下来定义Gauge类型的指标。Gauge是一种可以上下波动的瞬时值指标,非常适合表达连接池的实时状态。完整示例如下:
const express = require('express');
const client = require('prom-client');
const mysql = require('mysql2');
const register = new client.Registry();
// 创建数据库连接池
const pool = mysql.createPool({
host: '127.0.0.1',
user: 'app',
password: 'secret',
database: 'shop',
connectionLimit: 20,
queueLimit: 100
});
// 定义连接池监控指标
const poolActive = new client.Gauge({
name: 'db_pool_active_connections',
help: '当前活跃连接数',
registers: [register]
});
const poolIdle = new client.Gauge({
name: 'db_pool_idle_connections',
help: '当前空闲连接数',
registers: [register]
});
const poolTotal = new client.Gauge({
name: 'db_pool_total_connections',
help: '连接池总连接数',
registers: [register]
});
const acquireDuration = new client.Histogram({
name: 'db_pool_acquire_duration_seconds',
help: '获取连接耗时分布',
buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1],
registers: [register]
});
// 定时采样连接池状态,每5秒一次
setInterval(async () => {
try {
const status = await pool.pool.getConnectionStatus ? pool.pool.getConnectionStatus() : null;
// mysql2没有直接的状态接口时,可通过查询processlist估算
const [rows] = await pool.query('SHOW PROCESSLIST');
const appConns = rows.filter(r => r.User === 'app');
poolTotal.set(appConns.length);
// 也可以在getConnection与release处埋点维护活跃计数
} catch (e) {
console.error('采样失败', e);
}
}, 5000);
// 暴露metrics接口
const app = express();
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
app.listen(3000);对于mysql2这类没有内置状态查询的驱动,更可靠的做法是在getConnection和release处手动埋点维护计数器。示例如下:
let activeCount = 0;
const totalLimit = 20;
let idleCount = totalLimit;
// 包装获取连接的方法
async function getConnection() {
const start = Date.now();
const conn = await pool.getConnection();
acquireDuration.observe((Date.now() - start) / 1000);
activeCount++;
idleCount = Math.max(0, idleCount - 1);
syncMetrics();
return conn;
}
function releaseConnection(conn) {
conn.release();
activeCount = Math.max(0, activeCount - 1);
idleCount = Math.min(totalLimit, idleCount + 1);
syncMetrics();
}
function syncMetrics() {
poolActive.set(activeCount);
poolIdle.set(idleCount);
poolTotal.set(activeCount + idleCount);
}这种埋点方式虽然需要侵入业务代码,但数据准确且不依赖特定驱动的内部实现。如果使用generic-pool,它原生提供pool.available、pool.borrowed等属性,直接在定时任务里读取即可,无需手动埋点。
三、配置Prometheus采集与告警规则
指标暴露出来后,需要在Prometheus的配置文件中添加采集任务。编辑prometheus.yml:
scrape_configs:
- job_name: 'miniprogram-backend'
scrape_interval: 5s
static_configs:
- targets: ['127.0.0.1:3000']采集到数据后,就可以用PromQL进行查询分析了。几个常用的查询语句如下:查看活跃连接数趋势,直接使用db_pool_active_connections;计算连接池使用率,用db_pool_active_connections / db_pool_total_connections;判断池是否耗尽,看活跃数是否长期等于上限值20。
告警规则可以这样写,在rules.yml中定义两条核心告警:
groups:
- name: db-pool-alerts
rules:
- alert: DbPoolNearExhausted
expr: db_pool_active_connections >= 18
for: 2m
labels:
severity: warning
annotations:
summary: '连接池活跃数接近上限'
description: '活跃连接数已连续2分钟超过18,接近上限20'
- alert: DbPoolExhausted
expr: db_pool_active_connections >= 20
for: 1m
labels:
severity: critical
annotations:
summary: '连接池已耗尽'
description: '连接池已满,新请求可能正在排队等待'注意for字段的作用是持续时长过滤,避免瞬时抖动触发误报。告警级别建议分为warning和critical两档,warning提前预警,critical意味着需要立即处理。
四、用Grafana搭建可视化面板
光有数据和告警还不够直观,建议用Grafana搭建一个专属面板。常用的面板布局是:一个时序图同时展示活跃数、空闲数、总数三条曲线,用不同颜色区分,空闲数用面积图填充,视觉上一眼就能看出池子的水位变化;再配一个Stat面板展示当前使用率百分比,设置阈值变色,低于70%绿色、70%到90%黄色、超过90%红色。
获取连接耗时的Histogram指标也值得单独画一个面板,观察P95和P99延迟。如果发现获取连接的耗时不正常地增长,即使活跃数还没到上限,也说明池子已经开始排队,这是容量规划的重要参考信号。
另外提醒一点,微信小程序的流量有明显的高峰特征,比如秒杀活动开始瞬间连接池会被打满。建议把连接池容量指标与业务QPS放在同一个面板下对照观察,通过历史数据反推合理的connectionLimit取值,一般让高峰期活跃数稳定在容量的60%到70%为宜,既不浪费连接资源,也留出了突发流量的缓冲空间。
五、常见问题与排查思路
接入监控后,如果发现活跃数只涨不跌,基本可以断定是连接泄漏,重点排查异常分支中是否遗漏了release调用。一个防御性技巧是封装统一的查询函数,在finally块中保证归还连接:
async function query(sql, params) {
const conn = await getConnection();
try {
const [rows] = await conn.query(sql, params);
return rows;
} finally {
releaseConnection(conn); // 无论成功失败都归还连接
}
}如果发现空闲数长期偏高、活跃数很低,说明池子配置过大,浪费了数据库连接资源,可以适当调小connectionLimit。数据库的总连接数是有上限的,多个服务实例共享同一个数据库时,各实例池容量之和不能超过数据库的max_connections设置,这一点在水平扩容时尤其要小心。
最后,指标暴露接口本身也可能成为风险点,建议在网关层限制/metrics路径只允许内网访问,避免将运行时信息暴露给公网。监控体系搭好之后,连接池从黑盒变成透明的水位计,很多数据库层面的故障都能在萌芽阶段被捕获,运维压力会小很多。
微信小程序连接池监控Prometheus指标修改时间:2026-09-13 06:00:38