monitorEventLoopDelay 是什么 perf_hooks.monitorEventLoopDelay([options])
options: Object – resolution
: The sampling rate in milliseconds. Must be greater than zero. Default: 10.
Returns: Histogram
Creates a Histogram object that samples and reports the event loop delay over time. The delays will be reported in nanoseconds. Using a timer to detect approximate event loop delay works because the execution of timers is tied specifically to the lifecycle of the libuv event loop. That is, a delay in the loop will cause a delay in the execution of the timer, and those delays are specifically what this API is intended to detect.
监控 EventLoop 运行情况是判断系统是否健康的重要指标之一,如果有大量的延迟,说明系统存在密集计算,降低了系统的吞吐。Node.js 在 v11 版本引入了monitorEventLoopDelay
,而之前需要自己去实现。
版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 33 #define UV_VERSION_PATCH 1 #define V8_MAJOR_VERSION 7 #define V8_MINOR_VERSION 8 #define V8_BUILD_NUMBER 279 #define V8_PATCH_LEVEL 17 #define NODE_MAJOR_VERSION 14 #define NODE_MINOR_VERSION 0 #define NODE_PATCH_VERSION 0
实现原理 代码中隐去了当前介绍过程中不重要的代码,有兴趣可以查看源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function monitorEventLoopDelay (options = {} ) { return new ELDHistogram (new _ELDHistogram (resolution)); } class ELDHistogram { constructor (handle ) { this [kHandle] = handle; } enable ( ) { return this [kHandle].enable (); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class ELDHistogram : public HandleWrap, public Histogram { public : ELDHistogram (Environment* env, Local<Object> wrap, int32_t resolution); bool Enable () ; private : static void DelayIntervalCallback (uv_timer_t * req) ; bool enabled_ = false ; uv_timer_t timer_; }; bool ELDHistogram::Enable () { if (enabled_ || IsHandleClosing ()) return false ; enabled_ = true ; uv_timer_start (&timer_, DelayIntervalCallback, resolution_, resolution_); uv_unref (reinterpret_cast <uv_handle_t *>(&timer_)); return true ; } void ELDHistogram::DelayIntervalCallback (uv_timer_t * req) { ELDHistogram* histogram = ContainerOf (&ELDHistogram::timer_, req); histogram->RecordDelta (); TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), "min" , histogram->Min ()); TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), "max" , histogram->Max ()); TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), "mean" , histogram->Mean ()); TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), "stddev" , histogram->Stddev ()); }
从上述代码我们可以和很容易的知道,js 调用一个ELDHistogram
对象,该对象代理底层 C++的方法,一旦开启监控,就会在 EventLoop 上注册一个回调,每次时间一到就记录相关的值放在HdrHistogram_c 中,它是 C 对HdrHistogram 的实现,可以获取从记录开始到当前时间点的最大、最小、平均值、95 线等数据。
直白点讲就是开启一个定时器,通过向 libuv 注册 uv_timer_t 句柄,执行回调,获取数据存在一个特定的容器中,我们从该容器拿被处理好的数据。
Comments