Cas d'usage Redis : cache, files d'attente et limitation de débit
Vous avez construit une application web qui gagne en popularité, mais à mesure que le trafic augmente, vous remarquez des requêtes de base de données lentes et des délais d'attente occasionnels. Votre serveur peine sous la charge et les utilisateurs se plaignent de la latence. Vous avez besoin d'un magasin de données en mémoire rapide pour décharger les tâches répétitives et gérer les pics de trafic. Redis est la solution de référence pour de nombreux défis backend, et dans cet article, nous allons explorer trois cas d'usage pratiques : la mise en cache, les files d'attente et la limitation de débit.
Pourquoi Redis ?
Redis est un magasin clé-valeur en mémoire open source, connu pour sa rapidité et sa polyvalence. Il prend en charge des structures de données telles que les chaînes, les hachages, les listes, les ensembles et les ensembles triés, ce qui le rend adapté à un large éventail de tâches. Contrairement aux bases de données traditionnelles, Redis conserve les données en RAM, offrant une latence inférieure à la milliseconde. Il propose également des options de persistance, de réplication et de clustering pour une haute disponibilité.
1. Mise en cache avec Redis
La mise en cache est le cas d'usage le plus courant de Redis. En stockant les données fréquemment consultées dans Redis, vous réduisez la charge sur votre base de données principale et accélérez les temps de réponse. Par exemple, si votre application affiche une liste de produits populaires, vous pouvez mettre en cache le résultat de la requête pendant quelques minutes.
Comment implémenter la mise en cache
- Vérifier le cache : Avant d'interroger la base de données, vérifiez si les données existent dans Redis.
- Si trouvé (succès du cache) : Retournez les données mises en cache.
- Si non trouvé (échec du cache) : Interrogez la base de données, stockez le résultat dans Redis avec un temps d'expiration (TTL), et retournez les données.
Voici un exemple en Python utilisant redis-py :
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def get_products():
cache_key = 'products:popular'
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# Simuler une requête de base de données
products = [{'id': 1, 'name': 'Product A'}, {'id': 2, 'name': 'Product B'}]
r.setex(cache_key, 300, json.dumps(products)) # Mettre en cache pendant 5 minutes
return products
Bonnes pratiques : Utilisez des clés de cache significatives, définissez des TTL appropriés et envisagez des stratégies d'invalidation du cache. Pour les données fréquemment modifiées, utilisez des TTL courts ou implémentez une mise en cache write-through.
2. Files d'attente avec Redis
Les listes et les streams Redis sont excellents pour construire des files d'attente de messages simples. Ils vous permettent de découpler les tâches chronophages (comme l'envoi d'e-mails ou le traitement d'images) du cycle requête-réponse, améliorant l'expérience utilisateur et l'évolutivité.
Utiliser les listes comme file d'attente
Vous pouvez utiliser LPUSH pour ajouter des tâches à une liste et BRPOP pour extraire atomiquement les tâches de l'autre extrémité. Cela crée une file d'attente FIFO.
Producteur :
r.lpush('email_queue', json.dumps({'to': 'user@example.com', 'subject': 'Welcome'}))
Consommateur (dans un processus worker) :
while True:
_, job = r.brpop('email_queue', timeout=30)
if job:
process_email(json.loads(job))
Considérations : Les listes Redis sont simples mais manquent de fonctionnalités avancées comme les accusés de réception. Pour des besoins plus robustes, envisagez Redis Streams, qui prennent en charge les groupes de consommateurs et l'accusé de réception des messages.
3. Limitation de débit avec Redis
La limitation de débit protège votre API contre les abus et garantit une utilisation équitable. Les opérations atomiques de Redis en font un choix idéal pour implémenter des limiteurs de débit. Un algorithme courant est le compteur à fenêtre glissante, mais une approche plus simple à fenêtre fixe fonctionne également bien.
Limiteur 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, refusez 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