Developer Tools

Redis au-delà du cache : structures de données, Pub/Sub et applications temps réel

Apprenez à utiliser Redis bien plus qu'un simple cache — explorez ses structures de données, la messagerie pub/sub, les streams et les patterns pour créer des applications rapides et évolutives.

10 min de lecture

Salle de serveurs avec des connexions lumineuses

La plupart des développeurs connaissent Redis comme « ce cache ultra-rapide ». Pourtant, Redis est un serveur de structures de données en mémoire complet, capable de gérer les sessions, les classements temps réel, la limitation de débit, les files de messages, et bien plus encore — le tout avec une latence inférieure à la milliseconde.

Pourquoi Redis est si rapide

Redis stocke tout en mémoire et utilise une boucle d'événements mono-thread pour traiter les commandes. Pas d'I/O disque en lecture, pas de contention de verrous, pas de changement de contexte. Le résultat : plus de 100 000 opérations par seconde sur du matériel modeste.

Comparaison typique des latences :
┌─────────────────┬──────────────┐
│ Opération       │ Latence      │
├─────────────────┼──────────────┤
│ Redis GET       │ 0.1 ms       │
│ PostgreSQL SEL  │ 1-5 ms       │
│ Appel REST API  │ 50-200 ms    │
│ Lecture disque  │ 5-10 ms      │
└─────────────────┴──────────────┘

Structures de données principales

Redis n'est pas un simple magasin clé-valeur. Il prend en charge des structures de données riches qui correspondent directement aux besoins courants des applications.

Strings — la brique de base

Les Strings contiennent du texte, des nombres ou des données binaires jusqu'à 512 Mo :

SET user:1001:name "Alice"
GET user:1001:name          # "Alice"

# Compteur atomique
INCR page:views             # 1, 2, 3, ...
INCRBY cart:total 2500      # Ajoute 25.00 (stocké en centimes)

# Clés avec expiration (TTL)
SET session:abc123 "{...}" EX 3600   # Expire dans 1 heure
TTL session:abc123                    # Secondes restantes

Hashes — objets légers

Les Hashes sont parfaits pour stocker des objets sans surcoût de sérialisation :

HSET user:1001 name "Alice" email "alice@example.com" plan "pro"
HGET user:1001 name         # "Alice"
HGETALL user:1001           # Tous les champs et valeurs
HINCRBY user:1001 logins 1  # Incrément atomique d'un champ

Les Hashes utilisent 10 fois moins de mémoire que le stockage de chaque champ sous une clé séparée.

Lists — files d'attente et flux

Collections ordonnées prenant en charge le push/pop aux deux extrémités :

LPUSH notifications:alice "Nouveau commentaire sur votre publication"
LPUSH notifications:alice "Vous avez un nouvel abonné"
LRANGE notifications:alice 0 9    # Les 10 dernières notifications

# Utilisation comme file d'attente (producteur/consommateur)
RPUSH queue:emails "send-welcome"
LPOP queue:emails                  # Traiter le prochain job

Sets — collections uniques

Collections non ordonnées de chaînes uniques :

SADD tags:post:42 "redis" "database" "nosql"
SMEMBERS tags:post:42             # Tous les tags
SISMEMBER tags:post:42 "redis"    # true

# Opérations sur les Sets
SINTER tags:post:42 tags:post:99  # Tags communs
SUNION tags:post:42 tags:post:99  # Tous les tags combinés

Sorted Sets — classements et rankings

Des Sets avec un score pour chaque membre, triés automatiquement :

ZADD leaderboard 1500 "alice" 2300 "bob" 1800 "charlie"
ZREVRANGE leaderboard 0 2 WITHSCORES   # Top 3 des joueurs
ZRANK leaderboard "alice"               # Rang (base 0)
ZINCRBY leaderboard 100 "alice"         # Alice marque 100 points

C'est ainsi que sont construits à grande échelle les classements de jeux, les posts tendance et les files de priorité.

Patterns du monde réel

Pattern 1 : stockage de sessions

Plutôt que des sessions sauvegardées en base de données, utilisez Redis pour des recherches instantanées :

import redis
r = redis.Redis()

# Stocker la session
r.setex(f"session:{token}", 3600, json.dumps(user_data))

# Récupérer la session
data = r.get(f"session:{token}")

Pourquoi ? Les sessions en base de données ajoutent 1 à 5 ms par requête. Les sessions Redis ajoutent 0,1 ms. À 1 000 requêtes/s, cela représente 5 secondes économisées chaque seconde.

Pattern 2 : limitation de débit

Limiteur à fenêtre glissante en 3 commandes :

# Autoriser 100 requêtes par minute par utilisateur
MULTI
INCR rate:user:1001
EXPIRE rate:user:1001 60
EXEC

# Vérification : si le résultat de INCR > 100, rejeter la requête

Pattern 3 : mise en cache avec cache-aside

Le pattern de mise en cache le plus courant :

def get_user(user_id):
    # 1. Vérifier le cache
    cached = redis.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)
    
    # 2. Cache miss → interroger la base de données
    user = db.query("SELECT * FROM users WHERE id = %s", user_id)
    
    # 3. Peupler le cache (expire dans 5 minutes)
    redis.setex(f"user:{user_id}", 300, json.dumps(user))
    return user

Pattern 4 : Pub/Sub pour les événements temps réel

Redis Pub/Sub permet la messagerie temps réel entre services :

# Abonné (écoute les messages)
SUBSCRIBE chat:room:42

# Éditeur (envoie des messages)
PUBLISH chat:room:42 "Bonjour tout le monde !"

Dans le code applicatif :

# Éditeur
redis.publish("notifications", json.dumps({
    "type": "new_order",
    "order_id": 12345
}))

# Abonné
pubsub = redis.pubsub()
pubsub.subscribe("notifications")
for message in pubsub.listen():
    handle_notification(message)

Pattern 5 : verrous distribués

Évitez les conditions de concurrence entre plusieurs serveurs :

# Acquérir le verrou (NX = seulement si inexistant, EX = expiration)
SET lock:invoice:gen "worker-1" NX EX 30

# Libérer le verrou (uniquement si vous en êtes propriétaire — utiliser un script Lua)

Redis Streams — event sourcing et files de messages

Les Streams sont la réponse de Redis aux journaux d'événements de style Kafka :

# Ajouter des événements
XADD orders * user_id 1001 product "Widget" qty 3
XADD orders * user_id 1002 product "Gadget" qty 1

# Lire les derniers événements
XRANGE orders - + COUNT 10

# Groupes de consommateurs (plusieurs workers)
XGROUP CREATE orders processors $ MKSTREAM
XREADGROUP GROUP processors worker-1 COUNT 5 BLOCK 2000 STREAMS orders >

Les Streams offrent des journaux d'événements persistants et rejouables avec des groupes de consommateurs — idéaux pour la communication entre microservices.

Conseils de performance

1. Utiliser le pipelining pour les opérations en masse

Au lieu de 100 allers-retours, envoyez 100 commandes en une seule fois :

pipe = redis.pipeline()
for i in range(100):
    pipe.set(f"key:{i}", f"value:{i}")
pipe.execute()  # Un seul aller-retour

2. Choisir la bonne structure de données

  • Besoin d'un compteur ? → INCR (pas GET + SET)
  • Besoin d'un objet ? → Hash (pas une chaîne JSON sérialisée)
  • Besoin d'éléments uniques ? → Set (pas List + logique de déduplication)
  • Besoin d'un classement ? → Sorted Set (pas de tri après la requête)

3. Définir un TTL sur tout

La mémoire est limitée. Définissez toujours une expiration sur les clés de cache :

SET cache:api:result "{...}" EX 300   # TTL de 5 minutes

4. Utiliser des conventions de nommage des clés

ressource:id:champ
user:1001:profile
cache:api:v2:products
session:abc123
queue:emails:pending

Persistance : RDB vs AOF

Redis peut persister les données sur disque pour assurer la durabilité :

Mode Fonctionnement Compromis
RDB Snapshots ponctuels Récupération rapide, perte de données possible
AOF Journalise chaque écriture Plus lent, perte de données minimale
Les deux RDB + AOF combinés Meilleure durabilité
# Dans redis.conf
save 900 1          # Snapshot si 1 clé modifiée en 900s
appendonly yes      # Activer AOF
appendfsync everysec  # Fsync toutes les secondes

Référence rapide des commandes

Besoin de rechercher une commande Redis spécifique ? Utilisez notre Redis Cheat Sheet — elle couvre plus de 200 commandes organisées par structure de données avec la syntaxe, des exemples et une copie en un clic.

Pour conclure

Redis est bien plus qu'un cache. Ses structures de données correspondent parfaitement aux besoins réels des applications :

  • Strings → sessions, compteurs, cache simple
  • Hashes → profils utilisateurs, objets de configuration
  • Lists → files d'attente, fils d'activité, éléments récents
  • Sets → tags, visiteurs uniques, relations
  • Sorted Sets → classements, rankings, files de priorité
  • Streams → event sourcing, files de messages
  • Pub/Sub → notifications temps réel, chat

Commencez par la mise en cache, mais ne vous arrêtez pas là. Redis peut remplacer plusieurs composants d'infrastructure dans votre stack — et tout faire à une vitesse inférieure à la milliseconde.