Aller au contenu

Scalability - Scénarios de Scaling

Date: 2026-01-04 Status: Production-Ready


Introduction

Ce document détaille les scénarios de montée en charge de la plateforme Urbafix, de la configuration initiale single-instance jusqu'au déploiement multi-régions avec auto-scaling.

Principe : Activation progressive, opt-in, sans refonte complète.


Scénario 1: Single Instance (Actuel)

Architecture

┌─────────────────────┐
│  Reverse Proxy      │  (au choix)
│  (SSL termination)  │
└──────────┬──────────┘
           │
┌──────────▼──────────┐
│   Docker Host       │
│                     │
│  ┌──────────────┐   │
│  │ Web Container│   │  PHP 8.2 + Nginx
│  │ - Sessions   │   │
│  │   file       │   │
│  │ - Cache null │   │
│  │ - Queue sync │   │
│  │ - Uploads    │   │
│  │   local      │   │
│  └──────┬───────┘   │
│         │           │
│  ┌──────▼───────┐   │
│  │ DB Container │   │  MariaDB 10.11
│  │              │   │
│  └──────────────┘   │
└─────────────────────┘

Caractéristiques

  • Instances web : 1
  • Sessions : Fichiers PHP locaux
  • Cache : Aucun (queries DB directes)
  • Uploads : Filesystem local
  • Queue : Exécution synchrone

Capacité

  • Utilisateurs concurrents : ~50
  • Requêtes/seconde : ~10 req/s
  • Incidents/jour : ~500
  • Stockage photos : Limité par disque serveur

Configuration

# .env
SESSION_DRIVER=file
CACHE_DRIVER=null
STORAGE_DRIVER=local
QUEUE_DRIVER=sync

Coût

  • Serveur : 1 VPS (2 vCPU, 4 GB RAM) : ~20€/mois
  • Backup : Snapshots : ~5€/mois
  • Total : ~25€/mois

Limites

  • ❌ Pas de haute disponibilité (SPOF)
  • ❌ Sessions perdues si restart
  • ❌ Scaling vertical uniquement
  • ❌ Backup manual

Scénario 2: Single Instance + Redis

Architecture

┌─────────────────────┐
│  Reverse Proxy      │
└──────────┬──────────┘
           │
┌──────────▼──────────┐
│   Docker Host       │
│                     │
│  ┌──────────────┐   │
│  │ Web Container│───┼──┐
│  │ - Sessions   │   │  │
│  │   redis      │   │  │
│  │ - Cache      │   │  │
│  │   redis      │   │  │
│  │ - Queue sync │   │  │
│  └──────────────┘   │  │
│         │           │  │
│  ┌──────▼───────┐   │  │
│  │ DB Container │   │  │
│  └──────────────┘   │  │
│         │           │  │
│  ┌──────▼───────┐   │  │
│  │Redis Container◄──┘  │
│  └──────────────┘   │
└─────────────────────┘

Amélioration

  • ✅ Sessions persistantes (survive restart)
  • ✅ Cache DB queries (-50% load DB)
  • ✅ Préparation multi-instances

Configuration

# .env
SESSION_DRIVER=redis
CACHE_DRIVER=redis
STORAGE_DRIVER=local
QUEUE_DRIVER=sync

REDIS_PASSWORD=secure_password_32chars

Commandes

# Lancer Redis
docker-compose --profile redis up -d

# Vérifier
docker-compose exec redis redis-cli -a ${REDIS_PASSWORD} PING

Capacité

  • Utilisateurs concurrents : ~100 (+100%)
  • Requêtes/seconde : ~20 req/s (+100%)
  • Cache hit ratio : ~60-70%

Coût

  • Serveur : 1 VPS (2 vCPU, 4 GB RAM) : ~20€/mois
  • Redis : Inclus (même serveur)
  • Total : ~20€/mois (identique)

Scénario 3: Horizontal Scaling (2-3 instances)

Architecture

┌─────────────────────┐
│  Load Balancer      │  (au choix)
│  (Round Robin)      │
└──────────┬──────────┘
           │
     ┌─────┴─────┬─────────┐
     │           │         │
┌────▼────┐ ┌───▼────┐ ┌──▼─────┐
│  Web 1  │ │ Web 2  │ │ Web 3  │  Stateless
│ :8080   │ │ :8081  │ │ :8082  │
└────┬────┘ └───┬────┘ └──┬─────┘
     │          │          │
     └─────┬────┴────┬─────┘
           │         │
     ┌─────▼─────┐   │
     │   Redis   │   │  Sessions + Cache
     │   :6379   │   │
     └───────────┘   │
                     │
              ┌──────▼──────┐
              │  MariaDB    │
              │   :3306     │
              └─────────────┘

Migration

Étape 1 : Activer Redis (voir Scénario 2)

Étape 2 : Lancer instances

# Instance 1
WEB_PORT=8080 docker-compose --profile redis up -d

# Instance 2
WEB_PORT=8081 docker-compose --profile redis up -d

# Instance 3
WEB_PORT=8082 docker-compose --profile redis up -d

Étape 3 : Configurer le load balancer

Round-robin sur les 3 instances (127.0.0.1:8080, :8081, :8082), avec health check GET /health.php (attendu : HTTP 200) — la configuration exacte dépend du reverse proxy/load balancer choisi.

Étape 4 : Redémarrer le load balancer

# Commande spécifique à l'outil choisi

# Vérifier
curl http://localhost/health.php

Capacité

  • Utilisateurs concurrents : ~300 (x3)
  • Requêtes/seconde : ~60 req/s (x3)
  • Haute disponibilité : Oui (⅔ instances peuvent tomber)

Configuration

# .env (identique pour toutes instances)
SESSION_DRIVER=redis
CACHE_DRIVER=redis
STORAGE_DRIVER=local  # ⚠️ Volume partagé NFS requis
QUEUE_DRIVER=sync

Coût

  • Serveurs : 3 VPS (2 vCPU, 4 GB RAM) : ~60€/mois
  • Load Balancer : 1 VPS (1 vCPU, 2 GB RAM) : ~10€/mois
  • Total : ~70€/mois

Limites

  • ⚠️ Uploads locaux : NFS requis (complexité)
  • ⚠️ DB single point of failure
  • ⚠️ Queue sync : latence uploads

Scénario 4: Cloud-Native (S3 + Async Queue)

Architecture

┌─────────────────────┐
│  Load Balancer      │
│  (AWS ALB/ELB)      │
└──────────┬──────────┘
           │
     ┌─────┴─────┬─────────┐
     │           │         │
┌────▼────┐ ┌───▼────┐ ┌──▼─────┐
│  Web 1  │ │ Web 2  │ │ Web 3  │  Stateless
└────┬────┘ └───┬────┘ └──┬─────┘
     │          │          │
     └─────┬────┴────┬─────┘
           │         │
     ┌─────▼─────┐   │
     │   Redis   │   │  Sessions + Cache + Queue
     │ ElastiCache│   │
     └─────┬─────┘   │
           │         │
     ┌─────▼─────┐   │
     │  Workers  │   │  3 workers Supervisord
     │ (pHash,   │   │
     │  Blur,    │   │
     │  Email)   │   │
     └─────┬─────┘   │
           │         │
     ┌─────▼─────┐   │
     │  AWS S3   │   │  Uploads
     └───────────┘   │
                     │
              ┌──────▼──────┐
              │  RDS        │  MariaDB managed
              │  (Multi-AZ) │
              └─────────────┘

Migration

Étape 1 : Migrer uploads vers S3

# Créer bucket
aws s3 mb s3://urbafix-prod-uploads --region eu-west-3

# Copier uploads existants
aws s3 sync ./public/backend/uploads/ s3://urbafix-prod-uploads/

# Modifier .env
STORAGE_DRIVER=s3
STORAGE_S3_BUCKET=urbafix-prod-uploads
STORAGE_S3_REGION=eu-west-3
STORAGE_S3_KEY=AKIA...
STORAGE_S3_SECRET=...

# Redémarrer
docker-compose restart web

Étape 2 : Activer queue async

# .env
QUEUE_DRIVER=redis

# Créer bin/worker.php (voir DOCKER_STATELESS.md)

# Configurer Supervisord
# /etc/supervisor/conf.d/urbafix-workers.conf

# Lancer workers
supervisorctl reread
supervisorctl update
supervisorctl start urbafix-worker:*

Étape 3 : Migrer vers RDS

# Créer RDS instance (AWS Console)
# - Engine: MariaDB 10.11
# - Multi-AZ: Enabled
# - Storage: 100 GB gp3

# Backup DB actuelle
mysqldump -h localhost -u root -p urbafix > backup.sql

# Restore vers RDS
mysql -h urbafix-prod.xxxxx.eu-west-3.rds.amazonaws.com \
      -u admin -p urbafix < backup.sql

# Modifier .env
DB_HOST=urbafix-prod.xxxxx.eu-west-3.rds.amazonaws.com
DB_USER=admin
DB_PASSWORD=rds_password

# Redémarrer
docker-compose restart web

Étape 4 : Migrer vers ElastiCache Redis

# Créer ElastiCache cluster (AWS Console)
# - Engine: Redis 7.x
# - Node type: cache.t3.micro
# - Multi-AZ: Enabled

# Modifier .env
SESSION_REDIS_HOST=urbafix-prod.xxxxx.cache.amazonaws.com
CACHE_REDIS_HOST=urbafix-prod.xxxxx.cache.amazonaws.com
QUEUE_REDIS_HOST=urbafix-prod.xxxxx.cache.amazonaws.com

# Redémarrer
docker-compose restart web

Capacité

  • Utilisateurs concurrents : ~1000
  • Requêtes/seconde : ~200 req/s
  • Incidents/jour : ~10000
  • Haute disponibilité : 99.95% (Multi-AZ)

Configuration

# .env
SESSION_DRIVER=redis
CACHE_DRIVER=redis
STORAGE_DRIVER=s3
QUEUE_DRIVER=redis

# AWS managed services
DB_HOST=urbafix-prod.xxxxx.rds.amazonaws.com
SESSION_REDIS_HOST=urbafix-prod.xxxxx.cache.amazonaws.com
STORAGE_S3_BUCKET=urbafix-prod-uploads

Coût

  • EC2 : 3 instances t3.medium : ~90€/mois
  • RDS : db.t3.medium Multi-AZ : ~120€/mois
  • ElastiCache : cache.t3.micro : ~20€/mois
  • S3 : 100 GB + requêtes : ~5€/mois
  • ALB : ~20€/mois
  • CloudWatch : ~10€/mois
  • Total : ~265€/mois

Scénario 5: Auto-Scaling (ECS/Kubernetes)

Architecture (AWS ECS)

┌─────────────────────────────────┐
│  CloudFront CDN                 │  Edge caching
└──────────┬──────────────────────┘
           │
┌──────────▼──────────────────────┐
│  Application Load Balancer      │
│  (HTTPS termination)            │
└──────────┬──────────────────────┘
           │
┌──────────▼──────────────────────┐
│  ECS Cluster                    │
│                                 │
│  ┌──────────────────────────┐   │
│  │ ECS Service (Web)        │   │
│  │ - Desired: 3             │   │
│  │ - Min: 2                 │   │
│  │ - Max: 10                │   │
│  │ - Auto-scaling:          │   │
│  │   CPU > 70% → +1 task    │   │
│  │   CPU < 30% → -1 task    │   │
│  └──────┬───────────────────┘   │
│         │                       │
│  ┌──────▼───────────────────┐   │
│  │ ECS Service (Workers)    │   │
│  │ - Desired: 3             │   │
│  │ - Queue-based scaling    │   │
│  └──────────────────────────┘   │
└─────────────────────────────────┘
           │
     ┌─────┴─────┬─────────┐
     │           │         │
┌────▼────┐ ┌───▼────┐ ┌──▼─────┐
│  RDS    │ │ElastiCache│ │  S3   │
│Multi-AZ │ │  Redis  │ │Uploads│
└─────────┘ └─────────┘ └────────┘

Déploiement ECS

task-definition.json :

{
  "family": "urbafix-web",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "urbafix/web:latest",
      "memory": 1024,
      "cpu": 512,
      "essential": true,
      "portMappings": [
        {
          "containerPort": 80,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {"name": "SESSION_DRIVER", "value": "redis"},
        {"name": "CACHE_DRIVER", "value": "redis"},
        {"name": "STORAGE_DRIVER", "value": "s3"},
        {"name": "QUEUE_DRIVER", "value": "redis"}
      ],
      "secrets": [
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:eu-west-3:123456789:secret:urbafix/db_password"
        },
        {
          "name": "REDIS_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:eu-west-3:123456789:secret:urbafix/redis_password"
        }
      ],
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost/health.php || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3
      }
    }
  ]
}

Auto-Scaling Policy :

{
  "TargetValue": 70.0,
  "PredefinedMetricSpecification": {
    "PredefinedMetricType": "ECSServiceAverageCPUUtilization"
  },
  "ScaleOutCooldown": 60,
  "ScaleInCooldown": 300
}

Capacité

  • Utilisateurs concurrents : Illimité (auto-scale)
  • Requêtes/seconde : 500+ req/s
  • Elasticité : Oui (min 2, max 10 tasks)

Coût

  • ECS Fargate : 3-10 tasks (dynamique) : ~150-500€/mois
  • RDS : db.r6g.large Multi-AZ : ~400€/mois
  • ElastiCache : cache.r6g.large Cluster : ~300€/mois
  • S3 : 1 TB + requêtes : ~30€/mois
  • ALB : ~25€/mois
  • CloudFront : 100 GB egress : ~10€/mois
  • Total : ~915-1265€/mois (variable selon charge)

Scénario 6: Multi-Régions (Disaster Recovery)

Architecture

                    ┌─────────────────┐
                    │  Route 53       │  Géo-routing
                    │  Health Checks  │
                    └────┬───────┬────┘
                         │       │
              ┌──────────┘       └──────────┐
              │                             │
    ┌─────────▼─────────┐         ┌─────────▼─────────┐
    │  Region EU-WEST-3 │         │  Region EU-WEST-1 │
    │  (Paris - Primary)│         │(Ireland - Failover)│
    │                   │         │                   │
    │  - ECS Cluster    │         │  - ECS Cluster    │
    │  - RDS Primary    │◄───────►│  - RDS Read Replica│
    │  - ElastiCache    │         │  - ElastiCache    │
    │  - S3 (CRR)       │◄───────►│  - S3 (Replica)   │
    └───────────────────┘         └───────────────────┘

Configuration

Route 53 Health Check :

{
  "Type": "HTTPS",
  "ResourcePath": "/health.php",
  "FullyQualifiedDomainName": "urbafix.fr",
  "Port": 443,
  "RequestInterval": 30,
  "FailureThreshold": 3
}

RDS Replication :

# Créer read replica en eu-west-1
aws rds create-db-instance-read-replica \
  --db-instance-identifier urbafix-replica-ireland \
  --source-db-instance-identifier urbafix-prod-paris \
  --db-instance-class db.r6g.large \
  --availability-zone eu-west-1a

# Promouvoir en cas de disaster
aws rds promote-read-replica \
  --db-instance-identifier urbafix-replica-ireland

S3 Cross-Region Replication :

{
  "Role": "arn:aws:iam::123456789:role/s3-replication",
  "Rules": [
    {
      "Status": "Enabled",
      "Priority": 1,
      "Filter": {},
      "Destination": {
        "Bucket": "arn:aws:s3:::urbafix-uploads-ireland",
        "ReplicationTime": {
          "Status": "Enabled",
          "Time": {"Minutes": 15}
        }
      }
    }
  ]
}

Failover Automatique

Procédure : 1. Route 53 health check échoue (3 tentatives) 2. Bascule DNS vers région Ireland (TTL 60s) 3. ECS tasks démarrent en Ireland 4. Read replica promue en primary 5. Application opérationnelle en <5 minutes

Coût

  • Région primaire : ~1000€/mois
  • Région failover :
  • RDS replica : ~400€/mois
  • ElastiCache standby : ~300€/mois
  • S3 CRR : ~50€/mois
  • Route 53 : ~10€/mois
  • Total : ~1760€/mois

RTO / RPO

  • RTO (Recovery Time Objective) : <5 minutes
  • RPO (Recovery Point Objective) : <1 minute (async replication)

Métriques & Monitoring

Indicateurs Clés

Métrique Seuil OK Seuil Warning Seuil Critical Action
CPU Web <60% 60-80% >80% Scale out
Memory Web <70% 70-85% >85% Scale out
DB Connections <50 50-80 >80 Optimize queries
Cache Hit Ratio >60% 40-60% <40% Increase TTL
Queue Size <100 100-500 >500 Add workers
Response Time <200ms 200-500ms >500ms Investigate
Error Rate <0.1% 0.1-1% >1% Alert on-call

Dashboards Grafana

Dashboard Web :

# Requêtes par seconde
rate(http_requests_total[5m])

# Latence P95
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# Taux d'erreur
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])

Dashboard Queue :

# Jobs en attente
queue_size{queue="default"}

# Jobs traités par seconde
rate(queue_jobs_processed_total[5m])

# Durée moyenne traitement
rate(queue_job_duration_seconds_sum[5m]) / rate(queue_job_duration_seconds_count[5m])


Recommandations par Taille

Petite Municipalité (<10k habitants)

Configuration : Scénario 1 ou 2 - Single instance + Redis optionnel - Coût : 20-25€/mois - Capacité : 500 incidents/jour


Municipalité Moyenne (10k-50k habitants)

Configuration : Scénario 3 - 2-3 instances + Redis + load balancer - Coût : 70€/mois - Capacité : 2000 incidents/jour


Grande Ville (>50k habitants)

Configuration : Scénario 4 - 3+ instances + S3 + RDS + ElastiCache - Coût : 265€/mois - Capacité : 10000 incidents/jour


Métropole / Multi-Villes

Configuration : Scénario 5 - ECS Auto-Scaling + AWS managed services - Coût : 915-1265€/mois - Capacité : Illimitée


National / Haute Disponibilité

Configuration : Scénario 6 - Multi-régions + Disaster Recovery - Coût : 1760€/mois - RTO <5min, RPO <1min


Checklist Migration

Scénario 1 → 2 (Ajouter Redis)

  • Lancer container Redis (--profile redis)
  • Configurer SESSION_DRIVER=redis
  • Configurer CACHE_DRIVER=redis
  • Tester health endpoint
  • Monitoring Redis (connexions, mémoire)

Scénario 2 → 3 (Horizontal Scaling)

  • Configurer NFS pour uploads (ou migrer S3)
  • Lancer 2-3 instances web
  • Configurer le load balancer
  • Tester health checks
  • Vérifier répartition charge

Scénario 3 → 4 (Cloud-Native)

  • Créer bucket S3 + copier uploads
  • Configurer STORAGE_DRIVER=s3
  • Activer QUEUE_DRIVER=redis
  • Lancer workers Supervisord
  • Migrer vers RDS
  • Migrer vers ElastiCache
  • Configurer ALB
  • Tests charge

Scénario 4 → 5 (Auto-Scaling)

  • Containeriser avec Docker
  • Créer task definitions ECS
  • Configurer auto-scaling policies
  • Déployer sur ECS
  • Tests scaling (stress test)
  • Monitoring CloudWatch

Scénario 5 → 6 (Multi-Régions)

  • Créer read replica RDS
  • Configurer S3 CRR
  • Dupliquer ECS cluster région 2
  • Configurer Route 53 health checks
  • Tests failover
  • Documentation runbook disaster recovery

Ressources