Redisの活用事例:キャッシュ、キュー、レート制限

Backend2026-10-06TryQuickToolBox

数人のユーザーなら問題なく動作するWebアプリを構築したものの、トラフィックが増えるにつれて、ページの読み込みが遅くなったり、バックグラウンドジョブが重複したり、APIが悪意のあるクライアントから攻撃されたりすることに気づくでしょう。これらはRedisがエレガントに解決できる典型的なスケーリングの問題です。Redisはインメモリデータストアであり、キャッシュ、キュー、レート制限という3つの中核タスクに優れています。この記事では、各ユースケースを実践的な例とベストプラクティスとともに探っていきます。

なぜこれらのユースケースにRedisなのか?

Redisはデータをメモリに保存するため、信じられないほど高速で、多くの場合サブミリ秒の応答時間を実現します。文字列、リスト、セット、ソート済みセット、ハッシュなどの豊富なデータ構造をサポートしており、これらはキャッシュ、キュー、レート制限に自然にマッピングされます。また、アトミック操作、Pub/Sub、永続化オプションも提供しており、バックエンド開発者にとって多用途なツールとなっています。

1. Redisによるキャッシュ

キャッシュは最も一般的なRedisのユースケースです。頻繁にアクセスされるデータをRedisに保存することで、データベースの負荷を減らし、応答を高速化できます。

キャッシュの仕組み

リクエストが来たら、データがRedisに存在するか確認します。存在すれば(キャッシュヒット)、それを直接返します。存在しなければ(キャッシュミス)、データベースから取得し、有効期限付きでRedisに保存してから返します。このパターンはキャッシュアサイドと呼ばれます。

// Node.js example using ioredis
const Redis = require('ioredis');
const redis = new Redis();

async function getUser(userId) {
  const cacheKey = `user:${userId}`;
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
  await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600); // 1 hour TTL
  return user;
}

キャッシュのベストプラクティス

キャッシュ無効化戦略

無効化は難しい問題です。一般的な戦略には次のものがあります:

2. Redisによるキュー

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

シンプルなキューの実装

Redisのリストはキューに最適です。LPUSHで左側にジョブを追加し、BRPOPで右側からブロックしてポップします(FIFO)。

// Producer: add job
await redis.lpush('email_queue', JSON.stringify({ to: 'user@example.com', subject: 'Welcome' }));

// Consumer: process job (in a worker)
while (true) {
  const job = await redis.brpop('email_queue', 0); // 0 = block indefinitely
  const { to, subject } = JSON.parse(job[1]);
  await sendEmail(to, subject);
}

BRPOPLPUSHによる信頼性の高いキュー

ワーカーがクラッシュした場合にジョブを失わないように、BRPOPLPUSHを使用してジョブをアトミックに処理リストに移動します。処理が成功したら、処理リストから削除します。ワーカーが死んだ場合、別のワーカーが処理リストからジョブを回復できます。

const job = await redis.brpoplpush('email_queue', 'processing_queue', 0);
try {
  // process job
  await redis.lrem('processing_queue', 1, job);
} catch (err) {
  // handle error, maybe requeue
}

専用のキューライブラリ

本番環境では、Bull(Node.js)、RQ(Python)、Sidekiq(Ruby)などのライブラリを検討してください。これらはリトライ、スケジューリング、モニタリングをすぐに利用できる形で提供します。

3. Redisによるレート制限

レート制限はAPIを悪用から保護し、公平な使用を保証します。Redisのアトミック操作はリクエストのカウントに理想的です。

固定ウィンドウ方式のレート制限

時間ウィンドウごとにユーザーごとのカウンタをインクリメントします。カウントが制限を超えたら、リクエストを拒否します。

async function isAllowed(userId, limit = 100, windowSec = 60) {
  const key = `rate:${userId}:${Math.floor(Date.now() / 1000 / windowSec)}`;
  const count = await redis.incr(key);
  if (count === 1) await redis.expire(key, windowSec);
  return count