# Diagramme de Séquence : Cache Géospatial Redis > Architecture du cache Redis Geospatial pour l'optimisation des requêtes de découverte de contenu géolocalisé. ## Vue d'ensemble Le cache Redis Geospatial permet d'accélérer la recherche de contenus audio à proximité d'une position GPS en évitant des calculs PostGIS coûteux sur PostgreSQL à chaque requête. **Performance** : - Sans cache : ~200-500ms (calcul PostGIS sur 100K points) - Avec cache : ~5-10ms (filtrage Redis en mémoire) --- ## Flux complet : Cold Start → Warm Cache ```mermaid sequenceDiagram participant User as 📱 Utilisateur
(Paris) participant Backend as 🔧 Backend Go participant Redis as 🔴 Redis Geospatial
(Cache) participant PostgreSQL as 🗄️ PostgreSQL
+ PostGIS participant CDN as 🌐 NGINX Cache (OVH VPS) Note over User,CDN: 🥶 Cold Start - Cache vide User->>Backend: GET /contents?lat=48.8566&lon=2.3522&radius=50km Backend->>Redis: EXISTS geo:catalog Redis-->>Backend: false (cache vide) Backend->>PostgreSQL: SELECT id, lat, lon, title, geo_level
FROM contents WHERE active=true Note over PostgreSQL: Tous les contenus actifs
de la plateforme (métadonnées) PostgreSQL-->>Backend: 100K contenus (métadonnées) Backend->>Redis: GEOADD geo:catalog
lon1 lat1 "content:1"
lon2 lat2 "content:2"
... (100K entrées) Note over Redis: Stockage index spatial
en mémoire (~20 MB) Redis-->>Backend: OK (100000) Backend->>Redis: EXPIRE geo:catalog 300 Note over Redis: TTL 5 minutes Backend->>Redis: GEORADIUS geo:catalog
2.3522 48.8566 50 km Note over Redis: Filtrage spatial instantané
(index geohash) Redis-->>Backend: [content:123, content:456, ...]
(~500 IDs dans rayon) Backend->>PostgreSQL: SELECT * FROM contents
WHERE id IN (123, 456, ...)
AND geo_level = 'gps_precise' Note over PostgreSQL: Récupération détails complets
uniquement contenus proches PostgreSQL-->>Backend: Détails complets (500 contenus GPS) Backend->>PostgreSQL: SELECT * FROM contents
WHERE city='Paris' OR dept='75'
OR region='IDF' OR geo_level='national' Note over PostgreSQL: Contenus par niveau géographique PostgreSQL-->>Backend: Contenus ville/région/national Backend->>Backend: Scoring & mixage :
- GPS proche : 70%
- Ville : 20%
- Région : 8%
- National : 2% Backend-->>User: JSON: [{id, title, creator, audioUrl, score}, ...]
(playlist mixée et scorée) Note over User,CDN: 🎵 Lecture audio (requêtes séparées) User->>CDN: GET /audio/content-123.m3u8 CDN-->>User: Playlist HLS User->>CDN: GET /audio/content-123-segment-001.ts CDN-->>User: Segment audio Opus Note over User,CDN: 🔥 Warm Cache - Utilisateur 2 à Lyon (45km+) participant User2 as 📱 Utilisateur 2
(Lyon) User2->>Backend: GET /contents?lat=45.7640&lon=4.8357&radius=50km Backend->>Redis: EXISTS geo:catalog Redis-->>Backend: true ✅ (cache chaud) Backend->>Redis: GEORADIUS geo:catalog
4.8357 45.7640 50 km Note over Redis: Filtrage instantané
sur cache existant Redis-->>Backend: [content:789, content:012, ...]
(~300 IDs différents) Backend->>PostgreSQL: SELECT * FROM contents
WHERE id IN (789, 012, ...)
AND geo_level = 'gps_precise' PostgreSQL-->>Backend: Détails complets Backend->>PostgreSQL: SELECT * FROM contents
WHERE city='Lyon' OR dept='69'
OR region='Auvergne-RA' OR geo_level='national' PostgreSQL-->>Backend: Contenus ville/région/national Backend->>Backend: Scoring & mixage Backend-->>User2: JSON: [{id, title, creator, audioUrl, score}, ...] ``` --- ## Stratégie de cache ### Cache du catalogue complet (approche choisie) **Principe** : Au premier cache miss, charger **TOUS** les contenus géolocalisés en une seule fois dans Redis. **Avantages** : - ✅ 1 seul cache miss au démarrage de l'instance - ✅ Toutes les requêtes suivantes servies par Redis (n'importe quelle position GPS) - ✅ Simple à gérer (1 seule clé Redis : `geo:catalog`) - ✅ Pas de duplication de données **Inconvénients** : - ⚠️ Premier utilisateur subit le cold start (~500ms-1s) - ⚠️ Nécessite charger toute la base (acceptable : ~20 MB pour 100K contenus) **Alternatives non retenues** : - Cache par zone géographique → cache miss fréquents, complexité gestion chevauchements - Cache à la demande → trop de cache miss, pas d'optimisation réelle --- ## Détails techniques ### 1. Données stockées dans Redis **Clé Redis** : `geo:catalog` **Structure** : ``` GEOADD geo:catalog 2.3522 48.8566 "content:12345" # lon, lat, member 4.8357 45.7640 "content:67890" ... ``` **Taille mémoire** : - ~200 bytes par entrée (ID + coordonnées + index geohash) - 100K contenus = ~20 MB - Négligeable pour Redis (plusieurs GB RAM disponibles) **TTL** : 5 minutes (300 secondes) - Le contenu géolocalisé est quasi-statique (change peu) - Rechargement automatique toutes les 5 minutes si cache expiré - Permet de propager les nouveaux contenus rapidement ### 2. Niveaux géographiques Le cache Redis ne contient que les contenus avec **GPS précis** (`geo_level = 'gps_precise'`). Les autres niveaux géographiques sont gérés par filtrage applicatif : | Niveau | Stockage | Requête | |--------|----------|---------| | **GPS précis** | Redis + PostgreSQL | `GEORADIUS` puis `SELECT WHERE id IN (...)` | | **Ville** | PostgreSQL uniquement | `SELECT WHERE city = ?` | | **Département** | PostgreSQL uniquement | `SELECT WHERE department = ?` | | **Région** | PostgreSQL uniquement | `SELECT WHERE region = ?` | | **National** | PostgreSQL uniquement | `SELECT WHERE geo_level = 'national'` | ### 3. Commandes Redis utilisées ```bash # Vérifier existence du cache EXISTS geo:catalog # Retour : 0 (n'existe pas) ou 1 (existe) # Charger le catalogue complet (cold start) GEOADD geo:catalog 2.3522 48.8566 "content:1" 4.8357 45.7640 "content:2" ... # Retour : nombre d'éléments ajoutés # Définir TTL 5 minutes EXPIRE geo:catalog 300 # Rechercher contenus dans un rayon GEORADIUS geo:catalog 2.3522 48.8566 50 km # Retour : ["content:123", "content:456", ...] # Optionnel : obtenir distance et coordonnées GEORADIUS geo:catalog 2.3522 48.8566 50 km WITHDIST WITHCOORD # Retour : [["content:123", "12.5", ["2.35", "48.85"]], ...] ``` ### 4. Algorithme de scoring Le backend mixe les résultats selon une pondération : ``` Score final = (Pertinence GPS × 0.70) + (Pertinence Ville × 0.20) + (Pertinence Région × 0.08) + (Pertinence National × 0.02) ``` **Critères de pertinence** : - **GPS** : Plus proche = score élevé (distance inversée) - **Ville/Région** : Matching exact = score maximal - **National** : Score fixe faible (contenu générique) **Mixage playlist** : 1. Trier tous les contenus par score décroissant 2. Appliquer diversité créateurs (pas 3 contenus du même créateur d'affilée) 3. Injecter contenus sponsorisés/mis en avant (futurs) 4. Retourner top 50 pour la session d'écoute --- ## Métriques de performance ### Temps de réponse typiques | Scénario | Latence | Détail | |----------|---------|--------| | **Cold start** | 500-1000ms | Chargement 100K contenus dans Redis + requête | | **Warm cache** | 5-10ms | `GEORADIUS` + `SELECT WHERE id IN (...)` | | **TTL expiré** | 500-1000ms | Rechargement automatique | ### Charge serveurs | Composant | Sans cache | Avec cache | |-----------|------------|------------| | **PostgreSQL CPU** | 60-80% | 10-20% | | **Redis CPU** | N/A | 5-15% | | **Throughput** | ~50 req/s | ~500 req/s | --- ## Cas limites et optimisations futures ### Cas limite 1 : Contenu très dense (Paris intra-muros) **Problème** : 10K contenus dans rayon 5km → trop de résultats **Solution actuelle** : - Limiter résultats Redis à 1000 premiers (tri par distance) - Scorer et filtrer côté application **Optimisation future** : - Ajuster rayon dynamiquement selon densité - Utiliser `GEORADIUS ... COUNT 500` pour limiter côté Redis ### Cas limite 2 : Zones rurales (peu de contenu) **Problème** : Rayon 50km retourne <10 contenus **Solution actuelle** : - Augmenter poids contenus région/national dans le scoring - Suggérer contenus nationaux populaires **Optimisation future** : - Augmenter rayon automatiquement jusqu'à obtenir min 20 contenus - `GEORADIUS ... 100 km` si rayon initial insuffisant ### Cas limite 3 : Nombreux créateurs actifs (évolutivité) **Problème** : Cache 100K → 1M contenus (200 MB Redis) **Solution actuelle** : - 200 MB reste acceptable pour Redis **Optimisation future** : - Sharding géographique : cache Europe, cache USA, etc. - Limiter cache aux contenus actifs 90 derniers jours --- ## Invalidation du cache ### Stratégies d'invalidation | Événement | Action cache | Détail | |-----------|--------------|--------| | **Nouveau contenu publié** | Lazy (TTL) | Visible sous 5 minutes max | | **Contenu supprimé/modéré** | Lazy (TTL) | Disparaît sous 5 minutes max | | **Mise à jour GPS contenu** | Lazy (TTL) | Nouvelle position sous 5 minutes | | **Déploiement backend** | Flush volontaire | `DEL geo:catalog` si schema change | **Pas d'invalidation immédiate** pour simplifier l'architecture (cohérence éventuelle acceptable). **Alternative future** : - Pub/Sub Redis : notifier toutes les instances backend lors d'un changement - `GEOADD geo:catalog 2.35 48.85 "content:new"` pour ajout immédiat --- ## Schéma simplifié ``` ┌─────────────────────────────────────────────────────────┐ │ Utilisateur │ │ (Position GPS actuelle) │ └────────────────────────┬────────────────────────────────┘ │ │ GET /contents?lat=X&lon=Y&radius=Z ▼ ┌─────────────────────────────────────────────────────────┐ │ Backend Go (Fiber) │ │ │ │ 1. Vérifier cache Redis │ │ ├─ Cache HIT → GEORADIUS rapide │ │ └─ Cache MISS → Charger catalogue complet │ │ │ │ 2. Filtrer contenus GPS proches (Redis) │ │ 3. Récupérer contenus ville/région/national (PG) │ │ 4. Scorer et mixer selon pondération │ │ 5. Retourner playlist │ └────────────┬───────────────────────────┬────────────────┘ │ │ │ GEORADIUS │ SELECT détails ▼ ▼ ┌─────────────────────┐ ┌───────────────────────────┐ │ Redis Geospatial │ │ PostgreSQL + PostGIS │ │ (Index spatial) │ │ (Données complètes) │ │ │ │ │ │ • geo:catalog │ │ • contents (détails) │ │ • TTL 5 min │ │ • users │ │ • ~20 MB mémoire │ │ • playlists │ └─────────────────────┘ └───────────────────────────┘ ``` --- ## Références - [ADR-005 : Base de données](../../adr/005-base-de-donnees.md) - [Redis Geospatial Commands](https://redis.io/docs/data-types/geospatial/) - [PostGIS Documentation](https://postgis.net/documentation/) - [Règles métier : Découverte de contenu géolocalisé](../../regles-metier/03-decouverte-contenu.md)