跳到主要内容

事件循环

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

一、nodejs_eventloop_lag_seconds


1.1 认识

nodejs_eventloop_lag_seconds:这个指标记录了事件循环的延迟(lag)时间,单位是秒。它是一个总览性的指标,反映了事件循环延迟的基本情况,帮助开发者快速了解事件循环的当前表现。

Node.js 中,事件循环延迟是一个重要的性能指标,它反映了 Node.js 事件循环处理异步任务的效率。我们可以通过两种方式来计算事件循环的延迟时间:一种是基于 process.hrtime(),另一种是通过 Node.js 提供的 perf_hooks 模块中的 monitorEventLoopDelay API

1.1 process.hrtime 计算

process.hrtime() 提供了高精度的时间戳,可以帮助我们计算事件循环的延迟。通过计算事件循环开始和结束之间的时间差,我们可以获取事件循环的延迟时间。process.hrtime():适合用于需要高精度时间戳的手动计算场景。它提供了精确的纳秒级时间戳,但需要开发者手动计算延迟时间。

const http = require('http');

// 用于记录事件循环的延迟
let lastTimestamp = process.hrtime();

// 计算事件循环的延迟
function monitorEventLoopDelay() {
// 获取当前时间与上次时间的差值
const currentTimestamp = process.hrtime(lastTimestamp);
const elapsed = currentTimestamp[0] * 1000 + currentTimestamp[1] / 1e6; // 转换为毫秒

// 打印事件循环的延迟
console.log('Event Loop Delay (ms):', elapsed);

// 更新上次时间戳
lastTimestamp = process.hrtime();
}

// 每秒钟打印一次事件循环延迟
setInterval(monitorEventLoopDelay, 1000);

// 创建一个 HTTP 服务器(模拟应用的负载)
http.createServer((req, res) => {
res.end('Hello, Node.js Event Loop!');
}).listen(3000, () => {
console.log('Server is running at http://localhost:3000');
});
  • process.hrtime() 返回一个高精度时间戳,形式为 [seconds, nanoseconds]

  • 在每次 setInterval 调用时,我们使用 process.hrtime(lastTimestamp) 来计算从上次计算到现在的时间差(单位为纳秒)。然后将其转换为毫秒。

  • 这个延迟时间即为事件循环的延迟,它表示了 Node.js 从上次事件循环到当前事件循环的耗时。

1.2 perf_hooks.monitorEventLoopDelay 计算

Node.js 还提供了 perf_hooks.monitorEventLoopDelay,这是一个专门用于监控事件循环延迟的 API。它允许我们更高效、直接地获取事件循环延迟数据,而无需手动计算时间差。perf_hooks.monitorEventLoopDelay:这是专为事件循环延迟设计的 API,具有较低的性能开销,使用简单,能够高效地提供事件循环延迟数据。

const { monitorEventLoopDelay } = require('perf_hooks');
const http = require('http');

// 设置事件循环延迟监控(单位为毫秒)
const eventLoopMonitor = monitorEventLoopDelay({ resolution: 10 }); // 每10毫秒检查一次事件循环延迟
eventLoopMonitor.enable(); // 启动监控

// 创建一个 HTTP 服务器(模拟应用的负载)
http.createServer((req, res) => {
res.end('Hello, Node.js Event Loop!');
}).listen(3000, () => {
console.log('Server is running at http://localhost:3000');
});

// 每秒钟打印一次事件循环延迟
setInterval(() => {
const delay = eventLoopMonitor.mean;
console.log(`Event Loop Delay (ms): ${delay}`);
}, 1000);
  • perf_hooks.monitorEventLoopDelay:这是一个专门用于监控事件循环延迟的工具,可以提供非常精确的事件循环延迟信息。它的默认精度为毫秒。

  • resolution:指定了监控的精度。这里我们设置为 10 毫秒(即每10毫秒进行一次延迟测量)。

  • eventLoopMonitor.mean:返回的是最近一次计算的事件循环延迟的平均值(单位为毫秒)。

  • 通过 setInterval 每秒打印一次事件循环延迟。

1.3 process.hrtime 与 perf_hooks.monitorEventLoopDelay

要在 Node.js 中实现事件循环延迟的计算,优先使用 perf_hooks.monitorEventLoopDelay,如果不支持则降级为 process.hrtime()

const { performance, monitorEventLoopDelay } = require('perf_hooks');

// 默认的事件循环延迟计算方法
function calculateEventLoopLagUsingHrtime() {
const start = process.hrtime();
process.nextTick(() => {
const delta = process.hrtime(start);
const lag = delta[0] + delta[1] / 1e9; // 转换为秒
console.log(`Event loop lag (using hrtime): ${lag} seconds`);
});
}

// 事件循环延迟计算方法
function calculateEventLoopLag() {
// 检查 perf_hooks 是否可用,优先使用 monitorEventLoopDelay
if (monitorEventLoopDelay) {
const histogram = monitorEventLoopDelay();
histogram.enable(); // 启动事件循环延迟监控

setInterval(() => {
const minLag = histogram.min / 1e9; // 转换为秒
const maxLag = histogram.max / 1e9; // 转换为秒
const meanLag = histogram.mean / 1e9; // 转换为秒

console.log(`Event loop lag (min): ${minLag} seconds`);
console.log(`Event loop lag (max): ${maxLag} seconds`);
console.log(`Event loop lag (mean): ${meanLag} seconds`);
histogram.reset(); // 重置统计数据
}, 1000); // 每秒输出一次
} else {
// 如果 monitorEventLoopDelay 不可用,使用 process.hrtime 计算延迟
setInterval(calculateEventLoopLagUsingHrtime, 1000);
}
}

// 调用计算事件循环延迟
calculateEventLoopLag();
  • perf_hooks.monitorEventLoopDelay: monitorEventLoopDelayperf_hooks 提供的一个 API,用于监控事件循环的延迟,它提供了精确的统计数据:min(最小延迟)、max(最大延迟)、mean(平均延迟)等。如果 monitorEventLoopDelay 可用,则创建一个 histogram 实例,并启动事件循环延迟监控。每秒钟输出当前事件循环的最小、最大和平均延迟,并重置统计数据。

  • 如果 monitorEventLoopDelay 不可用,则使用 process.hrtime, process.hrtime 提供了一个高精度的时间差计算方法,单位为纳秒。我们通过在 process.nextTick 中调用它,测量每次事件循环的延迟时间。每秒计算一次延迟并输出结果。