Redisのユースケース:キャッシュ、キュー、レート制限

Backend2026-09-15TryQuickToolBox

開発環境では問題なく動作するWebアプリケーションを構築したものの、トラフィックが増えるにつれて応答時間が遅くなり、データベースが過負荷になることに気づくでしょう。原因はしばしば、繰り返される高コストな操作にあります。つまり、同じデータをデータベースから何度も取得したり、タスクを同期的に処理したり、悪意のあるリクエストレートを許可したりすることです。インメモリデータストアであるRedisは、これらの問題に対するエレガントな解決策を提供します。この記事では、Redisの3つの実用的なユースケース(キャッシュ、キュー、レート制限)を探ります。コード例を通じて各パターンの実装方法を学び、いつ適用すべきかを理解できるでしょう。

なぜRedisなのか?

Redisは、その速度と汎用性で知られるオープンソースのインメモリキーバリューストアです。文字列、リスト、セット、ハッシュなどのデータ構造をサポートしており、単純なキャッシュ以外のさまざまなタスクに適しています。データをメモリに保持するため、Redisはサブミリ秒のレイテンシを実現し、高性能なシナリオに最適です。また、永続化オプションも提供しているため、再起動時にデータが失われることはありません。それでは、3つのユースケースを詳しく見ていきましょう。

1. Redisによるキャッシュ

キャッシュは最も一般的なRedisのユースケースです。アイデアはシンプルです。高コストな操作(データベースクエリやAPI呼び出しなど)の結果をRedisに保存し、後続のリクエストに対して直接提供します。これにより、プライマリデータベースの負荷が軽減され、応答時間が短縮されます。

キャッシュの実装方法

  1. キャッシュを確認する: データベースにアクセスする前に、一意のキー(例:user:123)を使用してRedisにデータを問い合わせます。
  2. 見つかった場合(キャッシュヒット): キャッシュされたデータをすぐに返します。
  3. 見つからなかった場合(キャッシュミス): データベースからデータを取得し、有効期限(TTL)を設定してRedisに保存し、返します。

以下は、redis-pyを使用したPythonの例です:

import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def get_user(user_id):
    cache_key = f'user:{user_id}'
    cached = r.get(cache_key)
    if cached:
        return json.loads(cached)
    # Simulate database fetch
    user = fetch_user_from_db(user_id)
    r.setex(cache_key, 3600, json.dumps(user))  # Cache for 1 hour
    return user

ベストプラクティス: 意味のあるキーを選択し、古いデータを避けるために適切なTTLを設定し、キャッシュ無効化戦略を検討してください。読み取りが多いワークロードでは、キャッシュによってデータベースの負荷を桁違いに削減できます。

2. Redisによるキュー

キューは、時間のかかるタスクをリクエスト-レスポンスサイクルから分離します。たとえば、メールの送信、画像の処理、レポートの生成などは非同期で行うことができます。Redisのリストやストリームは、シンプルなキューの実装に最適です。

基本的なキューの実装

LPUSHを使用してリストの左側にジョブを追加し、BRPOPを使用して右側からブロックしてポップします。これによりFIFOキューが作成されます。

# Producer: add job
r.lpush('email_queue', json.dumps({'to': 'user@example.com', 'subject': 'Welcome'}))

# Consumer: process jobs
while True:
    _, job = r.brpop('email_queue', timeout=30)
    if job:
        process_email(json.loads(job))

より高度なニーズには、Redis Streamsがコンシューマグループ、確認応答、再生可能性を提供し、堅牢なメッセージ処理に適しています。

3. Redisによるレート制限

レート制限は、APIを悪用から保護し、公平な使用を保証します。Redisのアトミック操作により、自動的に期限切れになるカウンターを簡単に実装できます。

固定ウィンドウレート制限

固定ウィンドウアプローチでは、時間ウィンドウごとにNリクエストを許可します(例:IPごとに1時間あたり100リクエスト)。INCRとEXPIREを使用します:

def is_allowed(ip, limit=100, window=3600):
    key = f'rate:{ip}'
    current = r.incr(key)
    if current == 1:
        r.expire(key, window)
    return current