跳到主要内容

自定义指标

2024年12月25日
柏拉文
越努力,越幸运

一、CPU 指标


1.1 CPU 负载

nodejs_cpu_load_average CPU 负载情况。

CPU 负载 描述的是系统中等待 CPU 执行的任务数量。一般来说,它可以理解为系统队列中任务的数量,包括正在运行和等待运行的任务。CPU 负载的数值越高,说明系统任务越多,CPU 负载越重;数值越低,说明系统任务较少,CPU 有更多的闲暇时间。

CPU 负载 通常以平均值的形式显示,分为 1 分钟平均负载5 分钟平均负载15 分钟平均负载。这些数值分别表示系统在过去 1 分钟5 分钟15 分钟内 的平均负载。这个平均值可以帮助我们判断系统的负载趋势和波动情况。

CPU 负载 反映的是系统的整体负载情况,表示系统的繁忙程度,包括等待 CPUI/O 资源的进程。负载不一定与 CPU 使用率直接相关。

const os = require('os');
const promClient = require('prom-client');

// 创建一个 Gauge 类型的指标,用于获取 CPU 负载平均值
const loadAvgGauge = new promClient.Gauge({
name: 'nodejs_cpu_load_average',
help: 'CPU load average for 1, 5, 15 minutes',
labelNames: ['time_window'],
collect() {
// 获取 CPU 的 1分钟、5分钟和15分钟负载平均值
const loadAvg = os.loadavg();

// 设置负载平均值到对应的标签
this.labels('1_min').set(loadAvg[0]);
this.labels('5_min').set(loadAvg[1]);
this.labels('15_min').set(loadAvg[2]);
}
});

我们可以通过 Node.js 中的 os.loadavg() 方法获取系统的负载平均值(即 1 分钟、5 分钟和 15 分钟的负载平均值)

1.2 CPU 使用率

nodejs_cpu_usage_percentage CPU 使用率

CPU 使用率 是一个衡量计算机中央处理单元(CPU)在给定时间内有多忙碌的指标。它表示在 CPU 能够使用的时间里,CPU 实际上被使用的时间百分比。简单来说,CPU 使用率反映了计算机的处理能力被消耗的程度。

  1. 0% CPU 使用率意味着 CPU 完全空闲,没有任何任务在运行

  2. 100% CPU 使用率意味着 CPU 在该时刻完全处于工作状态,没有闲置

CPU 使用率 主要关注的是 CPU 资源的实际使用情况,反映了 CPU 被占用的百分比。如果系统 CPU 使用率很高,通常意味着系统忙于处理任务。

const os = require('os');
const promClient = require('prom-client');

// 获取 CPU 使用率
function getCpuUsage() {
const cpus = os.cpus();
let totalIdle = 0;
let totalTick = 0;

cpus.forEach(cpu => {
const times = cpu.times;
totalIdle += times.idle;
totalTick += Object.values(times).reduce((acc, val) => acc + val, 0);
});

// 计算空闲时间和总时间的比例
const idle = totalIdle / cpus.length;
const total = totalTick / cpus.length;
const percentage = (1 - idle / total) * 100; // CPU 使用率

return percentage;
}

// 创建 Prometheus Gauge 指标
const cpuUsageGauge = new promClient.Gauge({
name: 'nodejs_cpu_usage_percentage',
help: 'CPU usage percentage',
collect() {
// 在 collect 中调用 getCpuUsage,并更新指标值
const percentage = getCpuUsage();
this.set(percentage); // 设置 Gauge 的值为计算出的 CPU 使用率
}
});

CPU 使用率 通常是通过以下方式计算的:

  • 用户态(User TimeCPU 执行用户级程序的时间。

  • 系统态(System Time)CPU 执行内核操作的时间。

  • 空闲态(Idle TimeCPU 没有执行任何任务的时间。

  • 中断时间(IRQ Time:处理硬件中断的时间。

CPU 使用率 的计算公式一般是:

CPU 使用率 = (总时间 - 空闲时间) / 总时间 * 100
  • 空闲时间:所有 CPU 核心的 idle 时间的总和。

  • 总时间:包括所有 CPU 核心的 usersystemidle 时间的总和。

Node.js 中,我们可以使用 os.cpus() 获取每个 CPU 核心的时间数据,然后根据上述公式来计算 CPU 使用率。

二、请求指标


2.1 ART

nodejs_active_request_time_seconds (ART) 即活跃请求时间。在 Node.js 应用程序中,ART 指标用于表示处理某个请求的时间。具体而言,它衡量的是从接收到请求到处理完成的整个周期所消耗的时间,通常用秒或毫秒为单位。ART 可以帮助识别请求处理中的性能瓶颈。如果 ART 数值较高,说明请求的处理时间较长,可能是由于计算密集型操作、数据库查询、外部服务依赖等原因造成的。通过监控 ART 指标,可以在不同路由和方法级别上查看哪些请求花费的时间较长,从而进行优化,比如增加缓存、优化查询、减少阻塞操作等。

const { Gauge } = require("prom-client");

const artGauge = new Gauge({
name: "nodejs_active_request_time_seconds",
help: "The time spent processing a request in seconds",
labelNames: ["method", "path", "httpStatus", "code"],
});

async function artMiddleware(ctx, next) {
const start = process.hrtime();

await next();

const end = process.hrtime(start);
const durationInSeconds = end[0] + end[1] / 1e9;
const statusCode = ctx.status || 500;

artGauge
.labels(ctx.method, ctx.path, statusCode, `status_${statusCode}`)
.set(durationInSeconds);
}

router.get("/", artMiddleware, (ctx) => {
ctx.body = { code: 200, message: "成功!" };
});

2.2 TPS

TPS (Transactions Per Second) 是衡量系统或服务每秒处理多少事务的指标。它通常用于监控数据库、消息队列和应用层的事务处理能力。对于 Web 服务而言,TPS 代表的是每秒钟系统能够处理的业务请求或事务的数量。通过对 TPS 的监控,系统架构师可以更好地规划服务器的扩容和负载均衡,以适应日益增长的负载。如果 TPS 达到一定阈值并出现下降或不稳定,可以及时发现潜在的性能瓶颈或资源不足问题。

TPS 用来衡量系统处理每秒原子事务的能力,适用于那些涉及多个操作、需要事务保证的一致性的场景。TPS 则更侧重于事务处理,尤其是那些需要保证一致性和原子性的操作。例如: 在数据库中,一个事务可能包括插入、更新和删除等操作。QPS 用来衡量系统处理每秒请求的能力,通常适用于 无状态请求,且不需要事务处理的场景。QPS 是一个更宽泛的概念,适用于大多数的 HTTP 请求和查询操作,关注的是请求的频率。例如,一个 HTTP 请求可能只是查询或获取资源,并不涉及多步骤的操作。

// 每秒钟统计的请求数
let transactionCount = 0;

// 创建一个 Prometheus 指标 (TPS)
const tpsGauge = new promClient.Gauge({
name: 'nodejs_tps',
help: 'Transactions per second (TPS) for successful requests',
});

// 每秒钟的 TPS 计算
setInterval(() => {
// 当前秒的请求数即为 TPS
const tps = transactionCount;
console.log("TPS:", tps);

// 更新 Prometheus 指标
tpsGauge.set(tps);

// 重置计数器
transactionCount = 0;
}, 1000);

// 定义 TPS 计算中间件
async function tpsMiddleware(ctx, next) {
// 执行下一个中间件
await next();

// 只有成功的请求才会计入 TPS
if (ctx.status >= 200 && ctx.status < 300) {
transactionCount++; // 增加事务计数
}
}

// 使用 TPS 中间件
app.use(tpsMiddleware);
  1. 使用 setInterval 每秒钟获取当前的 TPS,并将其传递到 PrometheustpsGauge 指标中

  2. 由于 setInterval 依赖的计数器是每秒钟重置的,所以不需要在每个请求过程中更新 Prometheus 指标(例如每个请求就更新一次),而是通过全局的 setInterval 每秒一次更新,这样减少了频繁调用 Prometheus API

2.3 真实 QPS

nodejs_real_qps QPS (Queries per Second) 是衡量系统处理能力的一个重要指标,通常用于表示系统在每秒钟能够处理多少个请求。真实 QPS 是一种专注于计算真实、有效请求的 QPS 指标,区别于那些可能被错误请求、健康检查、静态资源请求等所影响的总 QPS。也就是说,真实 QPS 更关注的是应用层实际处理的请求,通常用来反映应用的实际负载。真实 QPS 能够帮助评估实际业务请求的流量,帮助开发人员和运维团队进行容量规划。

真实 QPS 计算的是每秒处理的有效请求数,通常会排除掉错误请求、无效请求、超时请求等。更多地关注系统健康状况和正常请求的处理能力,排除掉可能对应用健康产生负面影响的请求。

TPS 用来衡量系统处理每秒原子事务的能力,适用于那些涉及多个操作、需要事务保证的一致性的场景。TPS 则更侧重于事务处理,尤其是那些需要保证一致性和原子性的操作。例如: 在数据库中,一个事务可能包括插入、更新和删除等操作。QPS 用来衡量系统处理每秒请求的能力,通常适用于 无状态请求,且不需要事务处理的场景。QPS 是一个更宽泛的概念,适用于大多数的 HTTP 请求和查询操作,关注的是请求的频率。例如,一个 HTTP 请求可能只是查询或获取资源,并不涉及多步骤的操作。

// 定义 Prometheus QPS 指标
const realQPSGauge = new promClient.Gauge({
name: 'nodejs_real_qps',
help: 'Real QPS for successful requests', // 描述指标
});

let requestCount = 0;
const QPS_RESET_INTERVAL = 1000;

async function realQPSMiddleware(ctx, next) {
try{
await next();

if (ctx.status >= 200 && ctx.status < 300) {
requestCount++;
}

}catch(error){
ctx.status = 500;
}
}

function updateQps() {
qpsGauge.set(requestCount);
requestCount = 0;
}

setInterval(updateQps, QPS_RESET_INTERVAL);

router.get("/", realQPSMiddleware, (ctx) => {
list.push(new Array(1000).fill("柏拉文"));
ctx.body = { code: 200, message: "成功!" };
});

通过使用 setInterval 来每隔一秒定期计算 QPS,并且避免在每个请求中都进行计算,优化了性能和并发情况。同时,通过 labels 对请求进行区分,使得 Prometheus 指标可以更细粒度地展示请求的 QPS

  1. 使用 setInterval 每秒钟计算一次 QPS,并且清空计数器。这样做的好处是减少了每个请求的计算压力,不会频繁计算和更新 QPS

  2. 每秒一次的定时计算使得 requestCount 可以作为局部计数器进行更新,避免了每个请求都进行 QPS 计算的性能开销。

  3. 只有成功的请求(状态码在 200-299 之间)才会计入 QPS,对于错误请求会跳过计数。

  4. 每秒的 QPS 计算是单独进行的,并不会受到高并发影响,因为每个请求计数的操作是非阻塞的。我们将计数和计算逻辑分开,避免了由于高并发时的共享状态导致的竞态条件。

2.4 每秒 QPS

每秒 QPS(Queries Per Second) nodejs_qps 是衡量系统每秒处理的请求数量的指标,通常用于衡量一个 Web 应用或服务的吞吐量。在 Node.js 中,QPS 代表每秒钟 HTTP 请求的数量。这个指标对于监控系统性能、分析应用负载、预测资源需求和调优服务器性能非常有用。了解高负载时的 QPS,可以帮助我们提前进行容量规划,避免系统崩溃。可以根据设定的阈值,监控 QPS 指标来触发警报,及时发现系统故障或瓶颈。

每秒 QPS:计算的是每秒处理的请求数,不区分请求类型和状态,所有请求都会计入。更多地用于吞吐量、系统负载的监控,帮助了解系统在特定时间段内的处理能。

TPS 用来衡量系统处理每秒原子事务的能力,适用于那些涉及多个操作、需要事务保证的一致性的场景。TPS 则更侧重于事务处理,尤其是那些需要保证一致性和原子性的操作。例如: 在数据库中,一个事务可能包括插入、更新和删除等操作。QPS 用来衡量系统处理每秒请求的能力,通常适用于 无状态请求,且不需要事务处理的场景。QPS 是一个更宽泛的概念,适用于大多数的 HTTP 请求和查询操作,关注的是请求的频率。例如,一个 HTTP 请求可能只是查询或获取资源,并不涉及多步骤的操作。

// 定义 Prometheus QPS 指标
const qpsGauge = new promClient.Gauge({
name: 'nodejs_qps',
help: 'Real QPS for successful requests', // 描述指标
});

let requestCount = 0;
const QPS_RESET_INTERVAL = 1000;

async function qpsMiddleware(ctx, next) {
try{
await next();
requestCount++;
}catch(error){
ctx.status = 500;
}
}

function updateQps() {
qpsGauge.set(requestCount);
requestCount = 0;
}

setInterval(updateQps, QPS_RESET_INTERVAL);

router.get("/", qpsMiddleware, (ctx) => {
list.push(new Array(1000).fill("柏拉文"));
ctx.body = { code: 200, message: "成功!" };
});

通过使用 setInterval 来每隔一秒定期计算 QPS,并且避免在每个请求中都进行计算,优化了性能和并发情况。同时,通过 labels 对请求进行区分,使得 Prometheus 指标可以更细粒度地展示请求的 QPS

  1. 使用 setInterval 每秒钟计算一次 QPS,并且清空计数器。这样做的好处是减少了每个请求的计算压力,不会频繁计算和更新 QPS

  2. 每秒一次的定时计算使得 requestCount 可以作为局部计数器进行更新,避免了每个请求都进行 QPS 计算的性能开销。

  3. 每秒的 QPS 计算是单独进行的,并不会受到高并发影响,因为每个请求计数的操作是非阻塞的。我们将计数和计算逻辑分开,避免了由于高并发时的共享状态导致的竞态条件。