Communitygithub.com

redis-patterns

Redis 数据结构模式、缓存策略、分布式锁、限流、发布订阅和连接管理,适用于生产环境。在添加缓存、分布式锁、限流或使用 Redis 发布订阅功能时,或需要审查键设计时激活。

redis-patterns 是什么?

该技能提供了 Redis 在生产环境中的最佳实践参考,涵盖缓存策略、限流、分布式锁、发布订阅与流处理、键设计、连接管理及驱逐策略等核心模式。它支持 Python 编程语言,并针对常见的后端用例(如 Django/Flask 缓存、API 限流、工作线程协调、通知扇出等)给出了具体的代码示例和配置说明。技能详细描述了缓存旁路、写入直通、标签失效、固定窗口与滑动窗口限流、基于 SET NX PX 的单节点分布式锁以及 Redlock 算法、发布订阅和 Redis Streams 的消费者组实现。此外,还包括了连接池、集群模式和哨兵模式的生产级配置,以及避免无 TTL 键、KEYS * 命令等反模式的建议。用户可通过这些模式直接在项目中使用已封装的代码片段,提升 Redis 应用的可靠性、性能和可维护性。

兼容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/redis-patterns

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

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
布隆过滤器/HLLHyperLogLoghll:pageviews

核心模式

缓存旁路(惰性加载)

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

写入直通缓存

def update_product(product_id: int, data: dict):
    # 先写入数据库
    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}")

限流

固定窗口(简单)

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

滑动窗口(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
    -- 使用唯一成员(当前时间 + 序列)以避免同一毫秒内的冲突
    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 与流

Pub/Sub(即发即忘)

# 发布者
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)  # 限制流长度

# 消费者组——保证至少一次投递
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)

当需要投递保证、消费者组或重放能力时,优先使用 Streams 而非 Pub/Sub。

键设计

命名约定

# 模式:资源:id:字段
user:123:profile
order:456:status
cache:product:789

# 模式:命名空间:资源:id
myapp:session:abc123
myapp:ratelimit:user:123

# 模式:资源:日期(有时间限制的键)
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-lru仅对带 TTL 的键执行 LRU混合数据存储
allkeys-lfu驱逐最不经常使用项访问模式倾斜
volatile-ttl驱逐即将过期的键优先保留长生命周期数据

在 redis.conf 中设置:maxmemory-policy allkeys-lru

反模式

反模式问题修复
未设置 TTL 的键内存无限制增长始终设置 TTL
生产环境中使用 KEYS *阻塞服务器 (O(N))使用 SCAN 游标
存储大对象(>100KB)序列化慢,内存压力存储引用 + 从对象存储获取
一个 Redis 处理所有缓存与队列无隔离使用不同数据库或实例
忽略连接池限制负载下连接耗尽根据工作负载调整池大小
未处理缓存未命中雪崩冷启动时惊群效应使用锁或概率性提前过期
不加考虑的 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 缓存响应。键基于请求参数。

按用户限制 API 调用频率: 低流量端点使用固定窗口 + pipeline(transaction=True);高精度用户限流使用滑动窗口 Lua 脚本。

跨工作线程协调后台任务: 使用 acquire_lock,TTL 应超过预期任务持续时间。始终在 finally 块中释放锁。

将通知扇出到多个订阅者: 使用 Pub/Sub 进行即发即忘通知。如果需要保证投递或重放能力,切换到 Streams。

速查表

模式何时使用
缓存旁路读密集,可容忍轻微陈旧数据
写入直通需要强一致性
分布式锁防止对资源的并发访问
滑动窗口限流精确的按用户限流
Redis Streams带有消费者组的持久事件队列
Pub/Sub无需投递保证的广播
有序集合排行榜排名评分,分页
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/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

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.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相关技能