Communitygithub.com

redis-patterns

Modèles de structures de données Redis, stratégies de mise en cache, verrous distribués, limitation de débit, pub/sub et gestion des connexions pour les applications de production. À utiliser lors de l'ajout de cache, d'un verrou distribué, d'une limitation de débit ou de pub/sub avec Redis, ou lorsque la conception des clés nécessite une révision.

Qu'est-ce que redis-patterns ?

Ce jeu de compétences fournit un guide de référence complet pour l'utilisation de Redis dans des applications backend, couvrant les cas d'usage les plus courants tels que la mise en cache, la limitation de débit, les verrous distribués, la gestion des sessions et la messagerie via Pub/Sub ou Redis Streams. Il détaille le fonctionnement atomique des commandes Redis et l'importance des scripts Lua et des transactions MULTI/EXEC pour garantir la cohérence. La compétence inclut des extraits de code Python prêts à l'emploi, des bonnes pratiques pour la conception des clés (noms avec préfixes, TTL adaptés) et des stratégies de gestion des connexions (pooling, cluster, Sentinel). Elle met également en garde contre les anti-patrons courants comme l'absence de TTL sur les clés ou l'utilisation de `KEYS *` en production, et propose des solutions pour éviter les problèmes d'afflux de requêtes sur un cache froid. Les développeurs peuvent utiliser ce guide pour intégrer Redis de manière fiable dans leurs applications Django, Flask ou autres, en exploitant les schémas de données optimaux et les politiques d'éviction adaptées.

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

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Modèles Redis

Référence rapide des bonnes pratiques Redis pour les cas d'utilisation backend courants.

Fonctionnement

Redis est un magasin de structures de données en mémoire qui prend en charge les chaînes, les hachages, les listes, les ensembles, les ensembles triés, les flux, etc. Les commandes Redis individuelles sont atomiques sur une instance unique ; les workflows en plusieurs étapes nécessitent des scripts Lua, des transactions MULTI/EXEC ou une synchronisation explicite pour rester atomiques. Les données sont éventuellement persistées via des instantanés RDB ou des journaux AOF. Les clients communiquent via TCP en utilisant le protocole RESP ; les pools de connexions sont essentiels pour éviter la surcharge de la négociation par requête.

Quand activer

  • Ajout de cache à une application
  • Implémentation de la limitation de débit ou du throttling
  • Construction de verrous distribués ou de coordination
  • Mise en place de stockage de sessions ou de jetons
  • Utilisation de Pub/Sub ou de Redis Streams pour la messagerie
  • Configuration de Redis en production (pooling, éviction, clustering)

Aide-mémoire des structures de données

Cas d'utilisationStructureExemple de clé
Cache simpleStringproduct:123
Session utilisateurHashsession:abc
ClassementSorted Setscores:weekly
Visiteurs uniquesSetvisitors:2024-01-01
Flux d'activitéListfeed:user:456
Flux d'événementsStreamevents:orders
Compteurs / limites de débitString (INCR)ratelimit:user:123
Filtre Bloom / HLLHyperLogLoghll:pageviews

Modèles principaux

Cache-Aside (Chargement paresseux)

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 heure
    return product

Cache Write-Through

def update_product(product_id: int, data: dict):
    # Écrire d'abord dans la base de données
    db.execute("UPDATE products SET ... WHERE id = %s", product_id)

    # Mettre à jour immédiatement le cache
    cache_key = f"product:{product_id}"
    r.setex(cache_key, 3600, json.dumps(data))

Invalidation de cache

# Invalidation basée sur les tags — regrouper les clés connexes sous un ensemble
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)

Stockage de sessions

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}")

Limitation de débit

Fenêtre fixe (Simple)

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

Fenêtre glissante (Lua — Atomique)

-- 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
    -- Utiliser un membre unique (now + séquence) pour éviter les collisions dans la même milliseconde
    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]))

Verrous distribués

Verrou distribué (Nœud unique — 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)

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

Pour les configurations multi-nœuds, utilisez la bibliothèque redlock-py qui implémente l'algorithme Redlock complet.

Pub/Sub & Flux

Pub/Sub (Fire-and-Forget)

# Éditeur
def publish_event(channel: str, payload: dict):
    r.publish(channel, json.dumps(payload))

# Abonné (bloquant — exécuter dans un thread/processus séparé)
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']))

Flux Redis (File d'attente durable)

# Producteur
def emit(stream: str, event: dict):
    r.xadd(stream, event, maxlen=10000)  # Limiter la longueur du flux

# Groupe de consommateurs — garantit une livraison au moins une fois
try:
    r.xgroup_create('events:orders', 'processor', id='0', mkstream=True)
except Exception:
    pass  # Le groupe existe déjà

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)

Privilégiez les Flux au Pub/Sub lorsque vous avez besoin de garanties de livraison, de groupes de consommateurs ou de relecture.

Conception des clés

Conventions de nommage

# Modèle : resource:id:field
user:123:profile
order:456:status
cache:product:789

# Modèle : namespace:resource:id
myapp:session:abc123
myapp:ratelimit:user:123

# Modèle : resource:date (clés limitées dans le temps)
stats:pageviews:2024-01-01

Stratégie TTL

Type de donnéesTTL suggéré
Session utilisateur24h (86400)
Cache de réponse API5–15 min
Fenêtre de limitation de débitCorrespondre à la taille de la fenêtre
Jetons de courte durée5–10 min
Classement1h–24h
Données statiques/de référence1h–1 semaine

Définissez toujours un TTL. Les clés sans TTL s'accumulent indéfiniment et entraînent une pression sur la mémoire.

Gestion des connexions

Pool de connexions

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)

Mode Cluster

from redis.cluster import RedisCluster

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

Sentinel (Haute disponibilité)

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)

Politiques d'éviction

PolitiqueComportementMeilleur pour
noevictionErreur en écriture lorsque la mémoire est pleineFiles d'attente / données critiques
allkeys-lruÉviction des moins récemment utiliséesCache général
volatile-lruLRU uniquement parmi les clés avec TTLMagasin de données mixte
allkeys-lfuÉviction des moins fréquemment utiliséesModèles d'accès asymétriques
volatile-ttlÉviction des clés avec la plus courte durée de vie restantePrioriser les données à longue durée de vie

Définir via redis.conf : maxmemory-policy allkeys-lru

Anti-patrons

Anti-patronProblèmeCorrectif
Clés sans TTLLa mémoire croît indéfinimentToujours définir un TTL
KEYS * en productionBloque le serveur (O(N))Utiliser le curseur SCAN
Stocker de gros blobs (>100 Ko)Sérialisation lente, pression mémoireStocker une référence et récupérer depuis un magasin d'objets
Un seul Redis pour toutPas d'isolation entre cache et file d'attenteUtiliser des bases de données ou instances séparées
Ignorer les limites du pool de connexionsÉpuisement des connexions sous chargeDimensionner le pool en fonction de la charge de travail
Ne pas gérer une ruée vers le cache en cas d'absenceRuée sur un cache froidUtiliser des verrous ou une expiration précoce probabiliste
FLUSHALL sans réflexionEfface toute l'instanceLimiter les suppressions par modèle de clé

Prévention de la ruée en cas d'absence de cache

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)  # Revérifier après avoir acquis le verrou
        if cached:
            return json.loads(cached)
        value = fetch_fn()
        r.setex(key, ttl, json.dumps(value))
        return value

Remarque : pour les déploiements multi-processus, remplacez le verrou intra-processus par acquire_lock/release_lock de la section Verrous distribués ci-dessus.

Exemples

Ajouter un cache à un point de terminaison d'API Django/Flask : Utilisez cache-aside avec setex et un TTL de 5 minutes sur la réponse. Clé basée sur les paramètres de la requête.

Limiter le débit d'une API par utilisateur : Utilisez une fenêtre fixe avec pipeline(transaction=True) pour les points de terminaison à faible trafic ; utilisez une fenêtre glissante Lua pour un throttling précis par utilisateur.

Coordonner un travail en arrière-plan entre les workers : Utilisez acquire_lock avec un TTL qui dépasse la durée prévue du travail. Libérez toujours dans un bloc finally.

Diffuser des notifications à plusieurs abonnés : Utilisez Pub/Sub pour le fire-and-forget. Passez aux Flux si vous avez besoin d'une livraison garantie ou d'une relecture pour les consommateurs tardifs.

Référence rapide

ModèleQuand l'utiliser
Cache-asideLecture intensive, tolère une légère obsolescence
Write-throughCohérence forte requise
Verrou distribuéEmpêcher l'accès concurrent à une ressource
Limitation de débit par fenêtre glissanteThrottling précis par utilisateur
Flux RedisFile d'attente d'événements durable avec groupes de consommateurs
Pub/SubDiffusion sans garantie de livraison
Classement par ensemble triéScore classé, pagination
HyperLogLogComptage unique approximatif à faible empreinte mémoire

Connexe

  • Compétence : postgres-patterns — modèles de données relationnelles
  • Compétence : backend-patterns — modèles de couche API et service
  • Compétence : database-migrations — versionnement de schéma
  • Compétence : django-patterns — intégration du framework de cache Django
  • Agent : database-reviewer — workflow complet de révision de base de données

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.

Skills associés