Node.jsで大容量ファイルを扱う:AIモデルのような大きなデータ保存はストリーム処理使いましょう

Node.jsで大容量ファイルを扱う:AIモデルのような大きなデータ保存はストリーム処理使いましょう

こんにちは!今日はAIシステムのフロントサーバーとしてもよく使用するNode.jsについてのお話です。

AIモデルの普及に伴い、大容量のデータファイルを扱う機会が急増しています。LLMなどのモデルファイルやトレーニングデータセットは数GB、場合によっては数十、数百GBにも達することがあります。

一方、Node.jsはWebアプリケーションのフロントサーバーとして広く採用されており、データマネジメントやPythonで書かれたAIバックエンドとの橋渡し役としてもかなりお役立ちな存在です。

本記事では、Node.js v20LTSで5GB程度のファイルを処理しようとして遭遇した問題と、その解決方法について解説します。

Node.jsのバッファサイズ制限の変遷

Node.jsのバッファサイズ制限は、バージョンによって大きく変化してきました

Node.jsバージョン サポート終了日 バッファサイズ上限 備考
Node.js 0.12.x 2016年12月31日 ~1GB 初期のバッファサイズ制限(smalloc.kMaxLength使用)
Node.js 4.x (Argon) 2018年4月30日 ~2GB V8 4.4での書き換えにより制限が拡大
Node.js 6.x (Boron) 2019年4月30日 32ビット符号付き整数の最大値
Node.js 8.x (Carbon) 2019年12月31日 OpenSSL 1.0.2のEOLに合わせて早期終了
Node.js 10.x (Dubnium) 2021年4月30日 32ビット符号付き整数の最大値
Node.js 12.x (Erbium) 2022年4月30日 32ビット符号付き整数の最大値
Node.js 14.x (Fermium) 2023年4月30日 途中から4GBに拡大
Node.js 16.x 2023年9月11日 ~4GB OpenSSL 1.1.1のサポート終了に合わせてEOLが早まった
Node.js 17.x 2022年6月1日 奇数バージョンは短期サポート
Node.js 18.x 2025年4月30日 現在メンテナンスLTSフェーズ
Node.js 19.x 2023年6月1日 奇数バージョンは短期サポート
Node.js 20.x 2026年4月30日 現在アクティブLTSフェーズ
Node.js 21.7.2 2024年6月1日
Node.js 21.7.3 2024年6月1日 ~8TB v21.7.3でバッファサイズ上限が大幅拡大
Node.js 22.x (Jod) 2027年4月30日 2024年10月29日にLTSに移行
Node.js 23.x 2025年6月1日 奇数バージョンは短期サポート

Node.js v20LTSでは理論上は4GBまでのバッファを扱えるようになっていますが、I/O操作(ファイルの読み書き)における制限が依然として存在します。これはNode.js自体ではなく、その下層で動作するlibuv(非同期I/Oライブラリ)の制限によるものです。

実際に遭遇した問題:5GBのAIモデルファイル

あるプロジェクトで、5GBのAIモデルファイルをモデル管理サーバーとして使っているNode.js v20 LTSを経由して保存しようとした際、以下のコードを使用しました:

save_file(target_dir, file_name, file_buffer) {
  try {
    // 保存先ディレクトリが存在しない場合は作成
    if (!fs.existsSync(target_dir)) {
      fs.mkdirSync(target_dir, { recursive: true });
    }

    const file_path = path.join(target_dir, file_name);
    fs.writeFileSync(file_path, file_buffer);
    return true;
  } catch (error) {
    console.error(`ファイル保存エラー: ${error.message}\n${error.stack}`);
    return false;
  }
}

すると、以下のようなエラーが発生しました

ファイル保存エラー: The value of "length" is out of range. It must be >= 0 && <= 4294967295. Received 5368709120

このエラーは、Node.js v20LTSのバッファ制限が4GBであるのに対し、我々が扱おうとしていたファイルは5GB(5,368,709,120バイト)だったことを示しています。
こうやって無邪気なコードをかきましたが、巨大ファイルをこのような方法で保存するのはいただけないです。

エラーのとおり、5GBのファイルを一度に処理することはできないことが分かります。

(5GBならかわいいもんですが、素人が数百GBクラスのモデルデータをあつかうと、通常のコードは何でもなかったコードが一斉に不具合に見舞われたりします。)

解決策:ストリーム処理と非同期I/O

さて、この問題を解決するために、ストリーム処理と非同期I/Oを採用したアプローチに切り替えました

async save_file(target_dir, file_name, input_data) {
  try {
    // 保存先ディレクトリが存在しない場合は作成(非同期版)
    await fs.promises.mkdir(target_dir, { recursive: true });

    const file_path = path.join(target_dir, file_name);
    
    // ストリームを使用してファイルを書き込む
    const writeStream = fs.createWriteStream(file_path);
    
    // Bufferの場合
    if (Buffer.isBuffer(input_data)) {
      // チャンクに分割して書き込む
      const chunkSize = 1024 * 1024; // 1MBずつ
      for (let i = 0; i < input_data.length; i += chunkSize) {
        const chunk = input_data.slice(i, Math.min(i + chunkSize, input_data.length));
        writeStream.write(chunk);
      }
      writeStream.end();
    } 
    // ストリームの場合
    else if (typeof input_data.pipe === 'function') {
      input_data.pipe(writeStream);
    }
    // その他の場合(文字列など)
    else {
      writeStream.write(input_data);
      writeStream.end();
    }

    // 完了または失敗を待機する
    await new Promise((resolve, reject) => {
      writeStream.on('finish', resolve);
      writeStream.on('error', reject);
    });
    
    return true;
  } catch (error) {
    console.error(`ファイル保存エラー: ${error.message}\n${error.stack}`);
    throw error; // asyncメソッドなのでthrowを使う
  }
}

この改善版コードを使って5GBのモデルファイルを問題なく保存できるようになりました。

主な改善点は以下の通りです

  1. ストリーム処理
    データを小さなチャンク(1MB)に分割して処理することで、バッファサイズの制限を回避しました。
  2. 非同期処理
    async/awaitを使用することで、ファイル処理中もサーバーが他のリクエストに応答できるようになりました。
  3. プログレス表示の実装
    大きなファイルの転送過程を監視するために、チャンク単位のプログレス表示も組み込みました(コード例では省略)。

ということで、巨大ファイルを扱い、安定性を向上するためには、キャッシュ・ストリーミング・非同期での処理が非常に重要となります。

最新のNode.js(2025年4月時点でv.23)でも注意が必要

さて、Node.js v22以降では理論上8TBまでのバッファを扱えるようになりますが、実際のI/O操作ではまだ制限があるため、大きなファイルを扱う際にはどのバージョンでもストリーム処理を採用することがおすすめです。

(おまけ)さらに、マルチコアを活かすことで、パフォーマンス向上・最適化

Node.jsは単一スレッドで動作するため、CPUバウンドな処理を行う場合、マルチコアのパフォーマンスを活かしきれません。これを解決するのがclusterモジュールです。

今回のように単純なファイル保存の場合、基本的に単一ファイルへの書き込みはI/Oバウンドな処理で、OSのファイルシステムによって直列化されますので、複数のプロセスからの保存には実はそんなに意味がありません。まして、同じファイルに同時に書き込むと、ファイルシステムのロックやシークポインタの競合が発生し、むしろパフォーマンスが低下する可能性すらあります。

ただ、ファイルに対して一定の処理を行ったりする場合には、マルチコアにすることで、パフォーマンスを向上できる可能性もありますので、ご紹介します。

cluster モジュールの基本的な使い方

import cluster from 'node:cluster';
import http from 'node:http';
import { cpus } from 'node:os';
import process from 'node:process';

const numCPUs = cpus().length;

if (cluster.isPrimary) {
  console.log(`メインプロセス ${process.pid} 実行中`);
  
  // CPUコア数分のワーカーを起動
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  
  cluster.on('exit', (worker, code, signal) => {
    console.log(`ワーカー ${worker.process.pid} が終了しました`);
    // 必要に応じてワーカーを再起動
    cluster.fork();
  });
} else {
  // ワーカーは同じポートでHTTPサーバーを起動
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('Hello World\n');
  }).listen(8000);
  
  console.log(`ワーカー ${process.pid} 起動完了`);
}

大容量ファイル処理での最適化の組み合わせ

大容量ファイル+何等かな処理(CPUバウンドな)を扱う場合は、ストリーム処理とclusterモジュールを組み合わせることで、さらに効率的な処理が可能になります

  1. CPUコア数の最適利用
    clusterモジュールでCPUコア数分のプロセスを起動
  2. ストリーム処理
    各ワーカープロセス内でチャンク単位のストリーム処理を実装
  3. 負荷分散
    大きなファイルをワーカー間で分割処理(例: 範囲ごとに担当を分ける)

まとめ

AIモデルのような大容量ファイルを扱うNode.jsアプリケーションのストリーム処理についてご紹介しました。巨大ファイルはストリーム処理と非同期I/O操作を組み合わせることで効率的に扱うことができます

それではまた次回おあいしましょう!

Read more

AIエージェントを"事業に載せる"ために【第3回】AI導入を止めないために、実務で先に設計すべきこと

AIエージェントを"事業に載せる"ために【第3回】AI導入を止めないために、実務で先に設計すべきこと

— AI導入を"事業に載せる"ために、いま設計すべきこと(全3回) こんにちは!Qualitegコンサルティングチームです。 今回の「AI導入を“事業に載せる”ために、いま設計すべきこと」シリーズも、いよいよ第3回です。 第1回では、実際のAI導入事故を通じて、AIエージェントのリスクが単なる技術不良ではなく、権限や運用設計の不在から生まれることを見てきました。第2回では、事故が起きたときに責任をどこに置くのか、法務・契約・組織の観点から責任分解の難しさを整理しました。 では、AI導入を止めずに前に進めるためには、実務として何を先に設計しておくべきなのでしょうか。 本記事では、品質保証の転換、人間レビューの限界、海外で進む保険市場の変化も踏まえながら、AIエージェント導入前に設計すべき5つの領域と、経営として先に答えるべき3つの問いを整理します。 1. 品質保証の転換:「AIは自信を持って間違える」を前提にする 従来のソフトウェアの品質保証は、少なくとも同じ入力に対して同じ結果を期待しやすく、仕様・テスト・再現性を軸に品質を確認する考え方に立っていました。 ISACA

By Qualiteg コンサルティング
主要LLMプロバイダーのAPI料金表 — Claude / GPT / Gemini/Grok 【2026年5月13日時点】

主要LLMプロバイダーのAPI料金表 — Claude / GPT / Gemini/Grok 【2026年5月13日時点】

こんにちは、 今回は、主要LLMプロバイダー( Claude / GPT /Gemini/Grok)のAPI料金表  をまとめてみました。(2026年5月13日時点) プロバイダ別 料金一覧 まずは各社の現行ラインナップを縦に並べた一覧をご紹介します。価格はすべて per 1M tokens、円表記は 1ドル=160円換算です。 Anthropic(Claude) モデル Status Context Input Output Cached Input Claude Opus 4.7 Fast Mode Beta(Opus専用) 1M $30.00<br>(¥4,800) $150.00<br>

By Qualiteg プロダクト開発部
コーディングエージェントの現状と未来への展望 【第3回】"書くAI"から"指揮するAI"へ──2026年の開発現場で起きている変化

コーディングエージェントの現状と未来への展望 【第3回】"書くAI"から"指揮するAI"へ──2026年の開発現場で起きている変化

こんにちは! コーディングエージェントシリーズ、ついに最終回です! 2026年に入り、Claude Code、Cursor 3、GitHub Copilot Coding Agentはいずれも、単なるコード補完やチャット型支援を超え、複数エージェントを使った開発ワークフローへ進化しつつあります。本稿では、AIコーディングエージェントの最新動向を、Claude CodeのAuto Memory / Subagents、Cursor 3のAgents Window、GitHub CopilotのCoding Agent、そしてSWE-benchの読み方まで含めて整理します。 第1回では、2025年12月時点で百花繚乱状態にあったAIコーディングエージェントの全体像を俯瞰し、商用からOSSまで20以上のツールを「CLIベース」「IDE統合型」「AI特化IDE型」「自律型」の4つのカテゴリに整理しました。 第2回では、Claude Code・Codex CLI・Aiderを詳細比較したうえで、現在のコーディングエージェントが共通して抱える構造的課題——コンテキストウィンドウの限界、セッ

By Qualiteg コンサルティング
Windows版 Claude Code を irm でインストールして「claude is not recognized」を直すまで

Windows版 Claude Code を irm でインストールして「claude is not recognized」を直すまで

こんにちは! 公式PowerShellインストーラー(irm https://claude.ai/install.ps1 | iex)で Claude Code を入れたのに、claude --version を叩くと「The term 'claude' is not recognized as a name of a cmdlet...」と怒られるときがあります これは Anthropic 公式 GitHub にも報告されている 既知のバグで、インストーラーが PATH の追加を忘れています。実際にインストール作業をやって詰まったので、最短の解決手順をまとめます。 環境 * Windows 11 * PowerShell 7.x(コードは PowerShell

By Qualiteg プロダクト開発部