jakub holý

building the right thing, building it right, fast

Beware the performance cost of async_hooks (Node 8)


I was excited about async_hooks having finally landed in Node.js 8, as it would enable me to share important troubleshooting information with all code involved in handling a particular request. However it turned out to have terrible impact of our CPU usage (YMMV):

This was quite extreme and is likely related to the way how our application works and uses Promises. Do your own testing to measure the actual impact in your app.

However I am not the only one who has seen some performance hit from async_hooks - see https://github.com/bmeurer/async-hooks-performance-impact, in particular:

Here the results of running the Promise micro benchmarks with and without async_hooks enabled:

Benchmark Node 8.9.4 Node 9.4.0
Bluebird-doxbee (regular) 226 ms 189 ms
Bluebird-doxbee (init hook) 383 ms 341 ms
Bluebird-doxbee (all hooks) 440 ms 411 ms
Bluebird-parallel (regular) 924 ms 696 ms
Bluebird-parallel (init hook) 1380 ms 1050 ms
Bluebird-parallel (all hooks) 1488 ms 1220 ms
Wikipedia (regular) 993 ms 804 ms
Wikipedia (init hook) 2025 ms 1893 ms
Wikipedia (all hooks) 2109 ms 2124 ms

To confirm the impact of async_hook on our app, I have performed 3 performance tests:

CPU usage without async_hooks (Node 8)

It is difficult to see but the mean CPU usage is perhaps around 60% here.

CPU usage with "no-op" async_hooks (Node 8)

Here the CPU jumped to 100%.

CPU usage with "no-op" async_hooks (Node 11)

The same as above, but using Node 11 for comparison. I recorded it for just a few minutes but the CPU usage is still around 100%:

The code

This is the relevant code:
const asyncHooks = require('async_hooks'); // Node 8.9+
const querystring = require('querystring');
const crypto = require("crypto");
const context = {};
function createHooks() {
function init(asyncId, type, triggerId, resource) {
// if (context[triggerId]) {
// context[asyncId] = context[triggerId];
// }
function destroy(asyncId) {
// delete context[asyncId];
const asyncHook = asyncHooks.createHook({ init, destroy });
view raw async-context.js hosted with ❤ by GitHub