Node.js は『シングルスレッド』を理解して使い倒す
Node.js は I/O 重視のサービスに強い JavaScript ランタイムですが、本番ではシングルスレッド前提の罠がいくつもあります。本記事では編集部の視点で、運用フェーズの勘所を公開情報をもとに整理します。Next.js App Router 実践 もご参考に。
クラスタリングとプロセス分離
(1) CPU 1コア=1プロセス:cluster モジュールで複数起動。(2) PM2 や systemd:プロセス管理。(3) コンテナならコンテナ単位で並列化:1コンテナ1プロセス推奨。(4) Worker Threads:CPU集約処理を分離。(5) graceful shutdown:keepalive 中の接続も完了。
イベントループのブロッキング対策
(1) CPU 重い処理は禁止:JSON.stringify(大データ) でも止まる。(2) 同期 fs/crypto 禁止:非同期APIへ。(3) 長時間処理は分割:setImmediate でイベントループに譲る。(4) worker_threads / fork:別プロセスへ。(5) p-limit:並列度の制御。
メモリ管理とリーク対策
(1) --max-old-space-size:ヒープ上限。(2) typical sweetspot 512MB〜4GB(用途による)。(3) メモリリークの典型:イベントリスナー過剰登録・キャッシュ無限拡大・グローバル変数蓄積。(4) heap snapshot:Chrome DevTools で分析。(5) --inspect:本番直前にローカルで観察。Observability 実践 も合わせて。
パッケージ管理と依存
(1) pnpm 推奨:高速・厳密な依存解決。(2) lockfile 必須:再現性を保つ。(3) 本番依存と開発依存の分離:dependencies vs devDependencies。(4) セキュリティ監査:npm audit / Dependabot。(5) 古いバージョン放置を避ける:Node LTS の更新追従。
本番監視の必須項目
(1) レイテンシ (p50/p95/p99)。(2) イベントループ遅延:clinic.js / Datadog で計測。(3) ヒープサイズと GC 頻度。(4) アクティブハンドル数:リーク早期発見。(5) 外部依存のエラー率:DB/外部API/キュー。Datadog 活用ガイド もご参考に。
失敗しがちなパターン
(1) CPU 重い処理でリクエスト全滞留。(2) 未処理 Promise rejection:プロセスダウン。(3) 未捕捉例外で再起動ループ。(4) npm install を本番で実行:再現性低下。(5) 古いNode版で運用:セキュリティリスク。対策は、(1)worker_threads/別プロセス、(2)unhandledRejection ハンドラ、(3)uncaughtException + graceful shutdown、(4)CI でビルド済み artifact 配布、(5)LTS追従、です。