Docker + Prometheus + Grafana
一、认识
基于 Docker
实现 Node.js
服务监控,主要关注以下几个方面的指标:
-
性能指标:
-
事件循环延迟 (
Event Loop Delay
):监控Node.js
事件循环的延迟,评估系统性能。事件循环延迟是监控Node.js
性能的一个关键指标,直接反映了系统是否出现性能瓶颈。使用perf_hooks.monitorEventLoopDelay
来获取事件循环延迟的详细统计(需要Node.js 10.10
以上版本)。如果版本不支持,可以使用process.hrtime()
来手动计算事件循环延迟。 -
垃圾回收 (
GC
):监控垃圾回收的行为和对应用性能的影响。使用perf_hooks.PerformanceObserver
监控垃圾回收的持续时间、频率和类型。监控 GC 可帮助我们理解内存清理和优化的需要。 -
内存使用情况:包括堆内存和非堆内存的使用,帮助监控内存泄漏和资源消耗。使用
process.memoryUsage()
来获取内存使用情况(rss
,heapUsed
,heapTotal
,external
)。使用v8.getHeapStatistics()
获取V8
堆的信息。 -
CPU
使用率:监控CPU
的整体使用情况,识别是否存在CPU
密集型操作。使用os.cpus()
和process.cpuUsage()
监控CPU
使用率。可以计算每个核的使用情况,获取CPU
使用时间,帮助识别CPU
密集型任务。 -
CPU
负载:通过CPU
负载来判断系统资源是否充足,避免过载。通过Node.js
中的os.loadavg()
方法获取系统的负载平均值(即 1 分钟、5 分钟和 15 分钟的负载平均值)
-
-
服务状态指标:
-
平均响应时间 (
ART
):监控服务的响应速度,及时发现性能瓶颈。使用中间件来测量每个请求的响应时间, 帮助定位慢请求 -
每秒事务数 (
TPS
):衡量系统的处理能力,反映应用的吞吐量。使用中间件来监控请求数,计算每秒事务数(TPS
)。 -
每秒请求数 (
QPS
):用于监控服务的请求量,及时发现流量异常。使用中间件来监控请求数,计算每秒请求数(QPS
)。 -
真实请求数 (
Real QPS
):仅统计成功的请求数,用于评估服务的实际处理能力。使用中间件来监控请求数,计算每秒真实请求数(QPS
)。
-
-
系统资源监控:
- 句柄数 (
Handlers
):监控系统打开的文件句柄和网络连接数,确保资源不会被耗尽。通常指的是进程中打开的各种资源,如文件描述符、TCP/UDP
套接字、进程的I/O
等等。每个句柄都占用一些内存,并且可以影响系统的性能。process._getActiveHandles()
返回当前Node.js
进程的所有活动句柄(如TCP
、UDP
、定时器、请求等)
- 句柄数 (
其中, prom-client
调用 collectDefaultMetrics({ register })
收集默认指标, 它会收集 CPU
基础指标 process_cpu_user_seconds_total
、process_cpu_system_seconds_total
、process_cpu_seconds_total
; 内存基础指标 nodejs_heap_size_total_bytes
、nodejs_heap_size_used_bytes
、nodejs_external_memory_bytes
; GC
垃圾回收基础指标 nodejs_gc_duration_seconds
、 事件循环延迟基础指标 nodejs_eventloop_lag_seconds
、句柄基础指标 nodejs_active_handles
等。在此基础上,基于 Counter
指标类型定义了 QPS
基础指标, 每次成功的请求会调用 qpsCounter.inc()
来增加 nodejs_qps
指标。在 Prometheus
中查询 QPS
主要依赖 rate()
函数,它能够计算指定时间范围内的增量变化, 比如根据 Prometheus
抓取周期(假设为 15 秒)来计算 QPS 为
: rate(nodejs_qps[15s])
, 即过去 15
秒内的 QPS
(每秒请求数的平均值)。基于 Histogram
指标类型定义了 ART
基础指标, 它会根据预定义的时间桶来统计请求的响应时间,并提供一些有用的统计信息(如请求的平均时间、百分位数等)。
通过使用 prom-client
库收集这些关键指标,并将其暴露给 Prometheus
,Prometheus
会周期性地拉取并高效存储这些数据。结合 Grafana
进行数据可视化,帮助开发团队实时监控应用性能、健康状况以及资源使用情况。同时,利用 Alertmanager
配置告警策略,确保在关键指标异常时能及时通知相关人员进行处理。
二、Node.js 服务
2.1 metric.js
const {
register,
Counter,
Histogram,
collectDefaultMetrics,
} = require("prom-client");
collectDefaultMetrics({ register });
const qpsCounter = new Counter({
name: "nodejs_qps",
help: "Total number of successful requests",
labelNames: ["method", "path", "httpStatus"],
});
const artHistogram = new Histogram({
name: "nodejs_active_request_duration_seconds",
help: "Histogram of the duration of requests in seconds",
labelNames: ["method", "path", "httpStatus"],
buckets: [0.001, 0.01, 0.1, 0.5, 1, 2, 5, 10],
});
module.exports = {
qpsCounter,
artHistogram,
};
2.2 index.js
const Koa = require("koa");
const client = require("prom-client");
const KoaRouter = require("koa-router");
const { qpsCounter, artHistogram } = require("./metric");
const PORT = 3000;
const app = new Koa();
const router = new KoaRouter();
async function artMiddleware(ctx, next) {
const end = artHistogram.startTimer();
await next();
end({
path: ctx.path,
method: ctx.method,
httpStatus: ctx.status,
});
}
async function qpsMiddleware(ctx, next) {
try {
await next();
qpsCounter.inc({
path: ctx.path,
method: ctx.method,
httpStatus: ctx.status,
});
} catch (error) {
ctx.status = 500;
}
}
const list = [];
router.get("/", artMiddleware, qpsMiddleware, (ctx) => {
list.push(new Array(1000).fill("柏拉文"));
ctx.body = { code: 200, message: "成功!" };
});
router.get("/metrics", async (ctx) => {
try {
ctx.set("Content-Type", client.register.contentType);
ctx.body = await client.register.metrics();
} catch (error) {
ctx.status = 500;
ctx.body = "Error fetching metrics";
}
});
app.use(router.routes());
app.listen(PORT, () => {
console.log(`Koa Server 启动成功,监听端口:${PORT}`);
});
三、Docker 相关部署
四、Grafana 可视化配置
4.1 ART
要查询 ART
的平均响应时间,可以使用 rate()
函数计算每秒的请求总时长和请求总次数的增量,进而计算平均响应时间。
rate(nodejs_active_request_duration_seconds_sum[1m]) / rate(nodejs_active_request_duration_seconds_count[1m])
-
nodejs_active_request_duration_seconds_sum
:表示总请求时间的累计值(所有请求的响应时间之和)。 -
nodejs_active_request_duration_seconds_count
:表示总请求数(请求的次数)。 -
rate()
:计算每秒的增量,即每秒请求时长和请求数的平均值。
计算过去 1
分钟内的 ART
平均响应时间:
rate(nodejs_active_request_duration_seconds_sum[1m]) / rate(nodejs_active_request_duration_seconds_count[1m])
4.2 QPS
要查询某一时间段内的 QPS
,通常使用 rate()
函数。例如,查询过去 1
分钟内的 QPS
(每秒请求数的平均值):
rate(nodejs_qps[1m])
-
nodejs_qps
是计数器指标,它会累积成功请求的数量。 -
rate(nodejs_qps[1m])
计算过去1
分钟内的增量速率,即每秒成功请求数的平均值。
过去 15
秒内的 QPS
:
rate(nodejs_qps[15s])
查询特定路径、方法或状态码的 QPS
(例如,查询 /
路径的 GET
请求成功数):
rate(nodejs_qps{method="GET", path="/"}[1m])