Redisのインストールと基本的な使い方 — 深夜2時の本番障害から習熟まで

Database tutorial - IT technology blog
Database tutorial - IT technology blog

深夜2時、Djangoサーバーが亀のように遅くなった — 足りなかったのはRedisだった

当時、モバイルアプリ向けに商品一覧を返すDjango APIを動かしていた。トラフィックが少ないときは問題なかった。でもセール期間になると、サーバーがタイムアウトし始めた。確認してみると、MySQLが約400クエリ/秒を処理していて、その大半はフィルターパラメーターが少し違うだけの全く同じSELECT文だった。

原因はすぐわかった:結果が5分間変わらないのに、毎回リクエストがデータベースに直接アクセスしていた。これがキャッシュレイヤーの欠如というやつだ。

シンプルなクエリなのになぜデータベースが過負荷になるのか?

クライアントが/products?category=shoesというAPIを呼ぶたびに、DjangoはフルSQLクエリを実行し、MySQLはパース → インデックス検索 → ディスク読み取り(またはバッファープール) → レスポンスという処理を行う。400クエリ/秒でその80%が重複している場合、MySQLのCPUはほぼ同じ処理の繰り返しに費やされてしまう。

最もシンプルな解決策:中間にキャッシュレイヤーを追加することだ。初回は実際にクエリを実行して結果をキャッシュに保存する。次回以降はキャッシュから返すため、データベースには一切アクセスしない。これがまさにRedisが最も得意とすることだ。

LinuxへのRedisインストール — 手早くきれいに

Ubuntu / Debian

# Redisの公式リポジトリからインストール(最新版、Ubuntuの古いパッケージではない)
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list

sudo apt update
sudo apt install redis -y

# 状態を確認
sudo systemctl status redis
sudo systemctl enable redis

CentOS / RHEL / Rocky Linux

sudo dnf install epel-release -y
sudo dnf install redis -y
sudo systemctl start redis
sudo systemctl enable redis

Redisの動作確認

redis-cli ping
# 結果:PONG

PONGが表示されれば完了だ。表示されない場合はsystemctl status redisを確認しよう — 99%の確率でサービスが起動していないか、ポート6379がファイアウォールでブロックされている。

実務でよく使うRedisコマンド

SETとGET — 最もシンプル

redis-cli

# 値を保存
SET username "hoanganh"

# 値を取得
GET username
# => "hoanganh"

# TTL付きで保存(300秒後に自動削除)
SET session_token "abc123" EX 300

# 残り秒数を確認
TTL session_token

Hash — 複数フィールドを持つオブジェクトの保存

# ユーザー情報を保存
HSET user:1001 name "田中 太郎" email "[email protected]" age 28

# 1つのフィールドを取得
HGET user:1001 name

# 全フィールドを取得
HGETALL user:1001

List — シンプルなキュー

# 先頭に追加
LPUSH job_queue "send_email"
LPUSH job_queue "resize_image"

# 末尾から取り出す(FIFO)
RPOP job_queue
# => "send_email"

キーの削除と確認

# キーが存在するか確認
EXISTS username
# => 1(存在する)または 0(存在しない)

# キーを削除
DEL username

# 全キーを表示(本番環境では使用禁止 — 危険)
KEYS *

# 本番環境ではSCANを代わりに使う
SCAN 0 MATCH user:* COUNT 100

PythonでRedisキャッシュを使う — 実践例

最初のDjango APIの問題に戻ろう。あの夜に実際に行った修正方法はこうだ:

import redis
import json
import hashlib

# Redisに接続
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

def get_products(category: str, filters: dict) -> list:
    # クエリパラメーターからキャッシュキーを生成
    cache_key = f"products:{category}:{hashlib.md5(json.dumps(filters, sort_keys=True).encode()).hexdigest()}"

    # キャッシュから取得を試みる
    cached = r.get(cache_key)
    if cached:
        return json.loads(cached)

    # キャッシュミス → データベースをクエリ
    results = db.query("SELECT * FROM products WHERE category = %s ...", category)

    # キャッシュに保存、TTL 5分
    r.setex(cache_key, 300, json.dumps(results))

    return results

その夜のうちにデプロイ完了。MySQLクエリは400/秒から約40/秒に減少。レスポンスタイムは800msから20msへ改善。たった30行のキャッシュコードで、サーバーのタイムアウトが解消された。

本番環境向けRedis最小設定

デフォルトの設定ファイルは/etc/redis/redis.confにある。すぐに変更すべき項目は以下だ:

# Redisが使用するRAMの上限
maxmemory 512mb

# RAMが満杯になった時:期限切れに近いキーから削除(キャッシュ用途に適切)
maxmemory-policy allkeys-lru

# localhostのみにバインド、不要なら外部に公開しない
bind 127.0.0.1

# パスワードを設定(外部ポートが開いている場合は必須)
requirepass your_strong_password_here

# ディスクへのスナップショット保存(RDBパーシステンス)
save 900 1
save 300 10
save 60 10000

設定変更後:

sudo systemctl restart redis

# 認証テスト
redis-cli -a your_strong_password_here ping

Redisを適切な用途に使う — 向いていない場所に無理やり使わない

Redisは強力だが、すべての問題を解決できるわけではない。あるチームがRedisを注文のプライマリデータベースとして使っているのを見たことがある。パーシステンスを有効にしていなかったため、サーバーを再起動したら3日分のトランザクションデータが全部消えた。高い授業料だった:本番データに触れる前に、各ツールの役割を正しく理解しておくべきだ。

Redisが最も適しているのは:

  • APIレスポンスのキャッシュ — データベースの負荷を軽減し、読み取り速度を向上
  • セッションストレージ — ユーザーセッション、認証トークンの保存
  • レートリミット — IPごとのリクエスト数カウント、スパム対策
  • ジョブキュー — CeleryやRQとの組み合わせ
  • Pub/Subメッセージング — シンプルなリアルタイム通知

Redisに向いていないのは:

  • 絶対的な永続性が必要なデータ(注文、金融取引)
  • 複雑なリレーショナルデータ(複数テーブルのjoin)
  • 大きなファイルやバイナリblob

Redisの簡易モニタリング

# リアルタイム統計を確認
redis-cli info stats

# キャッシュのヒット率
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses'

# リアルタイムで実行中のコマンドを確認(topコマンドのように、ただしRedis用)
redis-cli monitor

keyspace_hitskeyspace_missesを大幅に上回っていれば、キャッシュは正常に機能している。逆の場合はTTLとキャッシュキーのロジックを見直そう。

Redisは難しくない。初めてインストールしてもすぐに使い始められた。問題はインストールではなく、いつ使うべきかを判断し、予期せぬ障害が起きないよう正しく設定することだ。次回、深夜にサーバーがもたつき始めたら、まずキャッシュレイヤーを確認してみよう — 高確率でそこが原因のはずだ。

Share: