# ADR-005 : Base de Données **Statut** : Accepté **Date** : 2025-01-17 ## Contexte Requêtes géolocalisées intensives (contenus à proximité), données utilisateurs, historiques d'écoute. ## Décision - **PostgreSQL + PostGIS** : Données persistantes et requêtes géospatiales - **PgBouncer** : Connection pooling pour PostgreSQL - **Redis Cluster** : Cache géolocalisation et sessions ## Architecture ```mermaid flowchart LR A[Requête API] B[Redis Cache] C[PgBouncer] D[PostgreSQL + PostGIS] E[Réponse] A --> B B -->|HIT| E B -->|MISS| C C --> D D --> C C --> B B --> E ``` ## Alternatives considérées | Usage | Option choisie | Alternatives | |-------|---------------|--------------| | Données utilisateurs | PostgreSQL | MySQL, MongoDB | | Géolocalisation | PostGIS | MongoDB Geo, Elasticsearch | | Cache | Redis | Memcached, KeyDB | | Analytics (futur) | ClickHouse | TimescaleDB | ## Justification ### PostgreSQL + PostGIS - Requêtes géospatiales complexes et précises - Index GIST pour performance - ACID, fiabilité éprouvée - Écosystème mature ### PgBouncer - **Connection pooling** : Réduit l'overhead de création de connexions PostgreSQL - **Mode transaction** : Connexion réutilisée entre transactions (optimal pour API stateless) - **Performance** : Permet de gérer 1000+ connexions concurrentes avec ~100 connexions réelles à PostgreSQL - **Scaling** : Essentiel pour supporter la montée en charge sans surcharger PostgreSQL - **Port** : :6432 (vs :5432 pour PostgreSQL direct) ### Redis - Cache géo natif (`GEORADIUS`) : 100K+ requêtes/sec - Sessions utilisateurs - Pub/sub pour temps réel ## Exemple de requête ```sql SELECT id, name, ST_Distance(location::geography, ST_MakePoint($lon, $lat)::geography) as distance FROM contents WHERE ST_DWithin(location::geography, ST_MakePoint($lon, $lat)::geography, 50000) ORDER BY distance LIMIT 20; ``` ## Conséquences - TTL cache Redis : 5 minutes (le contenu géolocalisé ne bouge pas) - Index GIST sur colonnes géométriques - Réplication read replicas pour scaling lecture ### Configuration PgBouncer **Mode recommandé** : `transaction` - Connexion libérée après chaque transaction - Optimal pour API stateless (Go + Fiber) - Maximise la réutilisation des connexions **Pool sizing** : - `default_pool_size` : 20 (connexions par base) - `max_client_conn` : 1000 (connexions clients max) - `reserve_pool_size` : 5 (connexions de secours) **Configuration type** (`pgbouncer.ini`) : ```ini [databases] roadwave = host=localhost port=5432 dbname=roadwave zitadel = host=localhost port=5432 dbname=zitadel [pgbouncer] listen_port = 6432 listen_addr = * auth_type = scram-sha-256 pool_mode = transaction default_pool_size = 20 max_client_conn = 1000 reserve_pool_size = 5 server_idle_timeout = 600 ``` **Connexion application Go** : ```go // Avant (PostgreSQL direct) // dsn := "postgres://user:pass@localhost:5432/roadwave" // Après (via PgBouncer) dsn := "postgres://user:pass@localhost:6432/roadwave" ```