Communitygithub.com

Redisパターン

Redisのデータ構造パターン、キャッシュ戦略、分散ロック、レート制限、Pub/Sub、本番アプリケーション向け接続管理を提供します。アプリケーションにキャッシュ、分散ロック、レート制限、Pub/Subを追加する際や、キー設計のレビューが必要な場合に使用します。

Redisパターン とは?

このスキルは、Redisを利用した一般的なバックエンドユースケースにおけるベストプラクティスを包括的に提供します。キャッシュ(Cache-Aside、Write-Through)、セッションストレージ、分散ロック、レート制限(Fixed Window、Sliding Window)、Pub/Sub、Redis Streamsなど、主要なパターンの実装例をPythonコード付きで解説します。さらに、キーの命名規則、TTL戦略、接続プール管理、クラスターモードやSentinelを用いた高可用性構成、evictionポリシー、アンチパターンとその対策についてもカバーしています。開発者はこのスキルを参照することで、Redisのアトミック性やパフォーマンス特性を活かした、堅牢でスケーラブルなシステムを設計・実装できます。

対応~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/redis-patterns

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Redisパターン は何をしますか?

一般的なバックエンドユースケースにおけるRedisのベストプラクティスのクイックリファレンスです。

仕組み

Redisはインメモリデータ構造ストアであり、文字列、ハッシュ、リスト、セット、ソート済みセット、ストリームなどをサポートします。個々のRedisコマンドは単一インスタンス上でアトミックですが、複数ステップのワークフローではアトミック性を維持するためにLuaスクリプト、MULTI/EXECトランザクション、または明示的な同期が必要です。データはオプションでRDBスナップショットまたはAOFログを介して永続化されます。クライアントはTCP経由でRESPプロトコルを使用して通信します。リクエストごとのハンドシェイクオーバーヘッドを避けるために、接続プールは必須です。

いつアクティブにするか

  • アプリケーションにキャッシュを追加する場合
  • レート制限またはスロットリングを実装する場合
  • 分散ロックまたは調整機能を構築する場合
  • セッションまたはトークンストレージをセットアップする場合
  • メッセージングのためにPub/SubまたはRedis Streamsを使用する場合
  • Redisを本番環境で設定する場合(プーリング、エビクション、クラスタリング)

データ構造チートシート

ユースケース構造キーの例
シンプルなキャッシュStringproduct:123
ユーザーセッションHashsession:abc
リーダーボードSorted Setscores:weekly
ユニークビジターSetvisitors:2024-01-01
アクティビティフィードListfeed:user:456
イベントストリームStreamevents:orders
カウンター/レート制限String (INCR)ratelimit:user:123
Bloomフィルター/HLLHyperLogLoghll:pageviews

コアパターン

Cache-Aside(遅延ロード)

import redis
import json

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

def get_product(product_id: int):
    cache_key = f"product:{product_id}"
    cached = r.get(cache_key)

    if cached:
        return json.loads(cached)

    product = db.query("SELECT * FROM products WHERE id = %s", product_id)
    r.setex(cache_key, 3600, json.dumps(product))  # TTL: 1時間
    return product

Write-Through Cache

def update_product(product_id: int, data: dict):
    # 最初にDBに書き込む
    db.execute("UPDATE products SET ... WHERE id = %s", product_id)

    # すぐにキャッシュを更新
    cache_key = f"product:{product_id}"
    r.setex(cache_key, 3600, json.dumps(data))

キャッシュ無効化

# タグベースの無効化 — 関連するキーをセットでグループ化
def cache_product(product_id: int, category_id: int, data: dict):
    key = f"product:{product_id}"
    tag = f"tag:category:{category_id}"
    pipe = r.pipeline(transaction=True)
    pipe.setex(key, 3600, json.dumps(data))
    pipe.sadd(tag, key)
    pipe.expire(tag, 3600)
    pipe.execute()

def invalidate_category(category_id: int):
    tag = f"tag:category:{category_id}"
    keys = r.smembers(tag)
    if keys:
        r.delete(*keys)
    r.delete(tag)

セッションストレージ

import time
import uuid

def create_session(user_id: int, ttl: int = 86400) -> str:
    session_id = str(uuid.uuid4())
    key = f"session:{session_id}"
    pipe = r.pipeline(transaction=True)
    pipe.hset(key, mapping={
        "user_id": user_id,
        "created_at": int(time.time()),
    })
    pipe.expire(key, ttl)
    pipe.execute()
    return session_id

def get_session(session_id: str) -> dict | None:
    data = r.hgetall(f"session:{session_id}")
    return data if data else None

def delete_session(session_id: str):
    r.delete(f"session:{session_id}")

レート制限

Fixed Window(シンプル)

def is_rate_limited(user_id: int, limit: int = 100, window: int = 60) -> bool:
    key = f"ratelimit:{user_id}:{int(time.time()) // window}"
    pipe = r.pipeline(transaction=True)
    pipe.incr(key)
    pipe.expire(key, window)
    count, _ = pipe.execute()
    return count > limit

Sliding Window(Lua — アトミック)

-- sliding_window.lua
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])

redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local count = redis.call('ZCARD', key)

if count < limit then
    -- 一意のメンバーを使用 (now + sequence) して、同じミリ秒内の衝突を回避
    local seq_key = key .. ':seq'
    local seq = redis.call('INCR', seq_key)
    redis.call('EXPIRE', seq_key, math.ceil(window / 1000))
    redis.call('ZADD', key, now, now .. '-' .. seq)
    redis.call('EXPIRE', key, math.ceil(window / 1000))
    return 1
end
return 0
sliding_window = r.register_script(open('sliding_window.lua').read())

def allow_request(user_id: int) -> bool:
    key = f"ratelimit:sliding:{user_id}"
    now = int(time.time() * 1000)
    return bool(sliding_window(keys=[key], args=[now, 60000, 100]))

分散ロック

分散ロック(単一ノード — SET NX PX)

import uuid

def acquire_lock(resource: str, ttl_ms: int = 5000) -> str | None:
    lock_key = f"lock:{resource}"
    token = str(uuid.uuid4())
    acquired = r.set(lock_key, token, px=ttl_ms, nx=True)
    return token if acquired else None

def release_lock(resource: str, token: str) -> bool:
    release_script = """
    if redis.call('get', KEYS[1]) == ARGV[1] then
        return redis.call('del', KEYS[1])
    else
        return 0
    end
    """
    result = r.eval(release_script, 1, f"lock:{resource}", token)
    return bool(result)

# 使用例
token = acquire_lock("order:payment:123")
if token:
    try:
        process_payment()
    finally:
        release_lock("order:payment:123", token)

マルチノードセットアップの場合は、Redlockアルゴリズム全体を実装した redlock-py ライブラリを使用してください。

Pub/Sub & Streams

Pub/Sub(Fire-and-Forget)

# パブリッシャー
def publish_event(channel: str, payload: dict):
    r.publish(channel, json.dumps(payload))

# サブスクライバー(ブロッキング — 別スレッド/プロセスで実行)
def subscribe_events(channel: str):
    pubsub = r.pubsub()
    pubsub.subscribe(channel)
    for message in pubsub.listen():
        if message['type'] == 'message':
            handle(json.loads(message['data']))

Redis Streams(永続キュー)

# プロデューサー
def emit(stream: str, event: dict):
    r.xadd(stream, event, maxlen=10000)  # ストリーム長を制限

# コンシューマグループ — 少なくとも1回の配信を保証
try:
    r.xgroup_create('events:orders', 'processor', id='0', mkstream=True)
except Exception:
    pass  # グループはすでに存在します

def consume(stream: str, group: str, consumer: str):
    while True:
        messages = r.xreadgroup(group, consumer, {stream: '>'}, count=10, block=2000)
        for _, entries in (messages or []):
            for msg_id, data in entries:
                process(data)
                r.xack(stream, group, msg_id)

配信保証、コンシューマグループ、リプレイが必要な場合は、Pub/SubよりもStreamsを優先してください。

キー設計

命名規則

# パターン: resource:id:field
user:123:profile
order:456:status
cache:product:789

# パターン: namespace:resource:id
myapp:session:abc123
myapp:ratelimit:user:123

# パターン: resource:date(時間バインドキー)
stats:pageviews:2024-01-01

TTL戦略

データ型推奨TTL
ユーザーセッション24時間 (86400)
APIレスポンスキャッシュ5~15分
レート制限ウィンドウウィンドウサイズに合わせる
短命トークン5~10分
リーダーボード1時間~24時間
静的/参照データ1時間~1週間

常にTTLを設定してください。TTLのないキーは無制限に蓄積され、メモリプレッシャーを引き起こします。

接続管理

接続プール

from redis import ConnectionPool, Redis

pool = ConnectionPool(
    host='localhost',
    port=6379,
    db=0,
    max_connections=20,
    decode_responses=True,
    socket_connect_timeout=2,
    socket_timeout=2,
)

r = Redis(connection_pool=pool)

クラスターモード

from redis.cluster import RedisCluster

r = RedisCluster(
    startup_nodes=[{"host": "redis-1", "port": 6379}],
    decode_responses=True,
    skip_full_coverage_check=True,
)

Sentinel(高可用性)

from redis.sentinel import Sentinel

sentinel = Sentinel(
    [('sentinel-1', 26379), ('sentinel-2', 26379)],
    socket_timeout=0.5,
)
master = sentinel.master_for('mymaster', decode_responses=True)
replica = sentinel.slave_for('mymaster', decode_responses=True)

エビクションポリシー

ポリシー動作最適な用途
noevictionフル時に書き込みエラーキュー/重要なデータ
allkeys-lru最も最近使用されていないものをエビクション一般的なキャッシュ
volatile-lruTTLのあるキーのみLRU混合データストア
allkeys-lfu最も頻繁に使用されていないものをエビクション偏ったアクセスパターン
volatile-ttl最も早く期限切れになるものをエビクション長命データを優先

redis.conf で設定: maxmemory-policy allkeys-lru

アンチパターン

アンチパターン問題修正
TTLのないキーメモリが無制限に増加常にTTLを設定
本番環境での KEYS *サーバーをブロック(O(N))SCAN カーソルを使用
大きなブロブの保存(100KB以上)シリアライズが遅く、メモリプレッシャー参照を保存し、オブジェクトストアから取得
すべてに単一のRedisキャッシュとキューの分離がない別のDBまたはインスタンスを使用
接続プール制限を無視負荷時の接続枯渇ワークロードに合わせてプールをサイジング
キャッシュミススタンピードを処理しないコールドスタート時の雪崩ロックまたは確率的早期期限切れを使用
考えなしの FLUSHALLインスタンス全体をワイプキーパターンで削除範囲を制限

キャッシュミススタンピードの防止

import threading

_locks: dict[str, threading.Lock] = {}
_locks_mutex = threading.Lock()

def get_with_lock(key: str, fetch_fn, ttl: int = 300):
    cached = r.get(key)
    if cached:
        return json.loads(cached)

    with _locks_mutex:
        if key not in _locks:
            _locks[key] = threading.Lock()
        lock = _locks[key]
    with lock:
        cached = r.get(key)  # ロック取得後に再確認
        if cached:
            return json.loads(cached)
        value = fetch_fn()
        r.setex(key, ttl, json.dumps(value))
        return value

注: マルチプロセスデプロイメントの場合は、インプロセスロックを上記「分散ロック」セクションの acquire_lock/release_lock に置き換えてください。

例

Django/Flask APIエンドポイントにキャッシュを追加する: レスポンスに対して setex と5分のTTLを使用したCache-Asideパターンを使用します。リクエストパラメータをキーにします。

ユーザーごとにAPIをレート制限する: 低トラフィックのエンドポイントには pipeline(transaction=True) を使用したFixed-Windowパターンを、正確なユーザーごとのスロットリングが必要な場合はSliding-Window Luaパターンを使用します。

ワーカー間でバックグラウンドジョブを調整する: 期待されるジョブの実行時間を超えるTTLで acquire_lock を使用します。必ず finally ブロックで解放します。

複数のサブスクライバーに通知をファンアウトする: Fire-and-ForgetにはPub/Subを使用します。配信保証や遅延コンシューマーのためのリプレイが必要な場合はStreamsに切り替えます。

クイックリファレンス

パターンいつ使うか
Cache-aside読み取り負荷が高く、多少の古さを許容する場合
Write-through強い整合性が必要な場合
分散ロックリソースへの同時アクセスを防ぐ場合
Sliding window レート制限正確なユーザーごとのスロットリングが必要な場合
Redis Streamsコンシューマグループを使用した永続イベントキューが必要な場合
Pub/Sub配信保証が不要なブロードキャスト
Sorted Set リーダーボードランク付けされたスコアリング、ページネーション
HyperLogLog低メモリでおおよそのユニークカウントが必要な場合

関連

  • スキル: postgres-patterns — リレーショナルデータパターン
  • スキル: backend-patterns — APIおよびサービス層パターン
  • スキル: database-migrations — スキーマバージョニング
  • スキル: django-patterns — Djangoキャッシュフレームワーク統合
  • エージェント: database-reviewer — データベースレビューの完全ワークフロー

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

関連スキル