メインコンテンツへスキップ
Background Image

Node.js パフォーマンス最適化実践ガイド

🚀 Node.jsパフォーマンス最適化のコア戦略
#

Node.jsは高性能なJavaScriptランタイムとして、適切な最適化戦略により驚異的なパフォーマンスを発揮できます。

✨ 重要な最適化領域
#

  • メモリ管理: メモリリークと過度な割り当ての回避
  • 非同期処理: I/O操作と並行処理の最適化
  • コード実行: CPU集約的操作の削減
  • ネットワーク最適化: HTTPリクエスト処理効率の向上

💾 メモリ最適化
#

1. メモリリーク検出
#

// --inspectフラグでアプリケーションを起動
// node --inspect app.js

// メモリ使用量の監視
const used = process.memoryUsage();
console.log(`メモリ使用量: ${Math.round(used.heapUsed / 1024 / 1024)} MB`);

2. オブジェクトプールパターン
#

class ObjectPool {
  constructor(createFn, resetFn, initialSize = 10) {
    this.createFn = createFn;
    this.resetFn = resetFn;
    this.pool = [];
    
    // オブジェクトの事前作成
    for (let i = 0; i < initialSize; i++) {
      this.pool.push(createFn());
    }
  }

  acquire() {
    return this.pool.pop() || this.createFn();
  }

  release(obj) {
    this.resetFn(obj);
    this.pool.push(obj);
  }
}

// 使用例
const connectionPool = new ObjectPool(
  () => ({ id: Date.now(), status: 'idle' }),
  (conn) => { conn.status = 'idle'; }
);

⚡ 非同期パフォーマンス最適化
#

1. Promise最適化
#

// Promise地獄の回避
async function optimizedUserFlow() {
  try {
    // 独立した操作の並行実行
    const [user, posts, comments] = await Promise.all([
      fetchUser(userId),
      fetchUserPosts(userId),
      fetchUserComments(userId)
    ]);
    
    return { user, posts, comments };
  } catch (error) {
    console.error('ユーザーデータの取得に失敗:', error);
    throw error;
  }
}

2. Streamによる大ファイル処理
#

const fs = require('fs');
const { Transform } = require('stream');

// 変換ストリームの作成
const upperCaseTransform = new Transform({
  transform(chunk, encoding, callback) {
    this.push(chunk.toString().toUpperCase());
    callback();
  }
});

// ファイルのストリーム処理
fs.createReadStream('input.txt')
  .pipe(upperCaseTransform)
  .pipe(fs.createWriteStream('output.txt'));

🔄 並行処理最適化
#

1. Worker Threads
#

const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

if (isMainThread) {
  // メインスレッド
  const worker = new Worker(__filename, {
    workerData: { number: 1000000 }
  });
  
  worker.on('message', (result) => {
    console.log('計算結果:', result);
  });
} else {
  // ワーカースレッド
  const { number } = workerData;
  let result = 0;
  
  for (let i = 0; i < number; i++) {
    result += i;
  }
  
  parentPort.postMessage(result);
}

2. クラスターモード
#

const cluster = require('cluster');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`マスタープロセス ${process.pid} が起動しました`);
  
  // ワーカープロセスの作成
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  
  cluster.on('exit', (worker, code, signal) => {
    console.log(`ワーカー ${worker.process.pid} が終了しました`);
    cluster.fork(); // 新しいワーカーを作成
  });
} else {
  // ワーカープロセス
  require('./app.js');
}

🚀 HTTP最適化
#

1. レスポンス圧縮
#

const express = require('express');
const compression = require('compression');

const app = express();

// 圧縮ミドルウェアの有効化
app.use(compression());

app.get('/api/data', (req, res) => {
  res.json({ message: 'Hello World' });
});

2. キャッシュ戦略
#

const express = require('express');
const app = express();

// 静的ファイルのキャッシュ
app.use(express.static('public', {
  maxAge: '1d',
  etag: true,
  lastModified: true
}));

// APIレスポンスのキャッシュ
app.get('/api/users', (req, res) => {
  res.set('Cache-Control', 'public, max-age=300'); // 5分間キャッシュ
  res.json(users);
});

📊 パフォーマンス監視
#

1. プロファイリング
#

// CPUプロファイリング
const profiler = require('v8-profiler-next');

profiler.startProfiling('CPU Profile');
setTimeout(() => {
  const profile = profiler.stopProfiling();
  profile.export((error, result) => {
    require('fs').writeFileSync('./profile.cpuprofile', result);
    profile.delete();
  });
}, 5000);

2. メモリプロファイリング
#

// メモリプロファイリング
const profiler = require('v8-profiler-next');

profiler.startProfiling('Memory Profile');
setTimeout(() => {
  const profile = profiler.stopProfiling();
  profile.export((error, result) => {
    require('fs').writeFileSync('./profile.heapprofile', result);
    profile.delete();
  });
}, 5000);

💡 ベストプラクティス
#

1. コード最適化
#

// 避けるべきパターン
for (let i = 0; i < array.length; i++) { // 毎回lengthを取得
  // 処理
}

// 推奨パターン
const length = array.length;
for (let i = 0; i < length; i++) {
  // 処理
}

// さらに推奨
array.forEach(item => {
  // 処理
});

2. データベース最適化
#

// 避けるべきパターン
async function getUserPosts(userId) {
  const user = await User.findById(userId);
  const posts = await Post.find({ userId: userId });
  return { user, posts };
}

// 推奨パターン
async function getUserPosts(userId) {
  const [user, posts] = await Promise.all([
    User.findById(userId),
    Post.find({ userId })
  ]);
  return { user, posts };
}

🔧 ツールとライブラリ
#

1. パフォーマンス監視ツール
#

  • clinic.js: Node.jsアプリケーションの診断
  • 0x: フレームグラフによるプロファイリング
  • autocannon: HTTP負荷テスト

2. 最適化ライブラリ
#

// 高速なJSON処理
const fastJson = require('fast-json-stringify');

const stringify = fastJson({
  title: 'string',
  type: 'object',
  properties: {
    name: { type: 'string' },
    age: { type: 'number' }
  }
});

📚 学習リソース
#

🎯 次のステップ
#

Node.jsパフォーマンス最適化の基本を習得したので、次は:

  1. マイクロサービスアーキテクチャでの最適化
  2. 本番環境でのパフォーマンス監視
  3. 負荷テストとキャパシティプランニング
  4. 高度なプロファイリングテクニック

このガイドがNode.jsパフォーマンス最適化の理解と活用に役立つことを願っています!何か質問があれば、コメント欄で議論を歓迎します。