AsyncLocalStorage 性能损耗测试

序言

Ref: https://github.com/nodejs/node/issues/34493

自己的某个项目中,内置的任务流系统依赖 AsyncLocalStorage,偶然看到一个关于 AsyncLocalStorage 性能损耗的 issue,自己也测了一下。

代码是测试极端情况下 async_hook 的损耗,循环大量的 async 函数。

https://github.com/nodejs/node/pull/36394 在 node 14.18、16.2 之后被加入,解决了这个问题。

测试使用阿里云 ECS(规格 ecs.g7.xlarge 4 核 16G)。测试结果中,除了 node 12 特别差劲意外,后面的大版本的实际上还好。

14 意料之外的快。16 Active LTS,也不错。18 不如 16,不知道怎么回事。不过靠前的几个 node 16 小版本也是相当拉胯,可以等 18 晋升为 LTS 后再试一下。

当 async 函数相对不那么多的时候,性能损耗通常不到 1%。

const { AsyncLocalStorage } = require('async_hooks')
const asyncLocalStorage = new AsyncLocalStorage()

let fn = async () => {
    /test/.test('test')
}


let runWithExpiry = async (expiry, fn) => {
    let iterations = 0
    while (Date.now() < expiry) {
        await fn()
        iterations++
    }
    return iterations
};

(async () => {

    console.log(`Performed ${await runWithExpiry(Date.now() + 100, fn)} iterations to warmup`)

    asyncLocalStorage.run({}, () => {
    })
    let withAls = await runWithExpiry(Date.now() + 1000, fn)
    console.log(`Performed ${withAls} iterations (with ALS enabled)`)

    asyncLocalStorage.disable()
    let withoutAls = await runWithExpiry(Date.now() + 1000, fn)
    console.log(`Performed ${withoutAls} iterations (with ALS disabled)`)

    console.log('ALS penalty: ' + Math.round((1 - (withAls / withoutAls)) * 10000) / 100 + '%')
})()

12 (95%+ 性能损耗)

[17:58:09] root :: s52  ➜  ~ » for i in {1..5}; do docker run -v ~/als.js:/tmp/als.js node:12 -- /tmp/als.js; done;
Performed 827790 iterations to warmup
Performed 355830 iterations (with ALS enabled)
Performed 8195377 iterations (with ALS disabled)
ALS penalty: 95.66%
Performed 869600 iterations to warmup
Performed 360341 iterations (with ALS enabled)
Performed 7745751 iterations (with ALS disabled)
ALS penalty: 95.35%
Performed 808719 iterations to warmup
Performed 357185 iterations (with ALS enabled)
Performed 7878044 iterations (with ALS disabled)
ALS penalty: 95.47%
Performed 842619 iterations to warmup
Performed 360615 iterations (with ALS enabled)
Performed 7994690 iterations (with ALS disabled)
ALS penalty: 95.49%
Performed 868442 iterations to warmup
Performed 347041 iterations (with ALS enabled)
Performed 6918083 iterations (with ALS disabled)
ALS penalty: 94.98%

14

[17:58:36] root :: s52  ➜  ~ » for i in {1..5}; do docker run -v ~/als.js:/tmp/als.js node:14 -- /tmp/als.js; done;
Performed 809831 iterations to warmup
Performed 3549429 iterations (with ALS enabled)
Performed 7401508 iterations (with ALS disabled)
ALS penalty: 52.04%
Performed 800033 iterations to warmup
Performed 3290075 iterations (with ALS enabled)
Performed 7198316 iterations (with ALS disabled)
ALS penalty: 54.29%
Performed 825597 iterations to warmup
Performed 3446828 iterations (with ALS enabled)
Performed 7448096 iterations (with ALS disabled)
ALS penalty: 53.72%
Performed 825476 iterations to warmup
Performed 3494714 iterations (with ALS enabled)
Performed 7265595 iterations (with ALS disabled)
ALS penalty: 51.9%
Performed 794054 iterations to warmup
Performed 3512392 iterations (with ALS enabled)
Performed 7504655 iterations (with ALS disabled)
ALS penalty: 53.2%

16

[17:59:57] root :: s52  ➜  ~ » for i in {1..5}; do docker run -v ~/als.js:/tmp/als.js node:16 -- /tmp/als.js; done;
Performed 652721 iterations to warmup
Performed 3462456 iterations (with ALS enabled)
Performed 6474613 iterations (with ALS disabled)
ALS penalty: 46.52%
Performed 708783 iterations to warmup
Performed 3459315 iterations (with ALS enabled)
Performed 6651899 iterations (with ALS disabled)
ALS penalty: 48%
Performed 669400 iterations to warmup
Performed 3436014 iterations (with ALS enabled)
Performed 6370868 iterations (with ALS disabled)
ALS penalty: 46.07%
Performed 707550 iterations to warmup
Performed 3526946 iterations (with ALS enabled)
Performed 6582745 iterations (with ALS disabled)
ALS penalty: 46.42%
Performed 711092 iterations to warmup
Performed 3526942 iterations (with ALS enabled)
Performed 6634118 iterations (with ALS disabled)
ALS penalty: 46.84%

18

[18:00:51] root :: s52  ➜  ~ » for i in {1..5}; do docker run -v ~/als.js:/tmp/als.js node:18 -- /tmp/als.js; done;
Performed 718358 iterations to warmup
Performed 3198417 iterations (with ALS enabled)
Performed 6309644 iterations (with ALS disabled)
ALS penalty: 49.31%
Performed 725577 iterations to warmup
Performed 3277435 iterations (with ALS enabled)
Performed 6654100 iterations (with ALS disabled)
ALS penalty: 50.75%
Performed 719344 iterations to warmup
Performed 3319792 iterations (with ALS enabled)
Performed 6737871 iterations (with ALS disabled)
ALS penalty: 50.73%
Performed 720873 iterations to warmup
Performed 3250289 iterations (with ALS enabled)
Performed 6794669 iterations (with ALS disabled)
ALS penalty: 52.16%
Performed 723713 iterations to warmup
Performed 3302753 iterations (with ALS enabled)
Performed 6829438 iterations (with ALS disabled)
ALS penalty: 51.64%

CC BY-NC-SA 4.0 本作品使用基于以下许可授权:Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注