# [COURS] GUIDE MONGODB REPLICA SET - 5 MACHINES - ULTRA DÉTAILLÉ

## [DOCS] PARTIE 1 : INTRODUCTION ET CONCEPTS FONDAMENTAUX

### * BIENVENUE DANS LE MONDE DE MONGODB REPLICA SET À 5 MACHINES !

Ce guide est conçu pour un **étudiant en génie logiciel débutant** qui veut comprendre **TOUT** sur les Replica Sets MongoDB avec une configuration professionnelle à 5 membres.

**Promesse de ce guide :**
[OK] Configuration PRODUCTION-READY avec 5 machines
[OK] Haute disponibilité maximale (tolérance de 2 pannes)
[OK] Performance optimale avec répartition de charge
[OK] Sécurité renforcée
[OK] Monitoring et maintenance avancés
[OK] Scripts d'automatisation complets

---

## [REFLEXION] QU'EST-CE QUE MONGODB ?

### Définition simple

**MongoDB** = Base de données NoSQL orientée documents

**Traduction en langage simple :**
Au lieu de stocker tes données dans des tableaux (comme MySQL), MongoDB les stocke dans des **documents JSON**.

**Analogie :**
```
Base de données SQL (MySQL)     vs     MongoDB (NoSQL)
═════════════════════════════          ═══════════════════════════

┌─────────────────────────┐            ┌──────────────────────────┐
│  Table: users           │            │  Collection: users       │
├─────────────────────────┤            ├──────────────────────────┤
│ id │ name    │ email    │            │  Document 1:             │
├────┼─────────┼──────────┤            │  {                       │
│ 1  │ Pierre  │ p@e.com  │            │    "_id": 1,             │
│ 2  │ Marie   │ m@e.com  │            │    "name": "Pierre",     │
└────┴─────────┴──────────┘            │    "email": "p@e.com",   │
                                       │    "age": 25,            │
  Structure RIGIDE                     │    "hobbies": ["code"]   │
  Colonnes fixes                       │  }                       │
  Relations complexes                  │                          │
                                       │  Document 2:             │
                                       │  {                       │
                                       │    "_id": 2,             │
                                       │    "name": "Marie",      │
                                       │    "email": "m@e.com"    │
                                       │  }                       │
                                       └──────────────────────────┘

                                         Structure FLEXIBLE
                                         Documents différents OK
                                         Pas de schéma strict
```

**Pourquoi MongoDB est populaire ?**

| Avantage | Explication |
|----------|-------------|
| **Flexible** | Pas besoin de définir un schéma strict à l'avance |
| **Scalable** | Facile d'ajouter des serveurs pour plus de puissance |
| **Rapide** | Excellentes performances en lecture/écriture |
| **JSON natif** | Format naturel pour les applis web modernes |
| **Géospatial** | Support natif des coordonnées GPS |
| **Agrégation** | Pipeline puissant pour analyser les données |

---

## [SYNC] QU'EST-CE QU'UN REPLICA SET ?

### Définition simple

**Replica Set** = Groupe de serveurs MongoDB qui contiennent **les mêmes données**

**Analogie du livre :**

```
Imagine que tu écris un livre important...

┌─────────────────────────────────────────────────────────────┐
│  SANS Replica Set (DANGEREUX [ATTENTION])                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [GUIDE] Un seul exemplaire du livre                             │
│     v                                                       │
│  [HOT] Si tu perds ce livre -> TOUT EST PERDU                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│  AVEC Replica Set à 5 membres (ULTRA-SÉCURISÉ [OK])           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [GUIDE] Exemplaire Original (Primary)                           │
│  [LIVRE] Copie 1 (Secondary)                                     │
│  [LIVRE] Copie 2 (Secondary)                                     │
│  [LIVRE] Copie 3 (Secondary)                                     │
│  [LIVRE] Copie 4 (Secondary)                                     │
│     v                                                       │
│  [HOT] Si tu perds 2 exemplaires -> Les 3 autres existent      │
│  [OK] Une copie devient automatiquement le nouveau original   │
│  [OK] Tolérance de panne MAXIMALE                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### Architecture d'un Replica Set à 5 membres

```
                    APPLICATION WEB/MOBILE
                         │
                         │ Lecture/Écriture
                         v
        ┌────────────────────────────────────────────────┐
        │       REPLICA SET MONGODB (5 MEMBRES)          │
        │                                                │
        │  ┌──────────────────────────────────────────┐  │
        │  │      PRIMARY (Principal)                 │  │
        │  │  ┌────────────────────────────────────┐  │  │
        │  │  │  Base de données                   │  │  │
        │  │  │  [EDIT]  TOUTES les écritures          │  │  │
        │  │  │  [EYE]  20% des lectures              │  │  │
        │  │  └────────────────────────────────────┘  │  │
        │  └──────────────────────────────────────────┘  │
        │              │                                 │
        │              │ Réplication automatique         │
        │              │ (copie en temps réel)           │
        │              v                                 │
        │  ┌──────────────────────────────────────────┐  │
        │  │  SECONDARY 1, 2, 3, 4                    │  │
        │  │  (4 Copies identiques)                   │  │
        │  ├──────────────┬──────────────┬────────────┤  │
        │  │              │              │            │  │
        │  │ SECONDARY 1  │ SECONDARY 2  │ SECONDARY 3│ │
        │  │  [EYE] 20% lect │ [EYE] 20% lect │  [EYE] 20% lect│ │
        │  │              │              │            │  │
        │  └──────────────┴──────────────┴────────────┘  │
        │  │                                          │  │
        │  │         SECONDARY 4                      │  │
        │  │          [EYE] 20% lectures                 │  │
        │  │                                          │  │
        │  └──────────────────────────────────────────┘  │
        └────────────────────────────────────────────────┘

        CHARGE RÉPARTIE : 100% / 5 = 20% par serveur ! [RAPIDE]
```

**Explication des rôles :**

### PRIMARY (Principal)
- **Rôle :** Reçoit TOUTES les écritures
- **Analogie :** Le directeur qui prend les décisions
- **Actions :**
  - [EDIT] Traite toutes les insertions, modifications, suppressions
  - [RESEAU] Envoie les changements aux 4 SECONDARY
  - [EYE] Gère 20% des lectures (répartition de charge)

### SECONDARY (Secondaire) - 4 membres
- **Rôle :** Maintiennent une copie exacte du PRIMARY
- **Analogie :** Les 4 assistants qui notent tout ce que fait le directeur
- **Actions :**
  - [ENTREE] Reçoivent les changements du PRIMARY
  - [SYNC] Appliquent les changements localement
  - [EYE] Gèrent chacun 20% des lectures
  - [OBJECTIF] N'importe lequel peut devenir PRIMARY si le PRIMARY tombe

---

## [OBJECTIF] POURQUOI 5 MEMBRES AU LIEU DE 3 ?

### Comparaison : 3 membres vs 5 membres

```
┌────────────────────────────────────────────────────────────────┐
│  REPLICA SET À 3 MEMBRES (Configuration minimale)              │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  Membres : 1 PRIMARY + 2 SECONDARY                             │
│  Majorité : 2/3                                                │
│  Tolérance de panne : 1 membre                                 │
│                                                                │
│  Scénario panne :                                              │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                        │
│  │ PRIMARY │  │SECONDARY│  │SECONDARY│                        │
│  └─────────┘  └─────────┘  └─────────┘                        │
│       [X]            │            │                              │
│     Tombe          │            │                              │
│                    └────────────┘                              │
│                    2 membres restants                          │
│                    Majorité OK (2/3)                           │
│                    [OK] Élection possible                        │
│                                                                │
│  Si 2ème membre tombe :                                        │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                        │
│  │ PRIMARY │  │SECONDARY│  │SECONDARY│                        │
│  └─────────┘  └─────────┘  └─────────┘                        │
│       [X]            [X]            │                              │
│                                 │                              │
│                          1 membre seul                         │
│                          Pas de majorité (1/3)                 │
│                          [X] Replica Set en READ-ONLY           │
│                          [X] Plus d'écritures possibles         │
│                                                                │
└────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────────────┐
│  REPLICA SET À 5 MEMBRES (Configuration professionnelle)       │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  Membres : 1 PRIMARY + 4 SECONDARY                             │
│  Majorité : 3/5                                                │
│  Tolérance de panne : 2 membres *                             │
│                                                                │
│  Scénario panne d'1 membre :                                   │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐ │
│  │ PRIMARY │  │   SEC1  │  │   SEC2  │  │   SEC3  │  │   SEC4  │ │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘ │
│       [X]            │            │            │            │      │
│                    │            │            │            │      │
│                    └────────────┴────────────┴────────────┘      │
│                    4 membres restants                           │
│                    Majorité OK (4/5 > 3/5)                      │
│                    [OK] Élection possible                         │
│                    [OK] Système continue normalement              │
│                                                                │
│  Scénario panne de 2 membres :                                 │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐ │
│  │ PRIMARY │  │   SEC1  │  │   SEC2  │  │   SEC3  │  │   SEC4  │ │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘ │
│       [X]            [X]            │            │            │      │
│                                 │            │            │      │
│                                 └────────────┴────────────┘      │
│                    3 membres restants                           │
│                    Majorité OK (3/5 = majorité exacte)          │
│                    [OK] Élection possible                         │
│                    [OK] Système continue de fonctionner ! [BRAVO]      │
│                                                                │
│  Scénario panne de 3 membres (rare mais couvert) :             │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐ │
│  │ PRIMARY │  │   SEC1  │  │   SEC2  │  │   SEC3  │  │   SEC4  │ │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘ │
│       [X]            [X]            [X]            │            │      │
│                                              │            │      │
│                                              └────────────┘      │
│                    2 membres restants                           │
│                    Pas de majorité (2/5 < 3/5)                  │
│                    [X] Replica Set en READ-ONLY                  │
│                                                                │
└────────────────────────────────────────────────────────────────┘
```

### Tableau comparatif

| Critère | 3 membres | 5 membres | Amélioration |
|---------|-----------|-----------|--------------|
| **Pannes tolérées** | 1 | 2 | +100% [OBJECTIF] |
| **Disponibilité** | 99.9% | 99.99% | +0.09% |
| **Capacité lecture** | 3× | 5× | +67% [RAPIDE] |
| **Temps d'arrêt/an** | ~9h | ~1h | -89% * |
| **Charge par serveur** | 33% | 20% | -39% [FORCE] |
| **Redondance** | 2 copies | 4 copies | +100% [SECURITE] |
| **Coût matériel** | 3 machines | 5 machines | +67% [ARGENT] |

---

## [MESURE] ARCHITECTURE FINALE POUR CE GUIDE

```
┌─────────────────────────────────────────────────────────────────┐
│                REPLICA SET: "rs0" - 5 MEMBRES                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  MACHINE 1 (192.168.1.10)                                       │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  PRIMARY (au démarrage)                                │     │
│  │  mongodb://192.168.1.10:27017                          │     │
│  │  Priorité: 5 (la plus haute, préféré comme PRIMARY)   │     │
│  │  Vote: Oui                                             │     │
│  │  Données: Oui                                          │     │
│  │  Tags: { dc: "paris", usage: "production" }           │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  MACHINE 2 (192.168.1.20)                                       │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  SECONDARY                                             │     │
│  │  mongodb://192.168.1.20:27017                          │     │
│  │  Priorité: 3 (haute, candidat PRIMARY de secours)     │     │
│  │  Vote: Oui                                             │     │
│  │  Données: Oui                                          │     │
│  │  Tags: { dc: "paris", usage: "production" }           │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  MACHINE 3 (192.168.1.30)                                       │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  SECONDARY                                             │     │
│  │  mongodb://192.168.1.30:27017                          │     │
│  │  Priorité: 2 (moyenne)                                 │     │
│  │  Vote: Oui                                             │     │
│  │  Données: Oui                                          │     │
│  │  Tags: { dc: "lyon", usage: "production" }            │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  MACHINE 4 (192.168.1.40)                                       │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  SECONDARY                                             │     │
│  │  mongodb://192.168.1.40:27017                          │     │
│  │  Priorité: 1 (normale)                                 │     │
│  │  Vote: Oui                                             │     │
│  │  Données: Oui                                          │     │
│  │  Tags: { dc: "lyon", usage: "analytics" }             │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  MACHINE 5 (192.168.1.50)                                       │
│  ┌────────────────────────────────────────────────────────┐     │
│  │  SECONDARY (DELAYED 1H - Protection)                   │     │
│  │  mongodb://192.168.1.50:27017                          │     │
│  │  Priorité: 0 (ne peut pas devenir PRIMARY)            │     │
│  │  Vote: Oui                                             │     │
│  │  Données: Oui (retard de 1 heure)                     │     │
│  │  Hidden: true (invisible aux applications)            │     │
│  │  SlaveDelay: 3600 secondes                            │     │
│  │  Tags: { dc: "marseille", usage: "backup" }           │     │
│  └────────────────────────────────────────────────────────┘     │
│                                                                 │
│  Quorum: 3/5 membres -> Tolérance: 2 membres en panne *        │
│  Distribution géographique: Paris (2), Lyon (2), Marseille (1) │
│  Latence réseau: < 50ms entre membres (recommandé)             │
└─────────────────────────────────────────────────────────────────┘
```

---

## [WEB] CONFIGURATION RÉSEAU POUR 5 MACHINES

### Option 1 : Réseau local existant (RECOMMANDÉ [OK])

```
┌────────────────────────────────────────────────────────────┐
│                    Ta Box Internet                          │
│                   (192.168.1.1)                            │
│                 Réseau: 192.168.1.0/24                     │
└────┬───────┬───────┬───────┬───────┬──────────────────────┘
     │       │       │       │       │
     │ WiFi  │ Eth   │ WiFi  │ Eth   │ WiFi
     v       v       v       v       v
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│Machine 1│ │Machine 2│ │Machine 3│ │Machine 4│ │Machine 5│
│ .10     │ │ .20     │ │ .30     │ │ .40     │ │ .50     │
│PRIMARY  │ │SECONDARY│ │SECONDARY│ │SECONDARY│ │SECONDARY│
│         │ │         │ │         │ │         │ │(DELAYED)│
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
```

**Étapes de configuration :**

**1. Connecter les 5 machines au même réseau**
- Toutes connectées à la même Box (WiFi ou Ethernet)
- Vérifier qu'elles sont sur le même sous-réseau

**2. Assigner des IPs statiques (IMPORTANT)**

**Pourquoi des IPs statiques ?**
```
IP dynamique (DHCP) : Peut changer au redémarrage
       v
Replica Set ne trouve plus le membre
       v
[X] Panne du Replica Set !

IP statique : Ne change JAMAIS
       v
[OK] Replica Set stable
```

**Configuration IP statique - Linux (Ubuntu/Debian) :**

```bash
# Sur CHAQUE machine, éditer la configuration réseau
sudo nano /etc/netplan/01-netcfg.yaml
```

**Machine 1 :**
```yaml
network:
  version: 2
  ethernets:
    enp0s3:  # Remplacer par ton interface (ip addr show)
      addresses:
        - 192.168.1.10/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4
```

**Machine 2 :**
```yaml
network:
  version: 2
  ethernets:
    enp0s3:
      addresses:
        - 192.168.1.20/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4
```

**Machine 3, 4, 5 : Même chose avec .30, .40, .50**

**Appliquer la configuration :**
```bash
sudo netplan apply
```

**Vérifier :**
```bash
ip addr show
# Tu dois voir ton IP statique
```

---

**Configuration IP statique - Windows :**

```
1. Panneau de configuration
2. Réseau et Internet
3. Centre Réseau et partage
4. Modifier les paramètres de la carte
5. Clic droit sur "Ethernet" ou "WiFi" -> Propriétés
6. IPv4 -> Propriétés
7. Utiliser l'adresse IP suivante :

Machine 1 :
   IP : 192.168.1.10
   Masque : 255.255.255.0
   Passerelle : 192.168.1.1
   DNS : 8.8.8.8, 8.8.4.4

Machine 2 :
   IP : 192.168.1.20
   [...]

Machine 3, 4, 5 : Pareil avec .30, .40, .50
```

---

**3. Tester la connectivité entre TOUTES les machines**

**Sur Machine 1 :**
```bash
ping 192.168.1.20  # Machine 2
ping 192.168.1.30  # Machine 3
ping 192.168.1.40  # Machine 4
ping 192.168.1.50  # Machine 5
```

**Résultat attendu (pour chaque ping) :**
```
PING 192.168.1.20 (192.168.1.20) 56(84) bytes of data.
64 bytes from 192.168.1.20: icmp_seq=1 ttl=64 time=2.34 ms
64 bytes from 192.168.1.20: icmp_seq=2 ttl=64 time=1.89 ms
^C
[OK] Connectivité OK
```

**Répéter ce test depuis TOUTES les machines vers TOUTES les autres !**

**Script de test complet (Linux/Mac) :**

```bash
#!/bin/bash
# Test de connectivité complète

echo "[RECHERCHE] Test de connectivité du Replica Set à 5 membres"
echo ""

MACHINES=("192.168.1.10" "192.168.1.20" "192.168.1.30" "192.168.1.40" "192.168.1.50")
NAMES=("Machine 1 (PRIMARY)" "Machine 2 (SEC1)" "Machine 3 (SEC2)" "Machine 4 (SEC3)" "Machine 5 (SEC4-DELAYED)")

for i in "${!MACHINES[@]}"; do
    IP="${MACHINES[$i]}"
    NAME="${NAMES[$i]}"
    
    echo "Testing ${NAME} (${IP})..."
    
    if ping -c 2 -W 2 "$IP" > /dev/null 2>&1; then
        echo "  [OK] ${NAME} is reachable"
    else
        echo "  [X] ${NAME} is NOT reachable"
    fi
done

echo ""
echo "[RECHERCHE] Test des ports MongoDB (27017)..."

for i in "${!MACHINES[@]}"; do
    IP="${MACHINES[$i]}"
    NAME="${NAMES[$i]}"
    
    if nc -zv "$IP" 27017 2>&1 | grep -q succeeded; then
        echo "  [OK] ${NAME} port 27017 is open"
    else
        echo "  [ATTENTION]  ${NAME} port 27017 is not open yet (normal if MongoDB not started)"
    fi
done
```

---

## [OBJECTIF] POURQUOI CETTE CONFIGURATION SPÉCIFIQUE ?

### Répartition géographique (simulation)

```
┌────────────────────────────────────────────────────────┐
│  DATACENTER PARIS (Machines 1 et 2)                   │
│  ┌──────────────┐  ┌──────────────┐                   │
│  │  Machine 1   │  │  Machine 2   │                   │
│  │  PRIMARY     │  │  SECONDARY   │                   │
│  │  Priority: 5 │  │  Priority: 3 │                   │
│  └──────────────┘  └──────────────┘                   │
│                                                        │
│  Rôle : Production principale                         │
│  Latence interne : < 1ms                              │
└────────────────────────────────────────────────────────┘
           │
           │ Fibre optique (10ms)
           v
┌────────────────────────────────────────────────────────┐
│  DATACENTER LYON (Machines 3 et 4)                    │
│  ┌──────────────┐  ┌──────────────┐                   │
│  │  Machine 3   │  │  Machine 4   │                   │
│  │  SECONDARY   │  │  SECONDARY   │                   │
│  │  Priority: 2 │  │  Priority: 1 │                   │
│  └──────────────┘  └──────────────┘                   │
│                                                        │
│  Rôle : Failover + Analytics                          │
│  Latence interne : < 1ms                              │
└────────────────────────────────────────────────────────┘
           │
           │ Fibre optique (30ms)
           v
┌────────────────────────────────────────────────────────┐
│  DATACENTER MARSEILLE (Machine 5)                     │
│  ┌──────────────┐                                     │
│  │  Machine 5   │                                     │
│  │  SECONDARY   │                                     │
│  │  DELAYED 1H  │                                     │
│  │  Priority: 0 │                                     │
│  └──────────────┘                                     │
│                                                        │
│  Rôle : Backup de sécurité (protection erreurs)      │
└────────────────────────────────────────────────────────┘

AVANTAGES :
[OK] Si datacenter Paris détruit -> Lyon prend le relais
[OK] Si datacenter Lyon détruit -> Paris continue
[OK] Si erreur humaine -> Machine 5 a l'état d'il y a 1h
[OK] Latence optimale : Clients à Paris/Lyon servis localement
```

### Priorités expliquées

```
┌──────────────────────────────────────────────────────────┐
│  SYSTÈME DE PRIORITÉS                                    │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  Machine 1 : Priority 5 (la plus haute)                 │
│  └─ Sera TOUJOURS PRIMARY si disponible                 │
│     Raison : Meilleur hardware, datacenter principal    │
│                                                          │
│  Machine 2 : Priority 3                                 │
│  └─ Devient PRIMARY si Machine 1 tombe                  │
│     Raison : Même datacenter, bon hardware             │
│                                                          │
│  Machine 3 : Priority 2                                 │
│  └─ Devient PRIMARY si Machines 1 et 2 tombent         │
│     Raison : Datacenter secondaire                      │
│                                                          │
│  Machine 4 : Priority 1                                 │
│  └─ Devient PRIMARY en dernier recours                  │
│     Raison : Réservé pour analytics normalement        │
│                                                          │
│  Machine 5 : Priority 0 (ne peut JAMAIS devenir PRIMARY)│
│  └─ Sert uniquement de backup de sécurité              │
│     Raison : Données retardées d'1h (pas à jour)       │
│                                                          │
└──────────────────────────────────────────────────────────┘
```

---

## [GRAPHIQUE] TABLEAU DES QUORUMS AVEC 5 MEMBRES

| Scénario | Membres actifs | Majorité ? | État |
|----------|----------------|------------|------|
| **Tous OK** | 5/5 | [OK] 5 > 3 | Optimal |
| **1 panne** | 4/5 | [OK] 4 > 3 | Fonctionne parfaitement |
| **2 pannes** | 3/5 | [OK] 3 = 3 | Fonctionne (limite) |
| **3 pannes** | 2/5 | [X] 2 < 3 | READ-ONLY (pas d'écritures) |
| **4 pannes** | 1/5 | [X] 1 < 3 | READ-ONLY |
| **5 pannes** | 0/5 | [X] 0 < 3 | Hors ligne |

**Conclusion : Tu peux perdre 2 membres et continuer à fonctionner ! [BRAVO]**

---

## [COURS] QUIZ DE VALIDATION PARTIE 1

**1. Quelle est la majorité nécessaire avec 5 membres ?**
- A) 2
- B) 3
- C) 4
- D) 5

<details>
<summary>Voir la réponse</summary>
[OK] **B) 3**

Majorité = (Nombre total / 2) + 1 = (5 / 2) + 1 = 2.5 + 1 = 3.5 -> arrondi à 3
</details>

---

**2. Combien de pannes simultanées peut tolérer un Replica Set à 5 membres ?**
- A) 1
- B) 2
- C) 3
- D) 4

<details>
<summary>Voir la réponse</summary>
[OK] **B) 2**

Avec 5 membres, majorité = 3. Si 2 tombent, il reste 3 membres -> majorité atteinte.
Si 3 tombent, il reste 2 membres -> pas de majorité.
</details>

---

**3. Pourquoi Machine 5 a Priority 0 ?**
- A) C'est une erreur de configuration
- B) Car elle est la plus lente
- C) Car ses données sont retardées d'1h (pas à jour)
- D) Car elle n'a pas assez de RAM

<details>
<summary>Voir la réponse</summary>
[OK] **C) Car ses données sont retardées d'1h (pas à jour)**

Une machine DELAYED ne doit JAMAIS devenir PRIMARY car ses données ne sont pas à jour. Priority 0 garantit qu'elle ne sera jamais élue PRIMARY.
</details>

---

**4. Quel est l'avantage principal de 5 membres vs 3 membres ?**
- A) C'est plus joli dans les diagrammes
- B) Tolérance de 2 pannes au lieu d'1
- C) MongoDB fonctionne plus vite
- D) C'est obligatoire en production

<details>
<summary>Voir la réponse</summary>
[OK] **B) Tolérance de 2 pannes au lieu d'1**

5 membres permettent de tolérer 2 pannes simultanées, contre 1 seule avec 3 membres. Cela offre une bien meilleure haute disponibilité.
</details>

---

**5. Pourquoi utiliser des IPs statiques et pas dynamiques (DHCP) ?**
- A) C'est plus rapide
- B) DHCP ne fonctionne pas avec MongoDB
- C) Les IPs peuvent changer et casser le Replica Set
- D) C'est obligatoire par MongoDB Inc.

<details>
<summary>Voir la réponse</summary>
[OK] **C) Les IPs peuvent changer et casser le Replica Set**

Avec DHCP, l'IP peut changer au redémarrage. Le Replica Set ne retrouvera plus le membre avec son ancienne IP -> panne du Replica Set.
</details>

---

## [OK] AUTO-ÉVALUATION PARTIE 1

**Avant de passer à la Partie 2, assure-toi de pouvoir répondre OUI à :**

- [ ] Je comprends pourquoi 5 membres offrent plus de résilience que 3
- [ ] Je sais calculer la majorité nécessaire (quorum)
- [ ] Je comprends le système de priorités
- [ ] Je sais pourquoi Machine 5 est DELAYED et Hidden
- [ ] J'ai configuré les 5 machines sur le même réseau
- [ ] J'ai assigné des IPs statiques à chaque machine
- [ ] J'ai testé la connectivité entre TOUTES les machines (ping)
- [ ] Je comprends la distribution géographique simulée

**Si tu as coché toutes les cases, tu es prêt pour la PARTIE 2 ! [BRAVO]**

---

## [LISTE] RÉCAPITULATIF PARTIE 1

**Architecture définie :**
- [OK] 5 machines sur réseau 192.168.1.0/24
- [OK] IPs statiques : .10, .20, .30, .40, .50
- [OK] 1 PRIMARY (Machine 1, Priority 5)
- [OK] 3 SECONDARY normaux (Machines 2, 3, 4)
- [OK] 1 SECONDARY DELAYED 1h (Machine 5, Hidden)
- [OK] Tolérance de panne : 2 membres
- [OK] Quorum : 3/5

**Prochaine étape :**
Installation de MongoDB sur les 5 machines !

**[RAPIDE] Prêt ? Passons à la PARTIE 2 ! ->**

# [COURS] GUIDE MONGODB REPLICA SET - 5 MACHINES - PARTIE 2

## [PACKAGE] INSTALLATION DE MONGODB SUR LES 5 MACHINES

### [OBJECTIF] OBJECTIF DE CETTE PARTIE

À la fin de cette partie, tu auras :
[OK] MongoDB installé sur les 5 machines
[OK] Toutes les instances configurées mais PAS ENCORE en Replica Set
[OK] Vérifié que tout fonctionne individuellement
[OK] Pare-feu configuré sur chaque machine

**[ATTENTION] IMPORTANT : On installe d'abord, on configure le Replica Set dans la Partie 3 !**

---

## [ECRAN] PRÉREQUIS

**Avant de commencer, vérifie que tu as :**

[OK] **5 machines connectées sur le même réseau**
   - Machine 1 : 192.168.1.10
   - Machine 2 : 192.168.1.20
   - Machine 3 : 192.168.1.30
   - Machine 4 : 192.168.1.40
   - Machine 5 : 192.168.1.50

[OK] **IPs statiques configurées sur chaque machine**

[OK] **Test ping fonctionnel entre TOUTES les machines**
   ```bash
   # Depuis n'importe quelle machine
   ping 192.168.1.10
   ping 192.168.1.20
   ping 192.168.1.30
   ping 192.168.1.40
   ping 192.168.1.50
   # Tous doivent répondre [OK]
   ```

[OK] **Ressources minimales par machine :**
   - CPU : 2 cœurs
   - RAM : 4 GB (8 GB recommandé pour production)
   - Disque : 20 GB libres (SSD recommandé)

[OK] **Accès administrateur sur chaque machine**

---

## [LISTE] PLAN D'INSTALLATION

**Nous allons installer MongoDB sur les 5 machines dans cet ordre :**

```
1. Machine 1 (PRIMARY futur)     <- Commence par celle-ci
2. Machine 2 (SECONDARY)         <- Ensuite
3. Machine 3 (SECONDARY)         <- Puis
4. Machine 4 (SECONDARY)         <- Puis
5. Machine 5 (SECONDARY DELAYED) <- En dernier

[TEMPS] Durée totale estimée : 50-75 minutes (10-15 min par machine)
```

**[IDEE] ASTUCE : Si tu as plusieurs écrans ou plusieurs personnes, tu peux installer en parallèle !**

---

## [LINUX] INSTALLATION SUR UBUNTU/DEBIAN (LES 5 MACHINES)

### [CLE] Étape 1 : Importer la clé GPG (sur CHAQUE machine)

**Ouvrir un terminal sur Machine 1 :**

```bash
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
   sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg \
   --dearmor
```

**Vérifier que la clé est importée :**
```bash
ls -lh /usr/share/keyrings/mongodb-server-7.0.gpg
```

**Résultat attendu :**
```
-rw-r--r-- 1 root root 2.7K Dec 16 10:00 /usr/share/keyrings/mongodb-server-7.0.gpg
[OK] Clé importée
```

**RÉPÉTER cette étape sur Machines 2, 3, 4, 5**

---

### [PACKAGE] Étape 2 : Ajouter le dépôt MongoDB (sur CHAQUE machine)

**Identifier ta version Ubuntu/Debian :**

```bash
lsb_release -a
```

**Sortie exemple :**
```
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.3 LTS
Release:        22.04
Codename:       jammy
             ^^^^^^^
      Utilise la commande correspondante ci-dessous
```

---

**Pour Ubuntu 22.04 (Jammy) :**
```bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Pour Ubuntu 20.04 (Focal) :**
```bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Pour Debian 12 (Bookworm) :**
```bash
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/7.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Pour Debian 11 (Bullseye) :**
```bash
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/debian bullseye/mongodb-org/7.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**Vérifier :**
```bash
cat /etc/apt/sources.list.d/mongodb-org-7.0.list
```

**RÉPÉTER sur les 5 machines**

---

### [SYNC] Étape 3 : Mettre à jour les paquets (sur CHAQUE machine)

```bash
sudo apt update
```

**Résultat attendu (extrait) :**
```
Get:3 https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 InRelease [4,783 B]
Get:4 https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0/multiverse amd64 Packages [23.4 kB]
[OK] Le dépôt MongoDB est détecté
```

**RÉPÉTER sur les 5 machines**

---

### [ENTREE] Étape 4 : Installer MongoDB (sur CHAQUE machine)

```bash
sudo apt install -y mongodb-org
```

**[TEMPS] Durée : 2-4 minutes par machine**

**Résultat attendu :**
```
Setting up mongodb-org-server (7.0.5) ...
Created symlink /etc/systemd/system/multi-user.target.wants/mongod.service
[...]
Setting up mongodb-org (7.0.5) ...
[OK] Installation réussie
```

**RÉPÉTER sur les 5 machines**

---

### [OK] Étape 5 : Vérifier l'installation (sur CHAQUE machine)

**1. Vérifier la version :**

```bash
mongod --version
```

**Résultat attendu :**
```
db version v7.0.5
Build Info: {
    "version": "7.0.5",
    [...]
}
[OK] MongoDB 7.0.5 installé
```

**2. Vérifier le shell :**

```bash
mongosh --version
```

**Résultat attendu :**
```
1.10.6
[OK] Shell installé
```

**3. Vérifier que le service existe (mais pas démarré) :**

```bash
sudo systemctl status mongod
```

**Résultat attendu :**
```
[BLACK_CIRCLE] mongod.service - MongoDB Database Server
     Loaded: loaded (/lib/systemd/system/mongod.service; enabled)
     Active: inactive (dead)
             ^^^^^^^^^
        Pas encore démarré - NORMAL [OK]
```

**RÉPÉTER les vérifications sur les 5 machines**

---

### [HOT] Étape 6 : Configurer le pare-feu (sur CHAQUE machine)

**[ATTENTION] TRÈS IMPORTANT : NE PAS désactiver le pare-feu ! Voir l'ANNEXE sur les pare-feu.**

**Sur Ubuntu/Debian avec UFW :**

```bash
# Installer UFW si pas déjà installé
sudo apt install ufw -y

# Activer UFW
sudo ufw --force enable

# Autoriser SSH (IMPORTANT : sinon tu te lock dehors !)
sudo ufw allow 22/tcp

# Autoriser MongoDB (port 27017)
sudo ufw allow 27017/tcp

# Vérifier les règles
sudo ufw status numbered
```

**Résultat attendu :**
```
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere
[ 2] 27017/tcp                  ALLOW IN    Anywhere
[OK] Ports ouverts correctement
```

**RÉPÉTER sur les 5 machines**

---

## [WINDOW] INSTALLATION SUR WINDOWS (SI TU UTILISES WINDOWS)

### [ENTREE] Étape 1 : Télécharger MongoDB (sur chaque machine Windows)

**1. Aller sur :**
```
https://www.mongodb.com/try/download/community
```

**2. Sélectionner :**
```
Version: 7.0.5 (Current)
Platform: Windows
Package: MSI
```

**3. Télécharger le fichier :** `mongodb-windows-x86_64-7.0.5-signed.msi`

---

### [OUTIL] Étape 2 : Installer MongoDB (sur chaque machine)

**1. Double-cliquer sur le .msi**

**2. UAC -> Cliquer "Yes"**

**3. Écran de bienvenue -> "Next"**

**4. Licence -> Cocher "I accept" -> "Next"**

**5. Setup Type -> Choisir "Complete" -> "Next"**

**6. Service Configuration :**
```
[x] Install MongoDB as a Service
Service Name: MongoDB
Data Directory: C:\Program Files\MongoDB\Server\7.0\data\
Log Directory: C:\Program Files\MongoDB\Server\7.0\log\
[ ] Run service as Network Service user (laisser décoché)
```

**7. MongoDB Compass -> Cocher si tu veux une GUI -> "Next"**

**8. "Install" -> Attendre 5-10 minutes**

**9. "Finish"**

---

### [STOP] Étape 3 : ARRÊTER le service (IMPORTANT)

**MongoDB démarre automatiquement en standalone. Il faut l'arrêter AVANT de configurer le Replica Set !**

**PowerShell en Administrateur :**

```powershell
# Arrêter le service
Stop-Service -Name MongoDB

# Le passer en démarrage manuel
Set-Service -Name MongoDB -StartupType Manual

# Vérifier
Get-Service -Name MongoDB
```

**Résultat attendu :**
```
Status   Name               DisplayName
------   ----               -----------
Stopped  MongoDB            MongoDB Server (MongoDB)
[OK] Service arrêté
```

**RÉPÉTER sur toutes les machines Windows**

---

### [HOT] Étape 4 : Configurer le pare-feu Windows

**PowerShell en Administrateur :**

```powershell
New-NetFirewallRule -DisplayName "MongoDB Replica Set" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 27017 `
  -Action Allow `
  -Profile Domain,Private,Public
```

**Vérifier :**
```powershell
Get-NetFirewallRule -DisplayName "MongoDB Replica Set"
```

**Résultat attendu :**
```
Name                  : {GUID}
DisplayName           : MongoDB Replica Set
Enabled               : True
Direction             : Inbound
Action                : Allow
[OK] Règle créée
```

**RÉPÉTER sur toutes les machines Windows**

---

## [ITEM] INSTALLATION SUR macOS (SI TU UTILISES macOS)

### [BEER_MUG] Étape 1 : Installer Homebrew (si nécessaire)

**Vérifier si Homebrew est installé :**
```bash
brew --version
```

**Si pas installé :**
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

---

### [ENTREE] Étape 2 : Installer MongoDB

```bash
# Ajouter le tap MongoDB
brew tap mongodb/brew

# Installer MongoDB
brew install mongodb-community@7.0
```

**[TEMPS] Durée : 3-5 minutes**

---

### [STOP] Étape 3 : NE PAS démarrer le service

```bash
# S'assurer que le service n'est pas démarré
brew services stop mongodb-community@7.0

# Vérifier
brew services list
```

**Résultat attendu :**
```
Name                  Status  User
mongodb-community@7.0 stopped
[OK] Service arrêté
```

**RÉPÉTER sur toutes les machines macOS**

---

## [TEST] TEST DE CONNECTIVITÉ FINALE

**Avant de passer à la configuration, vérifions que TOUTES les machines peuvent communiquer sur le port MongoDB (27017).**

### Script de test automatique (Linux/Mac)

**Créer ce script sur Machine 1 :**

```bash
nano test-connectivity-5-machines.sh
```

**Contenu :**

```bash
#!/bin/bash
# ═══════════════════════════════════════════════════════════════
# TEST DE CONNECTIVITÉ - REPLICA SET 5 MACHINES
# ═══════════════════════════════════════════════════════════════

echo "[RECHERCHE] Test de connectivité du Replica Set à 5 membres"
echo "═══════════════════════════════════════════════════════════"
echo ""

# Configuration
MACHINES=(
    "192.168.1.10"
    "192.168.1.20"
    "192.168.1.30"
    "192.168.1.40"
    "192.168.1.50"
)

NAMES=(
    "Machine 1 (PRIMARY futur)"
    "Machine 2 (SECONDARY 1)"
    "Machine 3 (SECONDARY 2)"
    "Machine 4 (SECONDARY 3)"
    "Machine 5 (SECONDARY DELAYED)"
)

# Couleurs
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Test 1 : PING
echo "[RESEAU] TEST 1 : Connectivité réseau (PING)"
echo "───────────────────────────────────────────────────────────"

PING_FAILED=0
for i in "${!MACHINES[@]}"; do
    IP="${MACHINES[$i]}"
    NAME="${NAMES[$i]}"
    
    printf "Testing %-35s " "${NAME} (${IP})"
    
    if ping -c 2 -W 2 "$IP" > /dev/null 2>&1; then
        echo -e "${GREEN}[OK] Reachable${NC}"
    else
        echo -e "${RED}[X] NOT reachable${NC}"
        PING_FAILED=$((PING_FAILED + 1))
    fi
done

echo ""

if [ $PING_FAILED -eq 0 ]; then
    echo -e "${GREEN}[OK] Tous les membres sont joignables${NC}"
else
    echo -e "${RED}[X] $PING_FAILED membre(s) non joignable(s)${NC}"
    echo -e "${YELLOW}[ATTENTION]  Corrige la connectivité réseau avant de continuer${NC}"
    exit 1
fi

echo ""
echo "═══════════════════════════════════════════════════════════"
echo ""

# Test 2 : PORT 27017
echo "[PLUGIN] TEST 2 : Port MongoDB (27017)"
echo "───────────────────────────────────────────────────────────"

PORT_FAILED=0
for i in "${!MACHINES[@]}"; do
    IP="${MACHINES[$i]}"
    NAME="${NAMES[$i]}"
    
    printf "Testing %-35s " "${NAME} (${IP}:27017)"
    
    if timeout 2 bash -c "</dev/tcp/$IP/27017" 2>/dev/null; then
        echo -e "${GREEN}[OK] Port ouvert${NC}"
    else
        echo -e "${YELLOW}[ATTENTION]  Port fermé ou MongoDB pas démarré${NC}"
        PORT_FAILED=$((PORT_FAILED + 1))
    fi
done

echo ""

if [ $PORT_FAILED -eq 0 ]; then
    echo -e "${GREEN}[OK] Tous les ports sont ouverts${NC}"
elif [ $PORT_FAILED -eq 5 ]; then
    echo -e "${YELLOW}[ATTENTION]  Tous les ports fermés - NORMAL si MongoDB pas encore démarré${NC}"
else
    echo -e "${YELLOW}[ATTENTION]  $PORT_FAILED port(s) fermé(s) - Vérifie les pare-feu${NC}"
fi

echo ""
echo "═══════════════════════════════════════════════════════════"
echo ""

# Test 3 : LATENCE
echo "[RAPIDE] TEST 3 : Latence réseau"
echo "───────────────────────────────────────────────────────────"

LATENCY_WARNING=0
for i in "${!MACHINES[@]}"; do
    IP="${MACHINES[$i]}"
    NAME="${NAMES[$i]}"
    
    printf "Testing %-35s " "${NAME} (${IP})"
    
    # Ping et extraire le temps moyen
    LATENCY=$(ping -c 5 -W 2 "$IP" 2>/dev/null | tail -1 | awk -F '/' '{print $5}' | cut -d '.' -f1)
    
    if [ -z "$LATENCY" ]; then
        echo -e "${RED}[X] Erreur mesure${NC}"
        LATENCY_WARNING=$((LATENCY_WARNING + 1))
    elif [ "$LATENCY" -lt 10 ]; then
        echo -e "${GREEN}[OK] ${LATENCY}ms (excellent)${NC}"
    elif [ "$LATENCY" -lt 50 ]; then
        echo -e "${GREEN}[OK] ${LATENCY}ms (bon)${NC}"
    elif [ "$LATENCY" -lt 100 ]; then
        echo -e "${YELLOW}[ATTENTION]  ${LATENCY}ms (acceptable)${NC}"
        LATENCY_WARNING=$((LATENCY_WARNING + 1))
    else
        echo -e "${RED}[X] ${LATENCY}ms (trop élevé)${NC}"
        LATENCY_WARNING=$((LATENCY_WARNING + 1))
    fi
done

echo ""

if [ $LATENCY_WARNING -eq 0 ]; then
    echo -e "${GREEN}[OK] Latence réseau optimale${NC}"
else
    echo -e "${YELLOW}[ATTENTION]  Latence élevée détectée sur $LATENCY_WARNING membre(s)${NC}"
    echo -e "${YELLOW}   MongoDB fonctionne mieux avec latence < 50ms${NC}"
fi

echo ""
echo "═══════════════════════════════════════════════════════════"
echo ""

# Résumé
echo "[GRAPHIQUE] RÉSUMÉ DES TESTS"
echo "───────────────────────────────────────────────────────────"
echo "Total membres testés : ${#MACHINES[@]}"
echo "Membres joignables   : $((${#MACHINES[@]} - PING_FAILED))"
echo "Ports ouverts        : $((${#MACHINES[@]} - PORT_FAILED))"
echo "Latence bonne        : $((${#MACHINES[@]} - LATENCY_WARNING))"
echo ""

if [ $PING_FAILED -eq 0 ] && [ $LATENCY_WARNING -eq 0 ]; then
    echo -e "${GREEN}[OK] Tous les tests sont OK ! Prêt pour la configuration du Replica Set.${NC}"
    exit 0
elif [ $PING_FAILED -gt 0 ]; then
    echo -e "${RED}[X] Problèmes de connectivité réseau. Corrige avant de continuer.${NC}"
    exit 1
else
    echo -e "${YELLOW}[ATTENTION]  Connectivité OK mais optimisations possibles.${NC}"
    echo -e "${YELLOW}   Tu peux continuer mais surveille les performances.${NC}"
    exit 0
fi
```

**Rendre exécutable et lancer :**

```bash
chmod +x test-connectivity-5-machines.sh
./test-connectivity-5-machines.sh
```

**Résultat attendu :**

```
[RECHERCHE] Test de connectivité du Replica Set à 5 membres
═══════════════════════════════════════════════════════════

[RESEAU] TEST 1 : Connectivité réseau (PING)
───────────────────────────────────────────────────────────
Testing Machine 1 (PRIMARY futur) (192.168.1.10)      [OK] Reachable
Testing Machine 2 (SECONDARY 1) (192.168.1.20)        [OK] Reachable
Testing Machine 3 (SECONDARY 2) (192.168.1.30)        [OK] Reachable
Testing Machine 4 (SECONDARY 3) (192.168.1.40)        [OK] Reachable
Testing Machine 5 (SECONDARY DELAYED) (192.168.1.50)  [OK] Reachable

[OK] Tous les membres sont joignables

═══════════════════════════════════════════════════════════

[PLUGIN] TEST 2 : Port MongoDB (27017)
───────────────────────────────────────────────────────────
Testing Machine 1 (PRIMARY futur) (192.168.1.10:27017)     [ATTENTION]  Port fermé ou MongoDB pas démarré
Testing Machine 2 (SECONDARY 1) (192.168.1.20:27017)       [ATTENTION]  Port fermé ou MongoDB pas démarré
Testing Machine 3 (SECONDARY 2) (192.168.1.30:27017)       [ATTENTION]  Port fermé ou MongoDB pas démarré
Testing Machine 4 (SECONDARY 3) (192.168.1.40:27017)       [ATTENTION]  Port fermé ou MongoDB pas démarré
Testing Machine 5 (SECONDARY DELAYED) (192.168.1.50:27017) [ATTENTION]  Port fermé ou MongoDB pas démarré

[ATTENTION]  Tous les ports fermés - NORMAL si MongoDB pas encore démarré

═══════════════════════════════════════════════════════════

[RAPIDE] TEST 3 : Latence réseau
───────────────────────────────────────────────────────────
Testing Machine 1 (PRIMARY futur) (192.168.1.10)      [OK] 1ms (excellent)
Testing Machine 2 (SECONDARY 1) (192.168.1.20)        [OK] 2ms (excellent)
Testing Machine 3 (SECONDARY 2) (192.168.1.30)        [OK] 3ms (excellent)
Testing Machine 4 (SECONDARY 3) (192.168.1.40)        [OK] 2ms (excellent)
Testing Machine 5 (SECONDARY DELAYED) (192.168.1.50)  [OK] 4ms (excellent)

[OK] Latence réseau optimale

═══════════════════════════════════════════════════════════

[GRAPHIQUE] RÉSUMÉ DES TESTS
───────────────────────────────────────────────────────────
Total membres testés : 5
Membres joignables   : 5
Ports ouverts        : 0
Latence bonne        : 5

[OK] Tous les tests sont OK ! Prêt pour la configuration du Replica Set.
```

---

### Test Windows (PowerShell)

**Sur une machine Windows, créer ce script :**

```powershell
# test-connectivity-5-machines.ps1
# ═══════════════════════════════════════════════════════════════
# TEST DE CONNECTIVITÉ - REPLICA SET 5 MACHINES (Windows)
# ═══════════════════════════════════════════════════════════════

Write-Host "[RECHERCHE] Test de connectivité du Replica Set à 5 membres" -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host ""

# Configuration
$machines = @(
    @{ IP = "192.168.1.10"; Name = "Machine 1 (PRIMARY futur)" },
    @{ IP = "192.168.1.20"; Name = "Machine 2 (SECONDARY 1)" },
    @{ IP = "192.168.1.30"; Name = "Machine 3 (SECONDARY 2)" },
    @{ IP = "192.168.1.40"; Name = "Machine 4 (SECONDARY 3)" },
    @{ IP = "192.168.1.50"; Name = "Machine 5 (SECONDARY DELAYED)" }
)

# Test 1 : PING
Write-Host "[RESEAU] TEST 1 : Connectivité réseau (PING)" -ForegroundColor Yellow
Write-Host "───────────────────────────────────────────────────────────"

$pingFailed = 0
foreach ($machine in $machines) {
    $ip = $machine.IP
    $name = $machine.Name
    
    Write-Host ("Testing {0,-40}" -f "$name ($ip)") -NoNewline
    
    if (Test-Connection -ComputerName $ip -Count 2 -Quiet) {
        Write-Host " [OK] Reachable" -ForegroundColor Green
    } else {
        Write-Host " [X] NOT reachable" -ForegroundColor Red
        $pingFailed++
    }
}

Write-Host ""

if ($pingFailed -eq 0) {
    Write-Host "[OK] Tous les membres sont joignables" -ForegroundColor Green
} else {
    Write-Host "[X] $pingFailed membre(s) non joignable(s)" -ForegroundColor Red
    Write-Host "[ATTENTION]  Corrige la connectivité réseau avant de continuer" -ForegroundColor Yellow
    exit 1
}

Write-Host ""
Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host ""

# Test 2 : PORT 27017
Write-Host "[PLUGIN] TEST 2 : Port MongoDB (27017)" -ForegroundColor Yellow
Write-Host "───────────────────────────────────────────────────────────"

$portFailed = 0
foreach ($machine in $machines) {
    $ip = $machine.IP
    $name = $machine.Name
    
    Write-Host ("Testing {0,-40}" -f "$name ($ip:27017)") -NoNewline
    
    $result = Test-NetConnection -ComputerName $ip -Port 27017 -WarningAction SilentlyContinue
    
    if ($result.TcpTestSucceeded) {
        Write-Host " [OK] Port ouvert" -ForegroundColor Green
    } else {
        Write-Host " [ATTENTION]  Port fermé ou MongoDB pas démarré" -ForegroundColor Yellow
        $portFailed++
    }
}

Write-Host ""

if ($portFailed -eq 0) {
    Write-Host "[OK] Tous les ports sont ouverts" -ForegroundColor Green
} elseif ($portFailed -eq 5) {
    Write-Host "[ATTENTION]  Tous les ports fermés - NORMAL si MongoDB pas encore démarré" -ForegroundColor Yellow
} else {
    Write-Host "[ATTENTION]  $portFailed port(s) fermé(s) - Vérifie les pare-feu" -ForegroundColor Yellow
}

Write-Host ""
Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host ""

# Résumé
Write-Host "[GRAPHIQUE] RÉSUMÉ DES TESTS" -ForegroundColor Yellow
Write-Host "───────────────────────────────────────────────────────────"
Write-Host "Total membres testés : $($machines.Count)"
Write-Host "Membres joignables   : $($machines.Count - $pingFailed)"
Write-Host "Ports ouverts        : $($machines.Count - $portFailed)"
Write-Host ""

if ($pingFailed -eq 0) {
    Write-Host "[OK] Tous les tests sont OK ! Prêt pour la configuration du Replica Set." -ForegroundColor Green
    exit 0
} else {
    Write-Host "[X] Problèmes de connectivité réseau. Corrige avant de continuer." -ForegroundColor Red
    exit 1
}
```

**Exécuter :**
```powershell
.\test-connectivity-5-machines.ps1
```

---

## [LISTE] RÉCAPITULATIF PARTIE 2

**Ce que tu as fait :**

[OK] **Installation complète sur 5 machines :**
   - Machine 1 : MongoDB 7.0.5 [OK]
   - Machine 2 : MongoDB 7.0.5 [OK]
   - Machine 3 : MongoDB 7.0.5 [OK]
   - Machine 4 : MongoDB 7.0.5 [OK]
   - Machine 5 : MongoDB 7.0.5 [OK]

[OK] **Services arrêtés (pas en standalone) :**
   - Toutes les machines : Service MongoDB stopped [OK]

[OK] **Pare-feu configuré sur chaque machine :**
   - Port 27017 ouvert sur les 5 machines [OK]

[OK] **Tests de connectivité :**
   - Ping entre toutes les machines : [OK]
   - IPs statiques fonctionnelles : [OK]
   - Latence réseau acceptable : [OK]

**État actuel :**
```
Machine 1 (192.168.1.10)  <-->  Machine 2 (192.168.1.20)
         v                           v
    MongoDB installé            MongoDB installé
    Service ARRÊTÉ              Service ARRÊTÉ
    Port 27017 ouvert           Port 27017 ouvert
         v                           v
         v                           v
Machine 3 (192.168.1.30)  <-->  Machine 4 (192.168.1.40)
         v                           v
    MongoDB installé            MongoDB installé
    Service ARRÊTÉ              Service ARRÊTÉ
    Port 27017 ouvert           Port 27017 ouvert
         v
         v
Machine 5 (192.168.1.50)
         v
    MongoDB installé
    Service ARRÊTÉ
    Port 27017 ouvert

       TOUS PRÊTS POUR CONFIGURATION ! [OK]
```

---

## [OBJECTIF] PROCHAINE ÉTAPE

**PARTIE 3 : Configuration du Replica Set à 5 membres**

Tu vas maintenant :
1. Modifier les fichiers de configuration sur les 5 machines
2. Démarrer MongoDB sur chaque machine
3. Initialiser le Replica Set
4. Configurer les priorités
5. Configurer le membre DELAYED
6. Vérifier la réplication

**[TEMPS] Durée estimée Partie 3 : 45-60 minutes**

**[RAPIDE] Prêt ? Passons à la PARTIE 3 ! ->**

# [COURS] GUIDE MONGODB REPLICA SET - 5 MACHINES - PARTIES 3-4

## [CONFIG] PARTIE 3 : CONFIGURATION DU REPLICA SET À 5 MEMBRES

### [OBJECTIF] OBJECTIF DE CETTE PARTIE

À la fin de cette partie, tu auras :
[OK] Configuré MongoDB sur les 5 machines
[OK] Initialisé le Replica Set à 5 membres
[OK] Vérifié que la réplication fonctionne
[OK] Configuré le membre DELAYED
[OK] Testé le failover avec 2 pannes simultanées

**[TEMPS] Durée estimée : 45-60 minutes**

---

## [OUTIL] CONFIGURATION DES FICHIERS mongod.conf

### Configuration MACHINE 1 (PRIMARY futur - Priority 5)

**Éditer le fichier de configuration :**

```bash
sudo nano /etc/mongod.conf
```

**Contenu complet :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGODB - MACHINE 1 (PRIMARY)
# ═══════════════════════════════════════════════════════════════
# IP: 192.168.1.10
# Rôle: PRIMARY (Priority 5)
# Tags: dc=paris, usage=production
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 2  # Ajuste selon ta RAM (50-80% de RAM - 1GB)
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true
  verbosity: 0
  component:
    replication:
      verbosity: 1

net:
  port: 27017
  bindIp: 0.0.0.0  # IMPORTANT : Écoute sur toutes les interfaces
  maxIncomingConnections: 2000
  compression:
    compressors: snappy,zstd

replication:
  replSetName: rs0  # Nom du Replica Set (identique sur les 5 machines)

processManagement:
  fork: false  # false pour systemd
  pidFilePath: /var/run/mongodb/mongod.pid
  timeZoneInfo: /usr/share/zoneinfo

operationProfiling:
  mode: off
  slowOpThresholdMs: 100
```

**Sauvegarder (Ctrl+O, Entrée, Ctrl+X)**

---

### Configuration MACHINE 2 (SECONDARY - Priority 3)

**Éditer :**
```bash
sudo nano /etc/mongod.conf
```

**Contenu :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGODB - MACHINE 2 (SECONDARY)
# ═══════════════════════════════════════════════════════════════
# IP: 192.168.1.20
# Rôle: SECONDARY (Priority 3 - Failover principal)
# Tags: dc=paris, usage=production
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 2
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true
  verbosity: 0
  component:
    replication:
      verbosity: 1

net:
  port: 27017
  bindIp: 0.0.0.0
  maxIncomingConnections: 2000
  compression:
    compressors: snappy,zstd

replication:
  replSetName: rs0  # MÊME NOM que Machine 1

processManagement:
  fork: false
  pidFilePath: /var/run/mongodb/mongod.pid
  timeZoneInfo: /usr/share/zoneinfo

operationProfiling:
  mode: off
  slowOpThresholdMs: 100
```

---

### Configuration MACHINE 3 (SECONDARY - Priority 2)

**Identique à Machine 2, avec commentaire :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGODB - MACHINE 3 (SECONDARY)
# ═══════════════════════════════════════════════════════════════
# IP: 192.168.1.30
# Rôle: SECONDARY (Priority 2)
# Tags: dc=lyon, usage=production
# ═══════════════════════════════════════════════════════════════

# ... (reste identique à Machine 2)
```

---

### Configuration MACHINE 4 (SECONDARY - Priority 1)

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGODB - MACHINE 4 (SECONDARY)
# ═══════════════════════════════════════════════════════════════
# IP: 192.168.1.40
# Rôle: SECONDARY (Priority 1)
# Tags: dc=lyon, usage=analytics
# ═══════════════════════════════════════════════════════════════

# ... (reste identique aux autres SECONDARY)
```

---

### Configuration MACHINE 5 (SECONDARY DELAYED - Priority 0)

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGODB - MACHINE 5 (SECONDARY DELAYED)
# ═══════════════════════════════════════════════════════════════
# IP: 192.168.1.50
# Rôle: SECONDARY DELAYED (1 heure de retard)
# Priority: 0 (ne peut JAMAIS devenir PRIMARY)
# Hidden: true (invisible aux applications)
# Tags: dc=marseille, usage=backup
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 2
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true
  verbosity: 0
  component:
    replication:
      verbosity: 1

net:
  port: 27017
  bindIp: 0.0.0.0
  maxIncomingConnections: 2000
  compression:
    compressors: snappy,zstd

replication:
  replSetName: rs0  # MÊME NOM

processManagement:
  fork: false
  pidFilePath: /var/run/mongodb/mongod.pid
  timeZoneInfo: /usr/share/zoneinfo
```

**Note : Le délai et hidden seront configurés APRÈS l'initialisation du Replica Set**

---

## [RAPIDE] DÉMARRAGE DE MONGODB SUR LES 5 MACHINES

**Ordre recommandé : Démarrer TOUTES les machines avant l'initialisation**

### Sur CHAQUE machine (1, 2, 3, 4, 5) :

**Linux :**
```bash
sudo systemctl start mongod
sudo systemctl status mongod
```

**Résultat attendu :**
```
[BLACK_CIRCLE] mongod.service - MongoDB Database Server
     Loaded: loaded
     Active: active (running) since...
[OK] MongoDB démarré
```

**Vérifier que le port écoute :**
```bash
sudo netstat -tulpn | grep 27017
```

**Résultat :**
```
tcp        0      0 0.0.0.0:27017           0.0.0.0:*               LISTEN      1234/mongod
[OK] Port 27017 en écoute sur toutes les interfaces
```

---

## [LIEN] INITIALISATION DU REPLICA SET

### Se connecter au futur PRIMARY (Machine 1)

```bash
mongosh --host 192.168.1.10 --port 27017
```

**Tu es maintenant dans le shell MongoDB :**

```
Current Mongosh Log ID: ...
Connecting to:    mongodb://192.168.1.10:27017/
Using MongoDB:    7.0.5
Using Mongosh:    1.10.6

test>
```

---

### Initialiser le Replica Set avec les 5 membres

**Copier-coller cette commande :**

```javascript
rs.initiate({
  _id: "rs0",
  version: 1,
  members: [
    {
      _id: 0,
      host: "192.168.1.10:27017",
      priority: 5,
      tags: { dc: "paris", usage: "production" }
    },
    {
      _id: 1,
      host: "192.168.1.20:27017",
      priority: 3,
      tags: { dc: "paris", usage: "production" }
    },
    {
      _id: 2,
      host: "192.168.1.30:27017",
      priority: 2,
      tags: { dc: "lyon", usage: "production" }
    },
    {
      _id: 3,
      host: "192.168.1.40:27017",
      priority: 1,
      tags: { dc: "lyon", usage: "analytics" }
    },
    {
      _id: 4,
      host: "192.168.1.50:27017",
      priority: 0,
      hidden: false,  // On cachera plus tard
      tags: { dc: "marseille", usage: "backup" }
    }
  ]
})
```

**Explication ligne par ligne :**

```javascript
rs.initiate({
  _id: "rs0",  // Nom du Replica Set (correspond à replSetName dans mongod.conf)
  version: 1,  // Version de la configuration
  
  members: [
    {
      _id: 0,                            // ID unique du membre (0-4)
      host: "192.168.1.10:27017",        // IP:Port
      priority: 5,                       // Priorité la plus haute
      tags: { dc: "paris", usage: "production" }  // Tags pour routing
    },
    // Machine 2 : Priority 3 (deuxième choix pour PRIMARY)
    // Machine 3 : Priority 2 (troisième choix)
    // Machine 4 : Priority 1 (quatrième choix)
    // Machine 5 : Priority 0 (ne peut JAMAIS devenir PRIMARY)
  ]
})
```

**Résultat attendu :**

```javascript
{
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1702730000, i: 1 }),
    signature: { ... }
  },
  operationTime: Timestamp({ t: 1702730000, i: 1 })
}
```

**[OK] "ok: 1" = Initialisation réussie ! [BRAVO]**

**Attendre 10-20 secondes pour l'élection...**

**Le prompt va changer :**
```
test> 
rs0 [direct: primary] test>
     ^^^             ^^^^^^^^
  Replica Set       PRIMARY élu !
```

---

## [RECHERCHE] VÉRIFICATION DU STATUT

### Commande rs.status()

```javascript
rs.status()
```

**Résultat attendu (extrait simplifié) :**

```javascript
{
  set: 'rs0',
  date: ISODate('2024-12-16T10:00:00.000Z'),
  myState: 1,  // 1 = PRIMARY
  members: [
    {
      _id: 0,
      name: '192.168.1.10:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 234,
      optime: { ts: Timestamp(...), t: Long("1") },
      ...
    },
    {
      _id: 1,
      name: '192.168.1.20:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 228,
      syncSourceHost: '192.168.1.10:27017',
      ...
    },
    {
      _id: 2,
      name: '192.168.1.30:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      ...
    },
    {
      _id: 3,
      name: '192.168.1.40:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      ...
    },
    {
      _id: 4,
      name: '192.168.1.50:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      ...
    }
  ],
  ok: 1
}
```

**Points importants à vérifier :**

| Champ | Valeur attendue | Signification |
|-------|-----------------|---------------|
| **health** | 1 | Membre en bonne santé |
| **stateStr** | PRIMARY ou SECONDARY | Rôle actuel |
| **syncSourceHost** | IP d'un autre membre | Source de réplication |

**Commande simplifiée pour affichage :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(10)} | Health: ${m.health} | Priority: ${rs.conf().members[m._id].priority}`)
})
```

**Résultat :**

```
192.168.1.10:27017        | PRIMARY    | Health: 1 | Priority: 5
192.168.1.20:27017        | SECONDARY  | Health: 1 | Priority: 3
192.168.1.30:27017        | SECONDARY  | Health: 1 | Priority: 2
192.168.1.40:27017        | SECONDARY  | Health: 1 | Priority: 1
192.168.1.50:27017        | SECONDARY  | Health: 1 | Priority: 0

[OK] Tous les membres sont opérationnels !
```

---

## [ALARM_CLOCK] CONFIGURATION DU MEMBRE DELAYED (Machine 5)

**Pourquoi MAINTENANT et pas au début ?**

```
Le membre DELAYED doit d'abord se synchroniser avec le PRIMARY.
Une fois synchronisé, on active le délai de 1 heure.

Analogie : On laisse l'assistant tout noter, PUIS on lui dit
          "maintenant, attends 1h avant d'appliquer les changements"
```

### Configurer le délai

**Dans le shell MongoDB (toujours sur PRIMARY) :**

```javascript
// Récupérer la configuration actuelle
cfg = rs.conf()

// Modifier le membre 4 (Machine 5)
cfg.members[4].hidden = true        // Le rendre invisible
cfg.members[4].slaveDelay = 3600    // 3600 secondes = 1 heure
cfg.members[4].priority = 0         // Déjà à 0, on confirme

// Appliquer la nouvelle configuration
rs.reconfig(cfg)
```

**Résultat :**

```javascript
{
  ok: 1,
  '$clusterTime': { ... },
  operationTime: Timestamp(...)
}
```

**Vérifier :**

```javascript
rs.conf().members[4]
```

**Résultat attendu :**

```javascript
{
  _id: 4,
  host: '192.168.1.50:27017',
  arbiterOnly: false,
  buildIndexes: true,
  hidden: true,           // [OK] Caché
  priority: 0,            // [OK] Ne peut pas devenir PRIMARY
  tags: { dc: 'marseille', usage: 'backup' },
  secondaryDelaySecs: Long("3600"),  // [OK] Délai de 1h
  votes: 1
}
```

**[OK] Machine 5 est maintenant DELAYED de 1 heure !**

**Vérification du statut :**

```javascript
rs.status().members[4]
```

**Tu devrais voir :**

```javascript
{
  _id: 4,
  name: '192.168.1.50:27017',
  health: 1,
  state: 2,
  stateStr: 'SECONDARY',
  ...
  optimeDate: ISODate('2024-12-16T09:00:00.000Z'),  // 1h de retard par rapport aux autres
}
```

---

## [TEST] TESTS DE VALIDATION

### Test 1 : Insertion de données sur le PRIMARY

**Se connecter au PRIMARY :**

```javascript
// Déjà connecté depuis l'initialisation
use testdb

// Insérer des données de test
db.users.insertMany([
  { name: "Alice", email: "alice@example.com", age: 25, city: "Paris" },
  { name: "Bob", email: "bob@example.com", age: 30, city: "Lyon" },
  { name: "Charlie", email: "charlie@example.com", age: 28, city: "Marseille" },
  { name: "Diana", email: "diana@example.com", age: 26, city: "Paris" },
  { name: "Eve", email: "eve@example.com", age: 32, city: "Lyon" }
])
```

**Résultat :**

```javascript
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('...'),
    '1': ObjectId('...'),
    '2': ObjectId('...'),
    '3': ObjectId('...'),
    '4': ObjectId('...')
  }
}
[OK] 5 documents insérés
```

---

### Test 2 : Vérifier la réplication sur TOUS les SECONDARY

**Se connecter à Machine 2 (SECONDARY) :**

```bash
mongosh --host 192.168.1.20 --port 27017
```

**Par défaut, lecture interdite sur SECONDARY :**

```javascript
use testdb
db.users.find()
```

**Résultat :**

```
MongoServerError: not primary and secondaryOk=false - read queries are not allowed on secondary
```

**C'est normal ! Autoriser les lectures :**

```javascript
db.getMongo().setReadPref('secondary')
// Ou
rs.secondaryOk()

// Maintenant lire
db.users.find().pretty()
```

**Résultat :**

```javascript
[
  {
    _id: ObjectId('...'),
    name: 'Alice',
    email: 'alice@example.com',
    age: 25,
    city: 'Paris'
  },
  // ... 4 autres documents
]
[OK] Les données sont répliquées sur Machine 2 !
```

**Répéter ce test sur Machines 3, 4 :**

```bash
# Machine 3
mongosh --host 192.168.1.30 --port 27017
rs.secondaryOk()
use testdb
db.users.count()  # Devrait afficher 5

# Machine 4
mongosh --host 192.168.1.40 --port 27017
rs.secondaryOk()
use testdb
db.users.count()  # Devrait afficher 5
```

**Machine 5 (DELAYED) :**

```bash
mongosh --host 192.168.1.50 --port 27017
rs.secondaryOk()
use testdb
db.users.count()
```

**[ATTENTION] Si tu viens d'initialiser, Machine 5 peut déjà avoir les données !**

```
Pourquoi ?
-> Le délai de 1h s'applique aux NOUVELLES opérations
-> Les données insérées avant la configuration du délai sont déjà là

Pour tester le délai :
-> Attendre que Machine 5 soit à jour
-> Insérer de NOUVELLES données
-> Vérifier que Machine 5 ne les a pas immédiatement
```

---

### Test 3 : Vérifier le délai de réplication (Machine 5)

**Sur PRIMARY :**

```javascript
use testdb

// Insérer un nouveau document MAINTENANT
db.users.insertOne({
  name: "Frank",
  email: "frank@example.com",
  inserted_at: new Date(),
  test: "delayed_replication"
})
```

**Noter l'heure actuelle :** Par exemple 10:30:00

**Sur Machine 5 (DELAYED) :**

```javascript
use testdb
db.users.find({ name: "Frank" })
```

**Résultat IMMÉDIAT :**
```
// Rien (vide)
[OK] Le document n'est pas encore là (normal, délai de 1h)
```

**Attendre 1 heure (ou plus tard) et revérifier :**

```javascript
db.users.find({ name: "Frank" })
```

**Résultat après 1h :**
```javascript
[
  {
    _id: ObjectId('...'),
    name: 'Frank',
    email: 'frank@example.com',
    inserted_at: ISODate('2024-12-16T10:30:00.000Z'),
    test: 'delayed_replication'
  }
]
[OK] Le document apparaît 1h après l'insertion !
```

---

### Test 4 : Failover avec 1 panne

**Arrêter le PRIMARY actuel (Machine 1) :**

```bash
# Sur Machine 1
sudo systemctl stop mongod
```

**Sur une autre machine (ex: Machine 2), observer l'élection :**

```bash
mongosh --host 192.168.1.20 --port 27017
```

**Attendre 10-30 secondes...**

**Vérifier :**

```javascript
rs.isMaster().ismaster
```

**Résultat après élection :**
```javascript
true  // Machine 2 est devenue PRIMARY
```

**Vérifier le statut complet :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(15)} | Health: ${m.health}`)
})
```

**Résultat :**
```
192.168.1.10:27017        | (not reachable) | Health: 0   <- Arrêté
192.168.1.20:27017        | PRIMARY         | Health: 1   <- Nouveau PRIMARY
192.168.1.30:27017        | SECONDARY       | Health: 1
192.168.1.40:27017        | SECONDARY       | Health: 1
192.168.1.50:27017        | SECONDARY       | Health: 1

Quorum : 4/5 actifs (4 > 3) [OK]
Système fonctionne normalement !
```

**Redémarrer Machine 1 :**

```bash
sudo systemctl start mongod
```

**Observer (après 10-20 secondes) :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(15)} | Health: ${m.health}`)
})
```

**Possibilité 1 : Machine 1 redevient PRIMARY (priorité 5)**
```
192.168.1.10:27017        | PRIMARY         | Health: 1
192.168.1.20:27017        | SECONDARY       | Health: 1
...
```

**Possibilité 2 : Machine 2 reste PRIMARY**
```
192.168.1.10:27017        | SECONDARY       | Health: 1
192.168.1.20:27017        | PRIMARY         | Health: 1
...
```

**Les deux sont corrects ! MongoDB évite les basculements inutiles.**

---

### Test 5 : Failover avec 2 pannes SIMULTANÉES

**[OBJECTIF] C'est le test ultime : 2 pannes en même temps !**

**Arrêter 2 membres (ex: Machines 1 et 3) :**

```bash
# Sur Machine 1
sudo systemctl stop mongod

# Sur Machine 3
sudo systemctl stop mongod
```

**Vérifier depuis Machine 2 :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(15)} | Health: ${m.health}`)
})
```

**Résultat :**
```
192.168.1.10:27017        | (not reachable) | Health: 0   <- Panne 1
192.168.1.20:27017        | PRIMARY         | Health: 1   <- Toujours PRIMARY
192.168.1.30:27017        | (not reachable) | Health: 0   <- Panne 2
192.168.1.40:27017        | SECONDARY       | Health: 1
192.168.1.50:27017        | SECONDARY       | Health: 1

Membres actifs : 3/5
Majorité : 3/5 [OK]
Quorum atteint !
Système fonctionne ENCORE ! [BRAVO]
```

**Tester une écriture :**

```javascript
use testdb
db.users.insertOne({
  name: "Grace",
  email: "grace@example.com",
  test: "deux_pannes_simultanées"
})
```

**Résultat :**
```javascript
{
  acknowledged: true,
  insertedId: ObjectId('...')
}
[OK] L'écriture fonctionne malgré 2 pannes ! [RAPIDE]
```

---

### Test 6 : Limite - 3 pannes (READ-ONLY)

**[ATTENTION] Pour démonstration uniquement !**

**Arrêter un 3ème membre (ex: Machine 4) :**

```bash
# Sur Machine 4
sudo systemctl stop mongod
```

**Vérifier depuis Machine 2 :**

```javascript
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(15)} | Health: ${m.health}`)
})
```

**Résultat :**
```
192.168.1.10:27017        | (not reachable) | Health: 0
192.168.1.20:27017        | SECONDARY       | Health: 1   <- Plus PRIMARY !
192.168.1.30:27017        | (not reachable) | Health: 0
192.168.1.40:27017        | (not reachable) | Health: 0
192.168.1.50:27017        | SECONDARY       | Health: 1

Membres actifs : 2/5
Majorité requise : 3/5
2 < 3 [X]
Pas de quorum -> READ-ONLY
```

**Tester une écriture :**

```javascript
db.users.insertOne({ test: "va_échouer" })
```

**Résultat :**
```
MongoServerError: not master
[X] Écritures impossibles sans quorum
```

**Les lectures fonctionnent encore :**

```javascript
rs.secondaryOk()
db.users.count()
```

**Résultat :**
```
6  // Ou le nombre de documents présents
[OK] Lectures toujours possibles
```

**Redémarrer les machines pour retrouver le quorum :**

```bash
# Machines 1, 3, 4
sudo systemctl start mongod
```

---

## [GRAPHIQUE] COMMANDES UTILES REPLICA SET 5 MEMBRES

### Statut et monitoring

```javascript
// Statut complet
rs.status()

// Configuration
rs.conf()

// PRIMARY actuel
db.hello().primary

// Liste des SECONDARY
rs.status().members.filter(m => m.stateStr === 'SECONDARY').map(m => m.name)

// Vérifier le lag de réplication
rs.printSecondaryReplicationInfo()

// Affichage formaté
function displayReplicaSet() {
  const status = rs.status();
  const config = rs.conf();
  
  print("\n═══════════════════════════════════════════════════════════");
  print(`   REPLICA SET: ${status.set}`);
  print("═══════════════════════════════════════════════════════════\n");
  
  status.members.forEach(member => {
    const cfg = config.members.find(m => m._id === member._id);
    const lag = member.optimeDate ? 
                (status.members[0].optimeDate - member.optimeDate) / 1000 : 0;
    
    print(`${member.name.padEnd(25)} | ${member.stateStr.padEnd(12)} | ` +
          `Health: ${member.health} | Priority: ${cfg.priority} | ` +
          `Lag: ${lag.toFixed(1)}s`);
  });
  
  print("\n");
  const active = status.members.filter(m => m.health === 1).length;
  print(`Active: ${active}/5 | Majority: ${Math.ceil(5/2)} | ` +
        `Status: ${active >= 3 ? '[OK] OK' : '[X] READ-ONLY'}`);
  print("═══════════════════════════════════════════════════════════\n");
}

// Utiliser
displayReplicaSet()
```

---

## [LISTE] RÉCAPITULATIF PARTIE 3

**Ce que tu as accompli :**

[OK] **Configuré 5 membres :**
   - Machine 1 : PRIMARY (Priority 5)
   - Machine 2 : SECONDARY (Priority 3)
   - Machine 3 : SECONDARY (Priority 2)
   - Machine 4 : SECONDARY (Priority 1)
   - Machine 5 : SECONDARY DELAYED 1h (Priority 0, Hidden)

[OK] **Initialisé le Replica Set** avec rs.initiate()

[OK] **Vérifié la réplication** sur les 5 membres

[OK] **Testé le failover** :
   - 1 panne -> Système OK
   - 2 pannes -> Système OK *
   - 3 pannes -> READ-ONLY

[OK] **Configuré le membre DELAYED** (protection contre erreurs humaines)

**État actuel :**

```
┌──────────────────────────────────────────────────────────┐
│          REPLICA SET "rs0" OPÉRATIONNEL [OK]                │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  Membres actifs      : 5/5                               │
│  PRIMARY             : Machine 1 (ou 2)                  │
│  SECONDARY           : 4 membres                         │
│  Quorum              : 3/5                               │
│  Tolérance de panne  : 2 membres *                      │
│  Réplication         : [OK] Fonctionne                     │
│  Delayed membre      : [OK] Configuré (1h)                 │
│  Tags                : [OK] Paris, Lyon, Marseille         │
│                                                          │
└──────────────────────────────────────────────────────────┘
```

---

## [OBJECTIF] PARTIE 4 : OPÉRATIONS AVANCÉES ET MAINTENANCE

### READ PREFERENCE avec tags géographiques

**Scénario : Utilisateurs à Paris doivent lire depuis Paris**

```javascript
// Lire depuis datacenter Paris
db.getMongo().setReadPref('nearest', [{ dc: 'paris' }])

// Lire depuis datacenter Lyon
db.getMongo().setReadPref('nearest', [{ dc: 'lyon' }])

// Fallback si Paris indisponible -> Lyon
db.getMongo().setReadPref('nearest', [
  { dc: 'paris' },
  { dc: 'lyon' },
  {}  // Tous si aucun des deux
])
```

---

### WRITE CONCERN pour haute durabilité

**Pour transactions critiques :**

```javascript
// Écriture confirmée par 3 membres minimum
db.orders.insertOne(
  { product: "Laptop", price: 999, user: "alice" },
  { writeConcern: { w: 3, j: true, wtimeout: 5000 } }
)

// w: 3 = 3 membres (PRIMARY + 2 SECONDARY)
// j: true = Sur disque (journal)
// wtimeout: 5000 = Timeout 5 secondes
```

---

### BACKUP stratégique

**Stratégie avec 5 membres :**

```
Machine 1 : Production (pas de backup dessus)
Machine 2 : Production (pas de backup dessus)
Machine 3 : Production (pas de backup dessus)
Machine 4 : Analytics (peut servir de source backup)
Machine 5 : DELAYED (backup optimal - données stables)

Recommandation :
-> Faire mongodump depuis Machine 5 (DELAYED)
-> Moins de charge sur les membres de production
-> Protection contre suppressions accidentelles
```

**Script de backup depuis Machine 5 :**

```bash
#!/bin/bash
# backup-from-delayed.sh

BACKUP_DIR="/backup/mongodb"
DATE=$(date +%Y%m%d_%H%M%S)
MONGO_HOST="192.168.1.50:27017"  # Machine 5 (DELAYED)

mkdir -p "$BACKUP_DIR"

mongodump \
  --host="$MONGO_HOST" \
  --gzip \
  --archive="$BACKUP_DIR/backup-$DATE.gz"

# Nettoyer les backups > 7 jours
find "$BACKUP_DIR" -name "backup-*.gz" -mtime +7 -delete

echo "[OK] Backup terminé : $BACKUP_DIR/backup-$DATE.gz"
```

---

### MONITORING spécifique 5 membres

**Script de monitoring avancé :**

```javascript
// monitoring-rs5.js
function monitorReplicaSet() {
  const status = rs.status();
  const config = rs.conf();
  
  // Alertes
  const alerts = [];
  
  // 1. Vérifier la santé
  status.members.forEach(member => {
    if (member.health !== 1) {
      alerts.push(`[X] ${member.name} is UNHEALTHY`);
    }
  });
  
  // 2. Vérifier le quorum
  const active = status.members.filter(m => m.health === 1).length;
  if (active < 3) {
    alerts.push(`[ALERTE] CRITICAL: Only ${active} members active (need 3 for quorum)`);
  } else if (active === 3) {
    alerts.push(`[ATTENTION]  WARNING: Only 3 members active (no fault tolerance)`);
  }
  
  // 3. Vérifier le lag
  const primary = status.members.find(m => m.stateStr === 'PRIMARY');
  if (primary) {
    status.members.forEach(member => {
      if (member.stateStr === 'SECONDARY' && !config.members[member._id].hidden) {
        const lag = (primary.optimeDate - member.optimeDate) / 1000;
        if (lag > 10) {
          alerts.push(`[ATTENTION]  ${member.name} has ${lag.toFixed(1)}s replication lag`);
        }
      }
    });
  }
  
  // 4. Vérifier Machine 5 (DELAYED)
  const delayed = status.members[4];
  const expectedLag = 3600;  // 1 heure
  if (delayed && primary) {
    const actualLag = (primary.optimeDate - delayed.optimeDate) / 1000;
    if (Math.abs(actualLag - expectedLag) > 300) {  // Marge 5 min
      alerts.push(`[ATTENTION]  Machine 5 (DELAYED) lag is ${actualLag.toFixed(0)}s (expected ~3600s)`);
    }
  }
  
  // Afficher
  if (alerts.length > 0) {
    print("\n[NOTIF] ALERTS:");
    alerts.forEach(alert => print(`   ${alert}`));
  } else {
    print("\n[OK] All systems operational");
  }
  
  return alerts.length === 0;
}

// Exécuter
monitorReplicaSet()
```

---

### AJOUT d'un 6ème membre (optionnel)

**Si tu veux passer à 6 membres (tolérance toujours 2) :**

```javascript
rs.add({
  host: "192.168.1.60:27017",
  priority: 1,
  tags: { dc: "toulouse", usage: "backup" }
})
```

**Note : Avec 6 membres, majorité = 4**

---

### SUPPRESSION d'un membre

**Si un membre est définitivement hors service :**

```javascript
// Retirer Machine 4 par exemple
rs.remove("192.168.1.40:27017")

// Vérifier
rs.conf().members.length  // Devrait être 4
```

---

## [COURS] FÉLICITATIONS ! [BRAVO]

**Tu maîtrises maintenant :**

[OK] **Architecture 5 membres** :
   - Configuration optimale pour production
   - Tolérance de 2 pannes simultanées
   - Distribution géographique

[OK] **Gestion avancée** :
   - Membres DELAYED (protection erreurs)
   - Tags géographiques (routing intelligent)
   - Priorités (contrôle élection PRIMARY)

[OK] **Opérations** :
   - Installation sur 5 machines
   - Configuration Replica Set
   - Tests de failover
   - Monitoring et alertes

[OK] **Best practices** :
   - Backup depuis DELAYED
   - Read Preference avec tags
   - Write Concern pour durabilité

---

## [DOCS] ANNEXES ET RESSOURCES

### ANNEXE A : Tableau de décision nombre de membres

| Membres | Majorité | Tolérance | Coût | Recommandation |
|---------|----------|-----------|------|----------------|
| 3 | 2 | 1 | $ | [OK] Minimum prod |
| 5 | 3 | 2 | $$ | [OK] Haute dispo |
| 7 | 4 | 3 | $$$ | [ATTENTION] Rarement nécessaire |
| 4 ou 6 | 3 ou 4 | 1 ou 2 | $$+ | [X] Éviter (pair) |

**Conclusion : 5 membres = sweet spot** pour la plupart des applications de production.

---

### ANNEXE B : Checklist de mise en production

**Avant de déployer en production :**

- [ ] 5 machines avec IPs statiques
- [ ] MongoDB 7.0.5+ sur chaque machine
- [ ] Pare-feu configuré (port 27017)
- [ ] Latence réseau < 50ms entre membres
- [ ] 1 membre DELAYED configuré
- [ ] Tags géographiques définis
- [ ] Authentification activée (voir Partie Sécurité)
- [ ] TLS/SSL activé
- [ ] Backup automatique configuré
- [ ] Monitoring en place
- [ ] Tests de failover réussis
- [ ] Documentation à jour
- [ ] Équipe formée

---

### ANNEXE C : Commandes de dépannage rapide

```javascript
// Replica Set bloqué en READ-ONLY ?
rs.status().members.filter(m => m.health === 1).length
// Si < 3 -> Redémarrer les membres arrêtés

// PRIMARY ne s'élit pas ?
rs.conf().members.forEach(m => print(`${m.host} Priority: ${m.priority}`))
// Vérifier que au moins 1 membre a priority > 0

// Réplication lente ?
rs.printSecondaryReplicationInfo()
// Vérifier oplog, charge réseau

// Forcer reconfiguration
cfg = rs.conf()
rs.reconfig(cfg, { force: true })
// ATTENTION : Utiliser seulement en cas d'urgence

// Vérifier l'oplog
use local
db.oplog.rs.stats()
db.getReplicationInfo()
```

---

**[COURS] Tu es maintenant un expert MongoDB Replica Set ! [RAPIDE]**

**Prochaines étapes suggérées :**
1. Activer la sécurité (Authentification + TLS)
2. Mettre en place un monitoring professionnel
3. Automatiser les backups
4. Explorer le sharding (scalabilité horizontale)
5. Optimiser les index pour ta charge de travail

**Bon courage dans tes projets MongoDB ! [FORCE]**