如何在 node.js 中检测和测量事件循环阻塞?

How to detect and measure event loop blocking in node.js?

我想监控 node.js 中事件循环的每个 运行 需要多长时间。但是我不确定衡量这一点的最佳方法。我能想出的最好方法是这样的:

var interval = 500;
var interval = setInterval(function() {
    var last = Date.now();        
    setImmediate(function() {
        var delta = Date.now() - last;
        if (delta > blockDelta) {
            report("node.eventloop_blocked", delta);
        }
    });
}, interval);

我基本上是通过查看 setInterval 的延迟来推断事件循环 运行 的时间。我在 blocked 节点模块中看到了相同的方法,但感觉不准确且笨重。有没有更好的方法来获取这些信息?

更新:将代码更改为使用 setImmediate,如 hapi.js 所做的那样。

您可能还想查看 nodeio.js 中内置的分析。例如,参见这篇文章 http://www.brendangregg.com/flamegraphs.html

以及这个相关的 SO 答案 How to debug Node.js applications

"Is there a better way to get this information?" 我没有比检查 SetImmediate 的时间延迟更好的方法来测试事件循环,但是使用节点的高分辨率计时器而不是 Date.now()

可以获得更好的精度
var interval = 500;
var interval = setInterval(function() {
    var last = process.hrtime();          // replace Date.now()        
    setImmediate(function() {
        var delta = process.hrtime(last); // with process.hrtime()
        if (delta > blockDelta) {
            report("node.eventloop_blocked", delta);
        }
    });
}, interval);

注意:delta 将是一个元组数组 [seconds, nanoseconds]。

有关 process.hrtime() 的更多详细信息: https://nodejs.org/api/all.html#all_process_hrtime

"The primary use is for measuring performance between intervals."

代码

此代码将测量事件循环触发所花费的时间(以纳秒为单位)。它测量当前进程和下一个滴答之间的时间。

var time = process.hrtime();
process.nextTick(function() {
   var diff = process.hrtime(time);


   console.log('benchmark took %d nanoseconds', diff[0] * 1e9 + diff[1]);
   // benchmark took 1000000527 nanoseconds
});

编辑:添加说明,

process.hrtime([时间])

Returns [seconds, nanoseconds] 元组数组中的当前高分辨率实时。 time 是一个可选参数,它必须是先前 process.hrtime() 调用的结果(因此,包含先前时间的 [seconds, nanoseconds] 元组数组中的实时时间)与当前时间不同。这些时间与过去的任意时间相关,与一天中的时间无关,因此不受时钟漂移的影响。主要用途是测量间隔之间的性能。

process.nextTick(回调[ arg][ ...])

一旦当前事件循环运行完成,调用回调函数。

这不是 setTimeout(fn, 0) 的简单别名,它的效率要高得多。它在事件循环的后续滴答中触发任何其他 I/O 事件(包括计时器)之前运行。

看看这个插件https://github.com/tj/node-blocked我现在正在使用它,它似乎可以满足您的需求。

let blocked = require("blocked");

blocked(ms => {
  console.log("EVENT LOOP Blocked", ms);
});

将打印出事件循环被阻塞的时间(以毫秒为单位)