# 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 - [Redis Geospatial Documentation](https://redis.io/docs/data-types/geospatial/) - [go-redis/redis](https://github.com/redis/go-redis) - [ADR-005 : Base de Données](./005-base-de-donnees.md) (architecture cache + PostgreSQL)