提示:本网站现在为维护调试状态

Redis キャッシュ設計パターン

Choyeon
Choyeon
2026年8月28日 1 分で読了 318 閲覧
347 字 2,158 文字 更新日 2026年11月8日
Redis キャッシュ設計パターン
目次

Redis Cache Design Patterns

Caching is one of the most effective performance boosters, but wrong patterns without failure handling introduce inconsistency and instability.

Cache-Aside Pattern

On read, check cache first; on miss, query DB and backfill. On write, update DB then delete cache (delete preferred over update to avoid concurrent dirty reads). Simple but must handle stampede, penetration, avalanche.

import redis, json, hashlib, random
from functools import wraps
from typing import Callable, Any

r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)

def cache_aside(ttl: int = 300, jitter: float = 0.1):
    def decorator(fn: Callable):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            k = f"c:{fn.__name__}:{hashlib.md5(str((args,sorted(kwargs.items()))).encode()).hexdigest()[:10]}"
            cached = r.get(k)
            if cached == "__NULL__": return None
            if cached is not None: return json.loads(cached)
            result = fn(*args, **kwargs)
            t = int(ttl * (1 + random.uniform(-jitter, jitter)))
            if result is None: r.setex(k, max(30, t//5), "__NULL__")
            else: r.setex(k, max(1, t), json.dumps(result, default=str))
            return result
        return wrapper
    return decorator

def write_through(key: str, value: Any, db_update: Callable, ttl: int = 300):
    pipe = r.pipeline()
    pipe.setex(key, ttl, json.dumps(value, default=str))
    try:
        db_update(value)
        pipe.execute()
    except Exception:
        pipe.reset(); raise

bg_queue: list[tuple[str, Any]] = []
def write_behind(key: str, value: Any):
    bg_queue.append((key, value))
    r.setex(key, 60, json.dumps(value, default=str))

def flush_bg(db_update: Callable):
    while bg_queue:
        k, v = bg_queue.pop(0)
        try: db_update(k, v)
        except Exception: bg_queue.insert(0, (k, v)); break

@cache_aside(ttl=600)
def get_product(pid: int):
    return {"id": pid, "name": f"Product {pid}", "price": 99.99}

Write-Through vs Write-Behind

Write-Through updates cache and DB synchronously with strong consistency but higher latency. Write-Behind writes cache first then flushes asynchronously in batches for maximum throughput but risks short data-loss windows.

Pattern Consistency Read Perf Write Perf Best For
Cache-Aside Eventual High Medium Read-heavy
Write-Through Strong High Low latency Strict consistency
Write-Behind Weak/Eventual High Very High Logging/stats write-heavy
Refresh-Ahead Eventual Very High Medium Predictable hot keys

Best Practices

Add +-10% random jitter to TTL against avalanches. Use mutex/logical expiration for hot keys against stampedes. Cache null values for non-existent keys against penetration.

X微博Telegram

筆者について

投票

你最希望 Rosetta 优先加入哪项功能?

社区投票(演示数据,可后台删除)

コメント (5)

0 / 3000
云端漫步
云端漫步cloud-notes.cloud2026年9月20日

补充一点:实际使用中如果遇到 MySQL 的 8 小时超时问题,可以在连接串里加 autoReconnect=true 参数,虽然官方不推荐但挺好用的。

机器学习萌新
机器学习萌新2026年9月20日

受益匪浅,感谢大佬分享!

游戏策划阿哲
游戏策划阿哲2026年9月20日

有个小问题:你文中用的是 @Async 注解,这个默认用的是 SimpleAsyncTaskExecutor,生产环境是不是最好手动配一个线程池?

奶茶味程序媛
奶茶味程序媛2026年9月20日

好文!但是我觉得第三部分那个消息队列选型对比表有点偏向 Kafka 了,RocketMQ 在事务消息这块其实优势挺明显的。

独立开发者阿明
独立开发者阿明aming.dev2026年9月20日

太及时了,正好项目里要上 Redis 集群,照着来一遍省了好多事,谢谢!

関連記事

Go 言語並行:goroutine + channel + sync.WaitGroup

Go 言語並行:goroutine + channel + sync.WaitGroup

Goのネイティブ並行完全ガイド:軽量goroutine、CSPモデルのchannel、sync.WaitGroup、Contextキャンセル、ワーカープール、goroutineリーク対策。

1 分で読了
Node.js 性能診断:clinic.js + フレームグラフ

Node.js 性能診断:clinic.js + フレームグラフ

Node.js性能調査:clinic.jsレポート生成、フレームグラフ読解でホット関数、イベントループブロッカー、メモリリークを特定。

1 分で読了
Python 並行処理:asyncio vs ThreadPool vs ProcessPool

Python 並行処理:asyncio vs ThreadPool vs ProcessPool

Pythonの3大並行モデル徹底比較:GIL下のThreadPool、GIL回避のProcessPool、超高IO向けasyncio。性能と複雑性の4次元デシジョンツリー。

1 分で読了
CQRS + Event Sourcing アーキテクチャ解説

CQRS + Event Sourcing アーキテクチャ解説

高度な分散パターン:CQRS読み書き分離でクエリ性能、Event Sourcingはイベントを唯一の源として監査+時間遡行。一貫性・スナップショット・べき等とアンチパターンを解説。

1 分で読了
Rust 所有権と借用:ライフタイム完全理解

Rust 所有権と借用:ライフタイム完全理解

Rustの最難解概念をマスター:所有権ルール、可変/不変借用の制約、ライフタイム注釈。コンパイルエラー例と修正を通してBorrow Checkerの思考法を習得。

1 分で読了
テストピラミッド:単体/結合/E2E 比率と実践

テストピラミッド:単体/結合/E2E 比率と実践

テストピラミッド体系解説:下層 単体テスト(多数・高速・Mock分離)、中層 結合テスト(実DB/メッセージ協調)、上層 E2E(少数・重要ユーザーフロー)。推奨比率 70/20/10、カバレッジ指標と実践ガイド。

1 分で読了