性能を読み解く(公開ベンチから)
ここまで内部実装の進化を 4 段階に分けて見てきた。読者として最後に気になるのは「で、結局自分のアプリではどれくらいの差なの?」だろう。
ベンチを自前で取りたいところだが、Node.js の性能は環境(CPU/メモリ/カーネル)と workload(CPU bound / I/O bound)で大きく変わる。むしろ信頼できる公開ベンチを文脈付きで読む方が実用的だ。この章ではそれをやる。
ベンチを読む前に注意すべきこと
- microbench と実アプリの数値は別物。microbench は ALS 単体の overhead を測るが、実アプリでは I/O や DB 待ちが支配的で ALS の overhead は薄まる
- 環境を必ず確認。CPU 世代、Node のマイナーバージョン、libuv のスレッドプール設定で結果が変わる
- ALS あり / なしだけでなくNode のバージョン間の比較も意識する。同じ ALS でも 22 と 24 では中身が違う
各ベンチを実装と紐づけて読む
Issue #34493(2020):「97% 性能低下」
旧 createHook 実装の悪名。報告者のベンチでは、async ヘビーな環境で 97% のスループット低下。第 3 章で見たように、当時の ALS は全 Promise 生成で C++ → JS の境界跨ぎが起きる構造だったため、Promise 数 × 境界跨ぎコストが積み重なる。
PR #36394 ベンチ(2020-21):271k → 1.25M ops/sec
第 4 章の主役。V8 PromiseHook API 刷新の効果:
| 状態 | スループット | 備考 |
|---|---|---|
| disabled(フックなし) | 1,672,015 ops/sec | 上限 |
| 旧 enabled | 271,514 ops/sec | -83.7% |
| 新 enabled | 1,250,448 ops/sec | -25.2% |
約 4.6 倍の改善。境界跨ぎの除去が効いた。
Platformatic ベンチ(2025):実アプリ近傍
Platformatic Blog “The Hidden Cost of Async Context” の実測。環境は Intel i7-7700 / 62GB RAM / 100 並行接続 × 10 req × 10 秒。HTTP サーバー越しの req/s。
| Node | ALS なし | ALS あり | 低下率 |
|---|---|---|---|
| v22.17.1 | 56,446 req/s | 50,913 req/s | -9.8% |
| v24.4.1 | 57,301 req/s | 53,450 req/s | -6.7% |
第 5 章で見た AsyncContextFrame が、v22 → v24 で約 5% の改善(ALS 自体)に直接対応する。実アプリ環境で 6-10% の overhead は、運用上は許容範囲と判断するチームが多い数値だ。
Platformatic ベンチ:OpenTelemetry の重さ
同じベンチで OpenTelemetry の full instrumentation を有効にすると:
| Node | スループット | ベースから |
|---|---|---|
| v24 + ALS のみ | 53,450 req/s | -6.7% |
| v24 + OpenTelemetry full | 10,640 req/s | -81.4% |
ALS だけなら 6.7% だが、OpenTelemetry の全部入りは 80% 超の低下。これは ALS の問題ではない ── OpenTelemetry が async_hooks.createHook() を直接使っており、フック発火が大量に走るためだ。第 2 章で公式が「migrate away」と書いていたまさにその構造を、APM ツールが踏み抜いている。
第 8 章で扱う 2026/1 の DoS 脆弱性で「APM ツールが軒並み被弾した」のも、この依存関係に根がある。
Aschen microbench(2020 頃):25% 低下
Aschen の Gist は ALS 単体の microbench で 25% 低下を計測した。これは Issue #34493 と同時代の数値で、第 3 章で見た旧実装 の素のコスト。同じ条件で v24 を測ると数値は劇的に変わる(公開された具体値はないが、PR #36394 の延長で 70-80% の改善が想定される)。
Kuzzle 実アプリ(2020):8% 低下
旧実装でも実アプリでは 8% 程度の低下に収まったというデータ。microbench の 25% と差があるのは「実アプリでは I/O 待ちが支配的」だから。これは「数字を見る時の解像度」を上げる材料:microbench で 25% 低下 = 実アプリで 25% 遅くなる、ではない。
数値のサマリ
graph TB
A[Node 13.10 当初実装<br/>microbench -25%<br/>Issue #34493 では -97% 報告]
B[Node 16+ V8 PromiseHook<br/>microbench で 4.6x 改善]
C[Node 24 AsyncContextFrame<br/>実アプリで -6.7%<br/>v22 比 約 5% 改善]
D[OpenTelemetry full<br/>-81.4%]
A --> B --> C
C -.APM 系は別問題.- D
style A fill:#ffe1e1
style B fill:#fff4e1
style C fill:#e1ffe1
style D fill:#ffe1e1
運用判断の指針
これらの数値から、運用上の判断は次のようにできる:
- 新規プロジェクト: ALS をリクエストスコープに使うのは合理的。Node 22+ で性能影響は ~10% 内、Node 24 では ~7% 内
- 既存アプリで ALS を導入する場合: 自分の workload(I/O 中心 vs CPU 中心)を意識。I/O 中心ならほぼ気にならない、CPU 中心なら測ってから
- APM / OpenTelemetry 全面導入は慎重に: 80% 落ちる workload もある。サンプリング・選択的計装で抑える前提
この章の要点
- 公開ベンチは microbench と実アプリで数値感が違う。前者は内部 overhead、後者は workload で薄まった結果
- 旧実装(〜Node 15)は microbench で深刻、実アプリでは中程度(Kuzzle 8% / Issue 97%)
- PR #36394 で 4.6x 改善、Node 24 でさらに ~5% 改善(実アプリベンチ)
- OpenTelemetry の 80% 低下は ALS ではなく
createHook直叩きが原因 - 運用判断: ALS は ~10% で許容、APM 全面導入は別途検討
次章への問いかけ
数値で見えた。だが、この OpenTelemetry の話の延長線上で、2026 年 1 月、本当の事件が起きた。
なぜ React Server Components / Next.js は無事で、APM 各社は被弾したのか。次章で見る。