memory-cache

シンプルで効率的なインメモリキャッシュライブラリ。TTL(Time To Live)サポートとコールバック機能を提供する軽量なJavaScriptキャッシュソリューション。

GitHub概要

ptarjan/node-cache

A simple in-memory cache for nodejs

スター1,602
ウォッチ27
フォーク173
作成日:2010年4月29日
言語:JavaScript
ライセンス:BSD 2-Clause "Simplified" License

トピックス

なし

スター履歴

ptarjan/node-cache Star History
データ取得日時: 2025/10/22 10:20

概要

memory-cacheは、Node.jsアプリケーション向けのシンプルかつ効率的なインメモリキャッシュライブラリです。メモリ内にデータを一時的に保存し、高速なデータアクセスを実現します。TTL(Time To Live)機能により、自動的な期限切れ処理もサポートしています。

主な特徴

  • シンプルなAPI: 直感的で使いやすいAPIデザイン
  • TTLサポート: キャッシュエントリの自動期限切れ
  • コールバック機能: 期限切れ時のコールバック処理
  • 複数インスタンス: 独立した複数のキャッシュインスタンスを作成可能
  • 軽量: 外部依存なしの軽量実装
  • 同期処理: 非同期処理の複雑さがない

インストール

npm install memory-cache

または

yarn add memory-cache

基本的な使い方

単一インスタンスの使用

const cache = require('memory-cache');

// データをキャッシュに保存
cache.put('userId:123', { name: '山田太郎', age: 30 });

// キャッシュからデータを取得
const user = cache.get('userId:123');
console.log(user); // { name: '山田太郎', age: 30 }

// キャッシュからデータを削除
cache.del('userId:123');

// キャッシュをクリア
cache.clear();

TTL(Time To Live)の設定

const cache = require('memory-cache');

// 5秒間キャッシュする
cache.put('tempData', 'この情報は5秒後に削除されます', 5000);

// 3秒後に確認
setTimeout(() => {
  console.log(cache.get('tempData')); // データが表示される
}, 3000);

// 6秒後に確認
setTimeout(() => {
  console.log(cache.get('tempData')); // null (期限切れ)
}, 6000);

期限切れコールバック

const cache = require('memory-cache');

// 期限切れ時にコールバックを実行
cache.put('sessionData', 
  { userId: 456, token: 'abc123' }, 
  10000, // 10秒
  (key, value) => {
    console.log(`キャッシュ期限切れ: ${key}`);
    console.log('期限切れデータ:', value);
    // ここでクリーンアップ処理などを実行
  }
);

高度な使い方

複数のキャッシュインスタンス

const Cache = require('memory-cache').Cache;

// 独立したキャッシュインスタンスを作成
const userCache = new Cache();
const sessionCache = new Cache();

// それぞれ独立して動作
userCache.put('user:1', { name: '田中花子' });
sessionCache.put('session:abc', { expires: Date.now() + 3600000 });

console.log(userCache.size());    // 1
console.log(sessionCache.size());  // 1

キャッシュ統計情報

const cache = require('memory-cache');

// 複数のデータを追加
cache.put('key1', 'value1', 1000);
cache.put('key2', 'value2', 2000);
cache.put('key3', 'value3', 3000);

// キャッシュのサイズを取得
console.log('キャッシュサイズ:', cache.size());

// すべてのキーを取得
console.log('すべてのキー:', cache.keys());

// キャッシュメモリ使用量を推定
console.log('メモリ使用量:', cache.memsize());

キャッシュヘルパー関数

const cache = require('memory-cache');

// キャッシュを使用したデータ取得ヘルパー
function getCachedData(key, fetchFunction, ttl = 60000) {
  // キャッシュを確認
  let data = cache.get(key);
  
  if (data === null) {
    // キャッシュにない場合はデータを取得
    data = fetchFunction();
    cache.put(key, data, ttl);
  }
  
  return data;
}

// 使用例
const userData = getCachedData('user:789', () => {
  // 実際のデータ取得処理(DB、APIなど)
  return { id: 789, name: '佐藤次郎' };
}, 300000); // 5分間キャッシュ

実践的な例

API レスポンスキャッシュ

const cache = require('memory-cache');
const axios = require('axios');

class ApiCache {
  constructor(defaultTTL = 60000) {
    this.defaultTTL = defaultTTL;
  }

  async get(url, options = {}) {
    const cacheKey = `api:${url}:${JSON.stringify(options)}`;
    
    // キャッシュを確認
    const cachedResponse = cache.get(cacheKey);
    if (cachedResponse) {
      console.log('キャッシュから返却:', url);
      return cachedResponse;
    }
    
    // APIを呼び出し
    try {
      const response = await axios.get(url, options);
      const data = response.data;
      
      // レスポンスをキャッシュ
      cache.put(cacheKey, data, this.defaultTTL);
      console.log('APIから取得してキャッシュ:', url);
      
      return data;
    } catch (error) {
      console.error('API エラー:', error);
      throw error;
    }
  }

  // キャッシュを無効化
  invalidate(url, options = {}) {
    const cacheKey = `api:${url}:${JSON.stringify(options)}`;
    cache.del(cacheKey);
  }
}

// 使用例
const apiCache = new ApiCache(300000); // 5分のTTL

async function fetchUserData(userId) {
  const data = await apiCache.get(`https://api.example.com/users/${userId}`);
  return data;
}

セッション管理

const Cache = require('memory-cache').Cache;
const crypto = require('crypto');

class SessionManager {
  constructor(sessionTimeout = 1800000) { // 30分
    this.sessions = new Cache();
    this.sessionTimeout = sessionTimeout;
  }

  createSession(userId, userData) {
    const sessionId = crypto.randomBytes(32).toString('hex');
    const sessionData = {
      userId,
      userData,
      createdAt: Date.now(),
      lastAccess: Date.now()
    };

    this.sessions.put(sessionId, sessionData, this.sessionTimeout, (key, value) => {
      console.log(`セッション期限切れ: User ${value.userId}`);
    });

    return sessionId;
  }

  getSession(sessionId) {
    const session = this.sessions.get(sessionId);
    if (session) {
      // アクセス時間を更新
      session.lastAccess = Date.now();
      // TTLをリセット
      this.sessions.put(sessionId, session, this.sessionTimeout);
    }
    return session;
  }

  destroySession(sessionId) {
    this.sessions.del(sessionId);
  }

  getActiveSessions() {
    return this.sessions.size();
  }
}

// 使用例
const sessionManager = new SessionManager();

// セッション作成
const sessionId = sessionManager.createSession(123, { 
  name: '山田太郎',
  role: 'admin' 
});

// セッション取得
const session = sessionManager.getSession(sessionId);
console.log('アクティブセッション数:', sessionManager.getActiveSessions());

計算結果のメモ化

const cache = require('memory-cache');

function memoize(fn, ttl = 60000) {
  return function(...args) {
    const key = `memo:${fn.name}:${JSON.stringify(args)}`;
    
    const cachedResult = cache.get(key);
    if (cachedResult !== null) {
      console.log('キャッシュから返却');
      return cachedResult;
    }
    
    const result = fn.apply(this, args);
    cache.put(key, result, ttl);
    console.log('計算して保存');
    
    return result;
  };
}

// 重い計算処理の例
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// メモ化された関数
const memoizedFibonacci = memoize(fibonacci, 300000); // 5分間キャッシュ

// 最初の呼び出しは計算される
console.time('first');
console.log(memoizedFibonacci(40));
console.timeEnd('first');

// 2回目の呼び出しはキャッシュから
console.time('second');
console.log(memoizedFibonacci(40));
console.timeEnd('second');

他のキャッシュライブラリとの比較

memory-cache vs node-cache

特徴memory-cachenode-cache
API のシンプルさ
TTL サポート
統計情報
イベント×
型定義×

memory-cache vs lru-cache

特徴memory-cachelru-cache
メモリ効率
LRU アルゴリズム×
TTL
パフォーマンス

ベストプラクティス

1. キャッシュキーの命名規則

// 良い例:構造化されたキー
const userKey = `user:${userId}`;
const apiKey = `api:${endpoint}:${JSON.stringify(params)}`;
const sessionKey = `session:${sessionId}`;

// 悪い例:構造化されていないキー
const key1 = userId;
const key2 = 'data';

2. 適切なTTLの設定

const TTL = {
  SESSION: 30 * 60 * 1000,     // 30分
  API_RESPONSE: 5 * 60 * 1000,  // 5分
  STATIC_DATA: 24 * 60 * 60 * 1000, // 24時間
  TEMP_DATA: 60 * 1000          // 1分
};

cache.put('session:123', sessionData, TTL.SESSION);
cache.put('api:users', userData, TTL.API_RESPONSE);

3. エラーハンドリング

function safeGet(key, defaultValue = null) {
  try {
    const value = cache.get(key);
    return value !== null ? value : defaultValue;
  } catch (error) {
    console.error('キャッシュ取得エラー:', error);
    return defaultValue;
  }
}

4. メモリ管理

// 定期的なメモリ使用量チェック
setInterval(() => {
  const memSize = cache.memsize();
  const itemCount = cache.size();
  
  console.log(`キャッシュ統計 - アイテム数: ${itemCount}, メモリ: ${memSize}`);
  
  // 必要に応じてクリア
  if (memSize > 100 * 1024 * 1024) { // 100MB以上
    cache.clear();
    console.log('メモリ制限によりキャッシュをクリア');
  }
}, 60000); // 1分ごと

まとめ

memory-cacheは、シンプルさと使いやすさを重視したインメモリキャッシュライブラリです。複雑な機能は持たない代わりに、基本的なキャッシュ機能を確実に提供し、小規模から中規模のアプリケーションに最適です。より高度な機能(LRU、統計情報、イベントなど)が必要な場合は、node-cacheやlru-cacheなどの代替ライブラリを検討することをお勧めします。