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.
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.