分散キャッシュ比較:Redis vs Memcached vs Dragonfly でDBの負荷を削減する
オープンソースラボ編集部 ・ 2026年6月14日
分散キャッシュ比較:Redis vs Memcached vs Dragonfly でDBの負荷を削減する
Webアプリケーションのボトルネックになりやすいデータベースへの読み取りをインメモリキャッシュで高速化します。Redis(データ構造・永続化・PubSub)・Memcached(シンプル・高速・マルチスレッド)・Dragonfly(Redis互換・Redisより25倍高速・最新)の3つがOSS分散キャッシュの主要選択肢です。
分散キャッシュを選ぶ理由
- レスポンス高速化: DBクエリ(10〜100ms)をメモリキャッシュ(0.1〜1ms)に置き換えて100倍高速化
- DB負荷削減: 同じデータへの繰り返しアクセスをキャッシュで吸収してDB CPUとコネクション数を削減
- スケーラビリティ: Webサーバー・APIサーバーを増やす前にキャッシュ層でスループットを倍増
- セッション管理: Webセッション(ログイン状態・カート)を複数サーバー間で共有
主要ツールの概要
Redis
2009年公開、C製のOSSです。GitHubスター67k+。単純なKVSを超えた豊富なデータ構造(String・Hash・List・Set・Sorted Set・Stream・JSON)と永続化・PubSub・Lua scriptingを持つ多機能なインメモリデータストアです。AWS ElastiCache・Google Cloud Memorystore・Azure Cache for Redisのバックエンドとしても広く使われています。
# docker-compose.yml - Redis + Redis Insight UI
version: "3.8"
services:
redis:
image: redis:7.4-alpine
restart: unless-stopped
ports:
- "6379:6379"
command: >
redis-server
--maxmemory 2gb
--maxmemory-policy allkeys-lru
--appendonly yes
--appendfsync everysec
--save 900 1
--save 300 10
--requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 5s
timeout: 3s
retries: 5
redis-insight:
image: redis/redisinsight:latest
restart: unless-stopped
ports:
- "5540:5540"
volumes:
redis_data:
# Python (redis-py): 実践的なキャッシングパターン
import redis
import json
import hashlib
import functools
import time
from typing import Optional, Callable, Any
r = redis.Redis(
host='localhost',
port=6379,
password='your-password',
decode_responses=True,
socket_connect_timeout=2,
socket_timeout=2,
retry_on_timeout=True,
)
# パターン1: シンプルなキャッシュデコレーター
def cache(ttl: int = 300, prefix: str = 'cache'):
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs):
# キャッシュキーを生成
key_data = f'{func.__name__}:{args}:{sorted(kwargs.items())}'
cache_key = f'{prefix}:{hashlib.md5(key_data.encode()).hexdigest()}'
# キャッシュヒット確認
cached = r.get(cache_key)
if cached is not None:
return json.loads(cached)
# キャッシュミス: 関数を実行してキャッシュに保存
result = func(*args, **kwargs)
r.setex(cache_key, ttl, json.dumps(result, default=str))
return result
return wrapper
return decorator
@cache(ttl=600, prefix='product')
def get_product(product_id: int) -> dict:
# DB クエリのシミュレーション(10ms)
time.sleep(0.01)
return {'id': product_id, 'name': f'商品{product_id}', 'price': product_id * 100}
# パターン2: キャッシュ無効化(特定プレフィックスのキーを全削除)
def invalidate_product_cache(product_id: int):
pattern = f'product:*'
keys = r.keys(pattern)
if keys:
r.delete(*keys)
print(f'商品キャッシュを削除: {len(keys)}件')
# パターン3: Redisハッシュでユーザーセッションを管理
def create_session(user_id: int, session_id: str, ttl: int = 3600):
r.hset(f'session:{session_id}', mapping={
'user_id': str(user_id),
'created_at': str(time.time()),
'last_active': str(time.time()),
})
r.expire(f'session:{session_id}', ttl)
def get_session(session_id: str) -> Optional[dict]:
session = r.hgetall(f'session:{session_id}')
if not session:
return None
r.hset(f'session:{session_id}', 'last_active', str(time.time()))
r.expire(f'session:{session_id}', 3600)
return session
# パターン4: Sorted SetでランキングをO(log N)で管理
def update_ranking(user_id: int, score: float):
r.zadd('leaderboard', {str(user_id): score})
def get_top_users(count: int = 10) -> list:
return r.zrevrange('leaderboard', 0, count - 1, withscores=True)
# パターン5: Redisパイプラインでバッチ操作(RTT削減)
def bulk_cache_set(items: dict, ttl: int = 300):
pipe = r.pipeline()
for key, value in items.items():
pipe.setex(f'cache:{key}', ttl, json.dumps(value))
pipe.execute()
print(f'{len(items)}件をバッチキャッシュ')
Memcached
2003年公開、C製のOSSです。GitHubスター3k+。マルチスレッドでシンプルなKVSキャッシュに特化しており、Redisより少ないメモリで大量のキャッシュを保持できます。永続化・PubSub・データ構造は持ちませんが、単純なキャッシュだけなら最も高いメモリ効率を発揮します。
# docker-compose.yml - Memcached
version: "3.8"
services:
memcached:
image: memcached:1.6-alpine
restart: unless-stopped
ports:
- "11211:11211"
command: memcached -m 2048 -c 4096 -t 8
# -m: 最大メモリ2GB
# -c: 最大コネクション数4096
# -t: ワーカースレッド数8
# Python (pymemcache): Memcachedキャッシング
from pymemcache.client.base import PooledClient
from pymemcache.client.retrying import RetryingClient
import json
client = RetryingClient(
PooledClient(('localhost', 11211), max_pool_size=20),
attempts=3,
retry_delay=0.1,
)
def cache_page(key: str, html: str, ttl: int = 300):
client.set(key.encode(), html.encode(), expire=ttl)
def get_cached_page(key: str) -> Optional[str]:
result = client.get(key.encode())
return result.decode() if result else None
Dragonfly
2022年公開、C++製のOSSです。GitHubスター26k+。Redisと完全互換のAPIでRedisの25倍のスループット・80%少ないメモリ使用量を実現した次世代のインメモリデータベースです。マルチスレッド設計(Redisはシングルスレッド)により、CPUコアを最大限活用できます。
# docker-compose.yml - Dragonfly(Redis互換・drop-in replacement)
version: "3.8"
services:
dragonfly:
image: docker.dragonflydb.io/dragonflydb/dragonfly:latest
restart: unless-stopped
ports:
- "6379:6379"
ulimits:
memlock: -1 # メモリロック制限を解除(パフォーマンス最適化)
volumes:
- dragonfly_data:/data
command: >
--requirepass ${REDIS_PASSWORD}
--maxmemory 4gb
--snapshot_cron "*/30 * * * *"
--dbfilename dump.rdb
volumes:
dragonfly_data:
# Dragonfly は redis-py がそのまま動く(API完全互換)
import redis
# Dragonfly に接続(Redisと全く同じ接続方法)
r = redis.Redis(host='localhost', port=6379, password='your-password')
r.set('key', 'value')
print(r.get('key')) # Dragonflyで実行されている
# パフォーマンス比較(ベンチマーク)
# redis-benchmark -h localhost -p 6379 -c 200 -n 1000000 -t set,get
# Dragonfly: ~3,000,000 ops/sec (マルチコアCPUを全コア活用)
# Redis: ~100,000 ops/sec (シングルスレッド)
機能比較表
| 比較項目 | Redis | Memcached | Dragonfly |
|---|---|---|---|
| データ構造 | 豊富 | KVSのみ | Redis互換 |
| 永続化 | ✅ | ❌ | ✅ |
| マルチスレッド | ❌ | ✅ | ✅ |
| メモリ効率 | 中 | 高 | 最高 |
| Redis互換 | ✅ | ❌ | ✅(完全) |
| GitHub Stars | 67k+ | 3k+ | 26k+ |
分散キャッシュはDevOpsカテゴリ/categories/devopsのNginxプロキシキャッシュ・CDN(Cloudflare)と組み合わせてマルチレイヤーキャッシュ戦略を構築します。LLM Toolsカテゴリ/categories/llm-toolsのClaude API・OpenAI APIのレスポンスをRedisにキャッシュ(TTL 1時間)してAPI費用を削減する実装パターンも一般的です。
FAQ
Q. RedisとDragonflyを本番環境で使い分けるには?
A. 既存のRedisエコシステム(Redis Sentinel・Redis Cluster・ElastiCache)を使っているならRedis、大量のメモリアクセスがあってCPUスケールしたいセルフホスト環境ならDragonflyが向いています。Dragonflyへの移行: ①docker-composeのimageをDragonflyに変更するだけ(redis-py・ioredis・StackExchange.Redisなどクライアントを変更不要)②Dragonflyは現時点でRedis Sentinel/Clusterのレプリケーションプロトコルに対応しているため既存クラスター設定をそのまま流用可能(要バージョン確認)③Dragonfly CloudはマネージドDragonfly(セルフホスト不要)を提供しています。
Q. Redisのmaxmemory-policyはどれを選べばいいですか?
A. **キャッシュ用途はallkeys-lru、永続ストア兼用はvolatile-lru**が推奨です。主要ポリシーの使い分け: ①allkeys-lru: 全キーの中で最も最近使われていないものを削除(純粋なキャッシュに最適)②volatile-lru: TTL設定済みキーの中で最も使われていないものを削除(永続データとキャッシュが同居する場合)③allkeys-lfu: 最も使用頻度が低いキーを削除(アクセスパターンに偏りがある場合にLRUより効率的)④noeviction: メモリ上限到達時にエラーを返す(Redisをキューや永続ストアとして使う場合)。maxmemoryの設定: 物理メモリの60〜70%を設定してOSのスワップを防止します。
Q. PythonのDjangoでRedisをセッションバックエンドにするには?
A. ①pip install django-redis②settings.pyに設定: CACHES = {'default': {'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': 'redis://:password@localhost:6379/1', 'OPTIONS': {'CLIENT_CLASS': 'django_redis.client.DefaultClient'}}}③セッションバックエンドをキャッシュに変更: SESSION_ENGINE = 'django.contrib.sessions.backends.cache'・SESSION_CACHE_ALIAS = 'default'④cache.set・cache.get・@cache_pageデコレーターでビューをキャッシュ。Celeryのブローカーも同じRedisを使える: CELERY_BROKER_URL = 'redis://:password@localhost:6379/0'(DBインデックスを分けてキャッシュとCelery Brokerを分離するのが推奨)。
Q. RedisのPubSubはいつ使えばいいですか?
A. リアルタイム通知・チャット・ライブダッシュボードに使えますが、メッセージの永続化が不要な場合のみ適切です。RedisのPubSub: ①Subscriberがオフラインの間のメッセージは失われる(永続化なし)②PUBLISH channel message→SUBSCRIBE channelでリアルタイム配信③Webソケット(Socket.io・FastAPI WebSocket)との組み合わせでサーバー間のメッセージ中継に使用。永続化が必要な場合はRedis Streams(XADD・XREAD・XREADGROUP)を使います。実際の使い分け: ①チャットメッセージの永続化→Redis Streams②リアルタイムの閲覧者数カウントや「〇〇さんが入力中」のような揮発性通知→PubSub。
まとめ
| ユースケース | 推奨ツール |
|---|---|
| データ構造・永続化・PubSub・セッション | Redis |
| シンプルKVSのみ・高メモリ効率 | Memcached |
| Redis互換・高スループット・マルチコア最大活用 | Dragonfly |