Files
roadwave/docs/adr/023-solution-cache.md

5.9 KiB

ADR-023 : Solution de Cache

Statut : Accepté Date : 2026-01-31

Contexte

L'application nécessite un système de cache performant pour plusieurs cas d'usage critiques :

  • Cache de géolocalisation : Requêtes de proximité géographique intensives (contenus à moins de X mètres)
  • Sessions utilisateurs : Stockage temporaire des tokens JWT et contexte utilisateur
  • Données de référence : Métadonnées des contenus audio fréquemment consultés
  • Compteurs en temps réel : Nombre d'écoutes, statistiques d'engagement
  • Rate limiting : Protection contre les abus API

Les contraintes de performance sont strictes :

  • Latence p99 < 5ms pour les requêtes de cache
  • Support de 100K+ requêtes/seconde en lecture
  • Persistance optionnelle (données non critiques)
  • Clustering pour haute disponibilité

Décision

Redis 7+ en mode Cluster sera utilisé comme solution de cache principale.

Configuration :

  • Mode Cluster avec 3 nœuds minimum (haute disponibilité)
  • Persistence RDB désactivée pour les caches chauds (performance maximale)
  • AOF activé uniquement pour les sessions utilisateurs (durabilité)
  • Éviction allkeys-lru sur les caches non-critiques

Alternatives considérées

Critère Redis Memcached KeyDB Valkey
Géospatial natif GEORADIUS
Structures de données Sets, Hashes, Sorted Sets Clé-valeur simple
Clustering Redis Cluster Client-side
Pub/Sub
Écosystème Go go-redis/redis ⚠️ Limité Compatible Compatible
Maturité Très mature Mature ⚠️ Fork récent ⚠️ Fork très récent
License ⚠️ RSALv2 / SSPLv1 BSD BSD BSD

Memcached : Écarté pour l'absence de fonctionnalités géospatiales natives et de structures de données avancées (pas de sets, hashes).

KeyDB : Fork multi-thread de Redis compatible API. Écarté par manque de maturité relative et d'écosystème comparé à Redis (moins de contributions, documentation).

Valkey : Fork Linux Foundation de Redis (2024). Trop récent pour production, écosystème en construction. À réévaluer en 2026.

Justification

Fonctionnalités géospatiales natives

Redis fournit des commandes géospatiales optimisées critiques pour RoadWave :

  • GEOADD : Indexation de contenus géolocalisés
  • GEORADIUS : Recherche par rayon (ex: contenus à moins de 5km)
  • GEODIST : Calcul de distance entre deux points

Ces commandes permettent de servir les requêtes de proximité directement depuis le cache sans solliciter PostgreSQL/PostGIS, réduisant la latence de 50-80ms à <5ms.

Structures de données riches

  • Hashes : Métadonnées de contenus (titre, durée, URL HLS) → accès partiel efficace
  • Sets : Listes de contenus par catégorie, gestion de favoris
  • Sorted Sets : Classement par popularité, top écoutes hebdomadaires
  • Strings avec TTL : Sessions utilisateurs avec expiration automatique

Performance et scalabilité

  • Débit : 100K+ ops/sec par nœud en lecture (benchmark Redis Labs)
  • Latence : p99 < 1ms pour GET/SET simple
  • Clustering : Partitionnement automatique des données sur 16384 hash slots
  • Réplication : Read replicas pour scaling horizontal en lecture

Écosystème Go

Librairie go-redis/redis (13K+ stars GitHub) :

  • Support complet Redis Cluster
  • Pipeline et transactions
  • Context-aware (intégration Go idiomatique)
  • Pooling de connexions automatique

Pub/Sub pour temps réel

Support natif de messaging publish/subscribe pour :

  • Notifications push (invalidation de cache)
  • Événements temps réel (nouveau contenu géolocalisé)
  • Coordination entre instances API (scaling horizontal)

Conséquences

Positives

  • Cache géospatial : Réduction de charge PostgreSQL de ~70% sur requêtes de proximité
  • Latence : p99 < 5ms pour requêtes de contenu en cache (vs ~50ms PostgreSQL)
  • Scaling horizontal : Ajout de nœuds Redis transparent pour l'application
  • Polyvalence : Un seul système pour cache, sessions, rate limiting, pub/sub

Négatives

  • Complexité opérationnelle : Cluster Redis nécessite monitoring (slots, rebalancing)
  • Persistance limitée : RDB/AOF moins fiable que PostgreSQL → pas pour données critiques
  • Consommation mémoire : Structures riches = overhead vs Memcached (~20% de RAM en plus)

Stratégie de cache

TTL par type de donnée :

  • Métadonnées de contenu : 15 minutes (mise à jour rare)
  • Résultats géolocalisés : 5 minutes (contenus statiques géographiquement)
  • Sessions utilisateurs : 24 heures (renouvellement automatique)
  • Rate limiting : 1 minute (fenêtre glissante)

Invalidation :

  • Publication de contenu → DEL métadonnées + publication Pub/Sub
  • Modification géolocalisation → GEOREM puis GEOADD
  • Logout utilisateur → DEL session

Configuration production

Cluster 3 nœuds (minimum haute disponibilité) :

  • 1 master + 2 replicas
  • Répartition sur 3 zones de disponibilité (anti-affinité)
  • cluster-require-full-coverage no → lecture dégradée si nœud down

Mémoire :

  • maxmemory 2gb par nœud (ajustable selon charge)
  • maxmemory-policy allkeys-lru → éviction automatique anciennes clés

Persistance :

  • RDB désactivé (save "") pour caches chauds
  • AOF appendonly yes uniquement pour sessions (nœud dédié optionnel)

Monitoring

Métriques critiques à suivre :

  • Taux de hit/miss par namespace (target >95% hit rate)
  • Latence p99 par commande (alerter si >10ms)
  • Fragmentation mémoire (rebalance si >1.5)
  • Slots distribution dans le cluster

Références