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

Redis Cache Design Patterns

Choyeon
Choyeon
Aug 28, 2026 1 min read 319 Views
347 words 2,158 chars Updated Nov 8, 2026
Redis Cache Design Patterns
Table of contents

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

About the author

Poll

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

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

Comments (5)

0 / 3000
云端漫步
云端漫步cloud-notes.cloudSep 20, 2026

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

机器学习萌新
机器学习萌新Sep 20, 2026

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

游戏策划阿哲
游戏策划阿哲Sep 20, 2026

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

奶茶味程序媛
奶茶味程序媛Sep 20, 2026

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

独立开发者阿明
独立开发者阿明aming.devSep 20, 2026

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

Related posts

Go Concurrency: Goroutines, Channels & sync.WaitGroup

Go Concurrency: Goroutines, Channels & sync.WaitGroup

Complete Go native concurrency guide: lightweight goroutines, CSP-style channels, sync.WaitGroup, Context cancellation, worker pool patterns, and goroutine leak prevention.

1 min read
Node.js Performance Diagnostics: clinic.js & Flamegraphs

Node.js Performance Diagnostics: clinic.js & Flamegraphs

Node.js performance diagnostics: clinic.js one-click reports, reading flamegraphs for hot functions, event-loop blockers, memory leak stacks to pinpoint CPU/memory bottlenecks.

1 min read
Python Concurrency: asyncio vs ThreadPool vs ProcessPool

Python Concurrency: asyncio vs ThreadPool vs ProcessPool

Deep Python concurrency comparison: ThreadPool for IO-bound, ProcessPool bypassing GIL for CPU-bound, asyncio coroutines for ultra IO. 4-dimension decision tree with perf and complexity.

1 min read
CQRS + Event Sourcing Architecture Patterns

CQRS + Event Sourcing Architecture Patterns

Advanced patterns: CQRS separate read/write models for query performance; Event Sourcing using events as source of truth for audit + time travel. Covers consistency, snapshots, idempotency pitfalls and anti-patterns.

1 min read
Rust Ownership & Borrowing: Lifetimes Explained

Rust Ownership & Borrowing: Lifetimes Explained

Master Rust's most unique concepts: ownership rules, mutable/immutable borrowing constraints, lifetime annotations. Compile-error examples + fixes to think like the Borrow Checker for safe zero-cost code.

1 min read
Test Pyramid: Unit/Integration/E2E Ratios & Implementation

Test Pyramid: Unit/Integration/E2E Ratios & Implementation

Systematic test pyramid breakdown: bottom unit tests (many, fast, mock isolated), middle integration tests (real service/db/message interaction), top E2E tests (few, critical user flows). Recommended ratio 70/20/10, with coverage metrics and implementation playbook.

1 min read