Cas d'usage Redis : cache, files d'attente et limitation de débit
Vous avez ajouté Redis à votre stack, mais vous ne l'utilisez que comme un simple magasin clé-valeur. Redis offre des structures de données et des commandes puissantes qui peuvent résoudre élégamment le cache, les files d'attente et la limitation de débit. Ce guide vous montre comment implémenter ces patterns efficacement.
Pourquoi Redis pour ces cas d'usage ?
Redis est un magasin de données en mémoire connu pour sa rapidité et sa polyvalence. Il prend en charge les chaînes, les hachages, les listes, les ensembles, les ensembles triés, et plus encore. Ses opérations atomiques et son expiration intégrée le rendent idéal pour le cache, les files d'attente et la limitation de débit. De plus, il est facile à intégrer avec n'importe quel langage.
Cache avec Redis
Le cache est le cas d'usage le plus courant de Redis. Vous stockez les données fréquemment consultées dans Redis pour réduire la charge de la base de données et accélérer les réponses.
Pattern de cache-aside de base
Dans le pattern cache-aside, votre application vérifie d'abord Redis. Si les données ne sont pas là (échec de cache), elle les récupère depuis la base de données, puis les stocke dans Redis pour la prochaine fois.
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def get_user(user_id):
cache_key = f'user:{user_id}'
cached = r.get(cache_key)
if cached:
return json.loads(cached)
user = fetch_user_from_db(user_id) # votre appel DB
r.setex(cache_key, 3600, json.dumps(user)) # cache pendant 1 heure
return user
Bonnes pratiques :
- Définissez toujours un temps d'expiration (TTL) pour éviter les données obsolètes.
- Utilisez des noms de clés significatifs, comme
user:123:profile. - Gérez l'invalidation du cache : lorsque les données changent, mettez à jour ou supprimez l'entrée de cache.
- Envisagez d'utiliser les hachages Redis pour stocker plusieurs champs d'un objet afin d'économiser de la mémoire.
Patterns de cache avancés
Pour les applications à fort trafic, envisagez ces patterns :
- Write-through : Mettez à jour le cache et la base de données ensemble.
- Write-behind : Mettez à jour le cache d'abord, puis mettez à jour la base de données de manière asynchrone.
- Refresh-ahead : Rafraîchissez proactivement les entrées de cache avant leur expiration.
Files d'attente avec Redis
Les listes et les streams Redis sont parfaits pour construire des files d'attente de messages simples. Utilisez les listes pour les files d'attente de tâches de base et les streams pour un traitement d'événements plus complexe.
File d'attente de tâches simple avec des listes
Utilisez LPUSH pour ajouter des tâches et BRPOP pour les traiter. BRPOP bloque jusqu'à ce qu'une tâche soit disponible, ce qui le rend efficace pour les workers.
# Producteur
r.lpush('jobs', json.dumps({'task': 'send_email', 'to': 'user@example.com'}))
# Consommateur (worker)
while True:
_, job_data = r.brpop('jobs', timeout=30)
job = json.loads(job_data)
process_job(job)
Bonnes pratiques :
- Utilisez des listes séparées pour différents types de tâches ou priorités.
- Implémentez une file d'attente de lettres mortes pour les tâches échouées.
- Utilisez
BRPOPLPUSH(ouBLMOVEdans Redis 6.2+) pour déplacer atomiquement les tâches vers une liste de traitement, assurant la fiabilité. - Surveillez la longueur de la file d'attente avec
LLENpour dimensionner les workers.
Redis Streams pour l'event sourcing
Redis Streams (introduit dans Redis 5.0) fournit une file d'attente plus robuste avec des groupes de consommateurs, des accusés de réception et la relecture. Utilisez XADD pour ajouter des événements et XREADGROUP pour les consommer.
# Ajouter un événement
r.xadd('events', {'type': 'order_placed', 'order_id': '123'})
# Groupe de consommateurs
r.xgroup_create('events', 'order_processors', id='0', mkstream=True)
while True:
events = r.xreadgroup('order_processors', 'worker1', {'events': '>'}, count=10, block=5000)
for event in events:
process_event(event)
r.xack('events', 'order_processors', event.id)
Limitation de débit avec Redis
La limitation de débit protège vos API contre les abus et assure une utilisation équitable. Les opérations atomiques de Redis le rendent idéal pour compter les requêtes.
Limitation de débit à fenêtre fixe
Incrémentez un compteur pour chaque utilisateur et définissez une expiration. Si le compteur dépasse la limite, bloquez la requête.
def is_allowed(user_id, limit=100, window=60):
key = f'rate_limit:{user_id}'
current = r.incr(key)
if current == 1:
r.expire(key, window)
return current