Engineer Quiz

← 記事一覧

キャッシュ戦略の基礎 - Redis vs Memcached

キャッシュ戦略の基礎 - Redis vs Memcached

📚 概要

キャッシュは、アプリケーションのパフォーマンスを劇的に向上させる重要な技術です。データベースへの繰り返しクエリを削減し、レスポンス時間を短縮します。

この記事では、最も人気のあるキャッシュソリューション RedisMemcached について、歴史的背景から実践的な使い分けまで解説します。

🕰️ 歴史的背景

キャッシュの誕生

キャッシュという概念は、1960年代のメインフレームコンピュータの時代に遡ります。当時、CPUとメモリの速度差を埋めるために、高速な小容量メモリ(キャッシュメモリ)が導入されました。

Webアプリケーションとキャッシュ

2000年代初頭、Web 2.0の時代になると、動的なWebアプリケーションが増加しました。データベースへのアクセスがボトルネックとなり、分散キャッシュの需要が高まりました。

Memcached の誕生(2003年)

  • 開発者: Brad Fitzpatrick(LiveJournal創業者)
  • 背景: LiveJournalのデータベース負荷を軽減するために開発
  • 特徴: シンプルで高速なkey-valueストア

Redis の誕生(2009年)

  • 開発者: Salvatore Sanfilippo
  • 背景: リアルタイムWebアプリケーションのニーズに応えるため
  • 特徴: より多機能なデータ構造をサポート

🔧 技術解説

キャッシュの基本概念

フロー図:キャッシュヒットとミスの流れ

graph LR
    A[Client] --> B{Cache Check}
    B -->|Hit| C[Return from Cache]
    B -->|Miss| D[Query Database]
    D --> E[Store in Cache]
    E --> F[Return Data]
    C --> G[Fast Response]
    F --> G
    
    style C fill:#51cf66
    style D fill:#ff6b6b
  • Cache Hit: キャッシュにデータがある場合(1-5ms)
  • Cache Miss: キャッシュになく、DBクエリが必要(10-100ms)

Redis vs Memcached 比較表

特徴 Redis Memcached
データ構造 String, List, Set, Hash, Sorted Set String のみ
永続化 RDB, AOF なし(メモリのみ)
レプリケーション Master-Slave なし
トランザクション あり なし
パブサブ あり なし
Lua スクリプト あり なし
メモリ効率 やや劣る 優れている
マルチスレッド シングルスレッド マルチスレッド

Redis の特徴

1. 豊富なデータ構造

# String
redis.set("user:1000:name", "Alice")

# Hash
redis.hset("user:1000", mapping={
    "name": "Alice",
    "email": "alice@example.com",
    "age": 30
})

# List
redis.lpush("recent:logs", "User login at 10:00")

# Sorted Set
redis.zadd("leaderboard", {"Alice": 1000, "Bob": 950})

2. 永続化

永続化の仕組み

graph TB
    A[Redis Server] --> B{Persistence Mode}
    B --> C[RDB Snapshot]
    B --> D[AOF Log]
    C --> E[Save to Disk Periodically]
    D --> F[Record All Write Operations]
    
    style C fill:#4dabf7
    style D fill:#74c0fc
  • RDB: 定期的にスナップショットを保存
  • AOF: 全ての書き込み操作をログとして記録

Memcached の特徴

1. シンプルさと高速性

# Simple key-value operations
memcache.set("session:abc123", {"user_id": 1000}, time=3600)
value = memcache.get("session:abc123")

2. マルチスレッド

Memcachedはマルチスレッドで動作し、複数のCPUコアを効率的に利用できます。

💡 実践例

ユースケース1: APIレスポンスのキャッシュ

// Redis-based API cache
async function getUserData(userId: number) {
  const cacheKey = `user:${userId}`;
  
  // 1. Check cache
  const cached = await redis.get(cacheKey);
  if (cached) {
    return JSON.parse(cached);
  }
  
  // 2. Cache miss - fetch from DB
  const user = await db.query("SELECT * FROM users WHERE id = $1", [userId]);
  
  // 3. Store in cache with TTL
  await redis.setex(cacheKey, 3600, JSON.stringify(user));
  
  return user;
}

ユースケース2: セッション管理

// Memcached for session management
app.post("/login", async (c) => {
  const { username, password } = await c.req.json();
  
  // Authenticate
  const user = await authenticate(username, password);
  
  // Generate session ID
  const sessionId = generateSessionId();
  
  // Store in Memcached with TTL: 24h
  await memcached.set(`session:${sessionId}`, {
    userId: user.id,
    username: user.username
  }, 86400);
  
  return c.json({ sessionId });
});

📊 パフォーマンス比較

10,000リクエストの処理

パフォーマンス差の図

graph TB
    subgraph NoCache[Without Cache]
    A1[10000 requests] --> B1[DB Query x3]
    B1 --> C1[Total: 300s]
    end
    
    subgraph WithCache[With Redis Cache]
    A2[10000 requests] --> B2[Redis Cache]
    B2 --> C2[Total: 10s]
    end
    
    style C1 fill:#ff6b6b
    style C2 fill:#51cf66

結果: キャッシュ導入で 30倍 の速度改善!

  • キャッシュなし: 300秒(各リクエスト30ms)
  • Redisキャッシュ: 10秒(各リクエスト1ms)

🎯 使い分けガイド

Redis を選ぶべき場合

  • ✅ データ永続化が必要
  • ✅ 複雑なデータ構造を扱う(List, Set, Hash等)
  • ✅ レプリケーションやフェイルオーバーが必要
  • ✅ パブサブ機能を使いたい
  • ✅ Lua スクリプトで複雑な処理を実行したい

Memcached を選ぶべき場合

  • ✅ シンプルな key-value キャッシュで十分
  • ✅ メモリ効率を最大化したい
  • ✅ マルチスレッドのパフォーマンスが必要
  • ✅ セッション管理のみの用途

🔍 関連する問題

この記事に関連するクイズ問題:

  • Q1: APIで各リクエストがDBクエリを3回実行。10,000req/s処理するボトルネック解消策は?
  • Q7: 低カーディナリティカラムのインデックス問題は?
  • Q31: Dockerの主なメリットは?

📝 まとめ

  • キャッシュ は、データベース負荷を削減し、レスポンス時間を劇的に改善する
  • Redis は多機能で永続化に対応し、複雑なユースケースに最適
  • Memcached はシンプルで高速、純粋なキャッシュ用途に最適
  • 適切な選択 は、要件(永続化、データ構造、パフォーマンス)に基づいて行う

次のステップ: 実際のプロジェクトにRedisまたはMemcachedを導入し、パフォーマンスを測定してみましょう!