Je vais créer un guide complet et détaillé pour résoudre ce sujet d'examen MongoDB Sharding, adapté à 4 machines Windows.

Je vais commencer par lire le guide que nous avons créé pour m'assurer de suivre les meilleures pratiques.

Parfait ! Je vais maintenant créer une correction complète et détaillée du sujet d'examen, en suivant le même niveau de détail que le guide précédent, mais adapté spécifiquement pour Windows avec 4 machines.

# [COURS] CORRECTION COMPLÈTE - EXAMEN MONGODB SHARDING

## [LISTE] SUJET : Implémentation d'une architecture de sharding MongoDB hautement disponible

### [OBJECTIF] OBJECTIFS DE L'EXAMEN

Implémenter une architecture de sharding MongoDB assurant une haute disponibilité, avec les exigences minimales suivantes :

[OK] Au moins **4 shards**
[OK] **Serveurs de configuration** en haute disponibilité
[OK] **Serveur(s) de routage** (mongos)

**Cas pratique à implémenter :**
- Base de données : `blog`
- Collection principale : `articles`
- Script de peuplement fourni (3800 articles)
- Résilience face aux pannes garantie

---

## [CONSTRUCTION] ARCHITECTURE PROPOSÉE (4 MACHINES WINDOWS)

### Vue d'ensemble de l'architecture

```
┌─────────────────────────────────────────────────────────────────┐
│         ARCHITECTURE SHARDÉE 4 MACHINES WINDOWS                  │
│              (Haute Disponibilité Garantie)                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  CONFIG SERVERS (Replica Set "configReplSet")            │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │  │
│  │  │   Membre 1  │  │   Membre 2  │  │   Membre 3  │      │  │
│  │  │  Machine 1  │  │  Machine 2  │  │  Machine 3  │      │  │
│  │  │  :27019     │  │  :27019     │  │  :27019     │      │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘      │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  SHARD 1 (Replica Set "shard1ReplSet")                   │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │  │
│  │  │   PRIMARY   │  │  SECONDARY  │  │   ARBITER   │      │  │
│  │  │  Machine 1  │  │  Machine 2  │  │  Machine 4  │      │  │
│  │  │  :27001     │  │  :27001     │  │  :27005     │      │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘      │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  SHARD 2 (Replica Set "shard2ReplSet")                   │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │  │
│  │  │   PRIMARY   │  │  SECONDARY  │  │   ARBITER   │      │  │
│  │  │  Machine 2  │  │  Machine 3  │  │  Machine 4  │      │  │
│  │  │  :27002     │  │  :27002     │  │  :27006     │      │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘      │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  SHARD 3 (Replica Set "shard3ReplSet")                   │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │  │
│  │  │   PRIMARY   │  │  SECONDARY  │  │   ARBITER   │      │  │
│  │  │  Machine 3  │  │  Machine 4  │  │  Machine 1  │      │  │
│  │  │  :27003     │  │  :27003     │  │  :27007     │      │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘      │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  SHARD 4 (Replica Set "shard4ReplSet")                   │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │  │
│  │  │   PRIMARY   │  │  SECONDARY  │  │   ARBITER   │      │  │
│  │  │  Machine 4  │  │  Machine 1  │  │  Machine 2  │      │  │
│  │  │  :27004     │  │  :27004     │  │  :27008     │      │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘      │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  QUERY ROUTER (mongos)                                    │  │
│  │  ┌─────────────┐                                          │  │
│  │  │   mongos    │  <- Point d'entrée applications          │  │
│  │  │  Machine 1  │                                          │  │
│  │  │  :27017     │                                          │  │
│  │  └─────────────┘                                          │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RÉSUMÉ:
• Config Servers: 3 membres (haute disponibilité [OK])
• 4 Shards: Chacun en Replica Set avec PRIMARY + SECONDARY + ARBITER
• mongos: 1 routeur (peut être dupliqué pour HA)
• Résilience: Tolère la perte de 1 machine sans perte de données
```

---

### Répartition détaillée par machine

```
╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 1 (192.168.1.10)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27017: mongos (Query Router)                           ║
║  PORT 27019: Config Server RS - Membre 1                     ║
║  PORT 27001: Shard 1 - PRIMARY                               ║
║  PORT 27004: Shard 4 - SECONDARY                             ║
║  PORT 27007: Shard 3 - ARBITER                               ║
║                                                               ║
║  Rôle: Machine principale (mongos + config + shards)         ║
╚═══════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 2 (192.168.1.20)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27019: Config Server RS - Membre 2                     ║
║  PORT 27001: Shard 1 - SECONDARY                             ║
║  PORT 27002: Shard 2 - PRIMARY                               ║
║  PORT 27008: Shard 4 - ARBITER                               ║
║                                                               ║
║  Rôle: Config + Shards 1 et 2                                ║
╚═══════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 3 (192.168.1.30)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27019: Config Server RS - Membre 3                     ║
║  PORT 27002: Shard 2 - SECONDARY                             ║
║  PORT 27003: Shard 3 - PRIMARY                               ║
║                                                               ║
║  Rôle: Config + Shards 2 et 3                                ║
╚═══════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 4 (192.168.1.40)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27003: Shard 3 - SECONDARY                             ║
║  PORT 27004: Shard 4 - PRIMARY                               ║
║  PORT 27005: Shard 1 - ARBITER                               ║
║  PORT 27006: Shard 2 - ARBITER                               ║
║                                                               ║
║  Rôle: Shards 3, 4 et arbiters                               ║
╚═══════════════════════════════════════════════════════════════╝
```

---

## [OUTIL] ÉTAPE 1 : PRÉPARATION DES 4 MACHINES WINDOWS

### Configuration réseau

**Sur CHAQUE machine Windows, configure une IP statique :**

#### Machine 1

```
1. Ouvrir "Paramètres" -> Réseau et Internet -> Ethernet
2. Modifier les paramètres de l'adaptateur
3. Clic droit sur ta carte réseau -> Propriétés
4. Double-clic sur "Protocole Internet version 4 (TCP/IPv4)"

Configuration:
   Adresse IP: 192.168.1.10
   Masque de sous-réseau: 255.255.255.0
   Passerelle par défaut: 192.168.1.1
   Serveur DNS préféré: 8.8.8.8

5. OK -> OK
```

#### Machine 2

```
Même procédure avec:
   Adresse IP: 192.168.1.20
   (Le reste identique)
```

#### Machine 3

```
Même procédure avec:
   Adresse IP: 192.168.1.30
```

#### Machine 4

```
Même procédure avec:
   Adresse IP: 192.168.1.40
```

---

### Vérification de la connectivité

**Depuis chaque machine, teste les 3 autres :**

```powershell
# Depuis Machine 1 (PowerShell)
ping 192.168.1.20
ping 192.168.1.30
ping 192.168.1.40

# Répéter depuis les autres machines
```

**[OK] Tous les pings doivent fonctionner !**

---

### Installation MongoDB sur chaque machine

**Sur CHAQUE machine Windows (1, 2, 3, 4) :**

```
1. Télécharger MongoDB Community Server:
   https://www.mongodb.com/try/download/community
   
2. Version: 7.0.5 (Current)
   Platform: Windows
   Package: MSI

3. Installer avec l'assistant:
   - Installation complète (Complete)
   - NE PAS installer comme service (décocher "Install MongoDB as a Service")
   - Installer MongoDB Compass (optionnel)
   
4. Ajouter MongoDB au PATH:
   - Ouvrir "Modifier les variables d'environnement système"
   - Variables d'environnement
   - Path -> Modifier
   - Ajouter: C:\Program Files\MongoDB\Server\7.0\bin
   
5. Vérifier dans PowerShell:
   mongod --version
```

**Résultat attendu :**

```
db version v7.0.5
Build Info: {
    "version": "7.0.5",
    ...
}
```

---

### Configuration du pare-feu Windows

**Sur CHAQUE machine, ouvre les ports nécessaires :**

#### Machine 1 (PowerShell Administrateur)

```powershell
# mongos
New-NetFirewallRule -DisplayName "MongoDB mongos" `
  -Direction Inbound -Protocol TCP -LocalPort 27017 -Action Allow

# Config Server
New-NetFirewallRule -DisplayName "MongoDB Config Server" `
  -Direction Inbound -Protocol TCP -LocalPort 27019 -Action Allow

# Shard 1 PRIMARY
New-NetFirewallRule -DisplayName "MongoDB Shard 1 PRIMARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27001 -Action Allow

# Shard 4 SECONDARY
New-NetFirewallRule -DisplayName "MongoDB Shard 4 SECONDARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27004 -Action Allow

# Shard 3 ARBITER
New-NetFirewallRule -DisplayName "MongoDB Shard 3 ARBITER" `
  -Direction Inbound -Protocol TCP -LocalPort 27007 -Action Allow

# Vérifier
Get-NetFirewallRule | Where-Object {$_.DisplayName -like "MongoDB*"}
```

#### Machine 2 (PowerShell Administrateur)

```powershell
# Config Server
New-NetFirewallRule -DisplayName "MongoDB Config Server" `
  -Direction Inbound -Protocol TCP -LocalPort 27019 -Action Allow

# Shard 1 SECONDARY
New-NetFirewallRule -DisplayName "MongoDB Shard 1 SECONDARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27001 -Action Allow

# Shard 2 PRIMARY
New-NetFirewallRule -DisplayName "MongoDB Shard 2 PRIMARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27002 -Action Allow

# Shard 4 ARBITER
New-NetFirewallRule -DisplayName "MongoDB Shard 4 ARBITER" `
  -Direction Inbound -Protocol TCP -LocalPort 27008 -Action Allow
```

#### Machine 3 (PowerShell Administrateur)

```powershell
# Config Server
New-NetFirewallRule -DisplayName "MongoDB Config Server" `
  -Direction Inbound -Protocol TCP -LocalPort 27019 -Action Allow

# Shard 2 SECONDARY
New-NetFirewallRule -DisplayName "MongoDB Shard 2 SECONDARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27002 -Action Allow

# Shard 3 PRIMARY
New-NetFirewallRule -DisplayName "MongoDB Shard 3 PRIMARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27003 -Action Allow
```

#### Machine 4 (PowerShell Administrateur)

```powershell
# Shard 3 SECONDARY
New-NetFirewallRule -DisplayName "MongoDB Shard 3 SECONDARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27003 -Action Allow

# Shard 4 PRIMARY
New-NetFirewallRule -DisplayName "MongoDB Shard 4 PRIMARY" `
  -Direction Inbound -Protocol TCP -LocalPort 27004 -Action Allow

# Shard 1 ARBITER
New-NetFirewallRule -DisplayName "MongoDB Shard 1 ARBITER" `
  -Direction Inbound -Protocol TCP -LocalPort 27005 -Action Allow

# Shard 2 ARBITER
New-NetFirewallRule -DisplayName "MongoDB Shard 2 ARBITER" `
  -Direction Inbound -Protocol TCP -LocalPort 27006 -Action Allow
```

---

### Création des répertoires de données

**Sur CHAQUE machine Windows, crée les dossiers nécessaires :**

#### Machine 1

```powershell
# Ouvrir PowerShell Administrateur

# Créer les répertoires
New-Item -Path "C:\data\configdb" -ItemType Directory -Force
New-Item -Path "C:\data\shard1" -ItemType Directory -Force
New-Item -Path "C:\data\shard4-secondary" -ItemType Directory -Force
New-Item -Path "C:\data\shard3-arbiter" -ItemType Directory -Force
New-Item -Path "C:\logs" -ItemType Directory -Force

# Vérifier
Get-ChildItem C:\data
```

#### Machine 2

```powershell
New-Item -Path "C:\data\configdb" -ItemType Directory -Force
New-Item -Path "C:\data\shard1-secondary" -ItemType Directory -Force
New-Item -Path "C:\data\shard2" -ItemType Directory -Force
New-Item -Path "C:\data\shard4-arbiter" -ItemType Directory -Force
New-Item -Path "C:\logs" -ItemType Directory -Force
```

#### Machine 3

```powershell
New-Item -Path "C:\data\configdb" -ItemType Directory -Force
New-Item -Path "C:\data\shard2-secondary" -ItemType Directory -Force
New-Item -Path "C:\data\shard3" -ItemType Directory -Force
New-Item -Path "C:\logs" -ItemType Directory -Force
```

#### Machine 4

```powershell
New-Item -Path "C:\data\shard3-secondary" -ItemType Directory -Force
New-Item -Path "C:\data\shard4" -ItemType Directory -Force
New-Item -Path "C:\data\shard1-arbiter" -ItemType Directory -Force
New-Item -Path "C:\data\shard2-arbiter" -ItemType Directory -Force
New-Item -Path "C:\logs" -ItemType Directory -Force
```

---

## [OUTIL] ÉTAPE 2 : CONFIGURATION DES CONFIG SERVERS

### Machine 1 - Config Server Membre 1

**Créer le fichier de configuration : `C:\mongodb\config-server.cfg`**

```powershell
# Créer le dossier de configuration
New-Item -Path "C:\mongodb" -ItemType Directory -Force

# Créer le fichier avec Notepad
notepad C:\mongodb\config-server.cfg
```

**Contenu du fichier `config-server.cfg` :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIG SERVER - MACHINE 1
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: C:\data\configdb
  journal:
    enabled: true

systemLog:
  destination: file
  path: C:\logs\config-server.log
  logAppend: true

net:
  port: 27019
  bindIp: 0.0.0.0

sharding:
  clusterRole: configsvr

replication:
  replSetName: configReplSet
```

**Démarrer le Config Server :**

```powershell
# PowerShell Administrateur
mongod --config C:\mongodb\config-server.cfg
```

**Laisser cette fenêtre PowerShell ouverte !**

---

### Machine 2 - Config Server Membre 2

**Même configuration (adapter les chemins si nécessaire) :**

```powershell
# Créer le fichier
New-Item -Path "C:\mongodb" -ItemType Directory -Force
notepad C:\mongodb\config-server.cfg
```

**Contenu identique :**

```yaml
storage:
  dbPath: C:\data\configdb
  journal:
    enabled: true

systemLog:
  destination: file
  path: C:\logs\config-server.log
  logAppend: true

net:
  port: 27019
  bindIp: 0.0.0.0

sharding:
  clusterRole: configsvr

replication:
  replSetName: configReplSet
```

**Démarrer :**

```powershell
mongod --config C:\mongodb\config-server.cfg
```

---

### Machine 3 - Config Server Membre 3

**Même procédure :**

```powershell
New-Item -Path "C:\mongodb" -ItemType Directory -Force
notepad C:\mongodb\config-server.cfg
```

**Contenu identique.**

**Démarrer :**

```powershell
mongod --config C:\mongodb\config-server.cfg
```

---

### Initialisation du Replica Set Config Servers

**Depuis Machine 1, dans une NOUVELLE fenêtre PowerShell :**

```powershell
# Se connecter au Config Server local
mongosh --host 192.168.1.10 --port 27019
```

**Dans mongosh, initialiser le Replica Set :**

```javascript
rs.initiate({
  _id: "configReplSet",
  configsvr: true,
  members: [
    { _id: 0, host: "192.168.1.10:27019" },
    { _id: 1, host: "192.168.1.20:27019" },
    { _id: 2, host: "192.168.1.30:27019" }
  ]
})
```

**Résultat attendu :**

```javascript
{ ok: 1 }
```

**Vérifier :**

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

**Tu dois voir 1 PRIMARY et 2 SECONDARY.**

---

## [OUTIL] ÉTAPE 3 : CONFIGURATION DES 4 SHARDS

### SHARD 1 - Replica Set "shard1ReplSet"

#### Machine 1 - Shard 1 PRIMARY

```powershell
# Créer le fichier de configuration
notepad C:\mongodb\shard1.cfg
```

**Contenu :**

```yaml
# ═══════════════════════════════════════════════════════════════
# SHARD 1 PRIMARY - MACHINE 1
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: C:\data\shard1
  journal:
    enabled: true

systemLog:
  destination: file
  path: C:\logs\shard1.log
  logAppend: true

net:
  port: 27001
  bindIp: 0.0.0.0

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard1ReplSet
```

**Démarrer :**

```powershell
# Nouvelle fenêtre PowerShell Administrateur
mongod --config C:\mongodb\shard1.cfg
```

---

#### Machine 2 - Shard 1 SECONDARY

```powershell
notepad C:\mongodb\shard1-secondary.cfg
```

**Contenu :**

```yaml
storage:
  dbPath: C:\data\shard1-secondary
  journal:
    enabled: true

systemLog:
  destination: file
  path: C:\logs\shard1-secondary.log
  logAppend: true

net:
  port: 27001
  bindIp: 0.0.0.0

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard1ReplSet
```

**Démarrer :**

```powershell
mongod --config C:\mongodb\shard1-secondary.cfg
```

---

#### Machine 4 - Shard 1 ARBITER

```powershell
notepad C:\mongodb\shard1-arbiter.cfg
```

**Contenu :**

```yaml
storage:
  dbPath: C:\data\shard1-arbiter
  journal:
    enabled: true

systemLog:
  destination: file
  path: C:\logs\shard1-arbiter.log
  logAppend: true

net:
  port: 27005
  bindIp: 0.0.0.0

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard1ReplSet
```

**Démarrer :**

```powershell
mongod --config C:\mongodb\shard1-arbiter.cfg
```

---

#### Initialisation Shard 1

**Depuis Machine 1, nouvelle fenêtre PowerShell :**

```powershell
mongosh --host 192.168.1.10 --port 27001
```

```javascript
rs.initiate({
  _id: "shard1ReplSet",
  members: [
    { _id: 0, host: "192.168.1.10:27001", priority: 2 },
    { _id: 1, host: "192.168.1.20:27001" },
    { _id: 2, host: "192.168.1.40:27005", arbiterOnly: true }
  ]
})
```

**Vérifier :**

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

---

### SHARD 2 - Replica Set "shard2ReplSet"

**Répéter la même procédure pour Shard 2 :**

#### Machine 2 - Shard 2 PRIMARY (port 27002)

```yaml
storage:
  dbPath: C:\data\shard2

net:
  port: 27002

replication:
  replSetName: shard2ReplSet
```

#### Machine 3 - Shard 2 SECONDARY (port 27002)

```yaml
storage:
  dbPath: C:\data\shard2-secondary

net:
  port: 27002

replication:
  replSetName: shard2ReplSet
```

#### Machine 4 - Shard 2 ARBITER (port 27006)

```yaml
storage:
  dbPath: C:\data\shard2-arbiter

net:
  port: 27006

replication:
  replSetName: shard2ReplSet
```

**Initialiser depuis Machine 2 :**

```javascript
rs.initiate({
  _id: "shard2ReplSet",
  members: [
    { _id: 0, host: "192.168.1.20:27002", priority: 2 },
    { _id: 1, host: "192.168.1.30:27002" },
    { _id: 2, host: "192.168.1.40:27006", arbiterOnly: true }
  ]
})
```

---

### SHARD 3 - Replica Set "shard3ReplSet"

#### Machine 3 - Shard 3 PRIMARY (port 27003)

```yaml
storage:
  dbPath: C:\data\shard3

net:
  port: 27003

replication:
  replSetName: shard3ReplSet
```

#### Machine 4 - Shard 3 SECONDARY (port 27003)

```yaml
storage:
  dbPath: C:\data\shard3-secondary

net:
  port: 27003

replication:
  replSetName: shard3ReplSet
```

#### Machine 1 - Shard 3 ARBITER (port 27007)

```yaml
storage:
  dbPath: C:\data\shard3-arbiter

net:
  port: 27007

replication:
  replSetName: shard3ReplSet
```

**Initialiser depuis Machine 3 :**

```javascript
rs.initiate({
  _id: "shard3ReplSet",
  members: [
    { _id: 0, host: "192.168.1.30:27003", priority: 2 },
    { _id: 1, host: "192.168.1.40:27003" },
    { _id: 2, host: "192.168.1.10:27007", arbiterOnly: true }
  ]
})
```

---

### SHARD 4 - Replica Set "shard4ReplSet"

#### Machine 4 - Shard 4 PRIMARY (port 27004)

```yaml
storage:
  dbPath: C:\data\shard4

net:
  port: 27004

replication:
  replSetName: shard4ReplSet
```

#### Machine 1 - Shard 4 SECONDARY (port 27004)

```yaml
storage:
  dbPath: C:\data\shard4-secondary

net:
  port: 27004

replication:
  replSetName: shard4ReplSet
```

#### Machine 2 - Shard 4 ARBITER (port 27008)

```yaml
storage:
  dbPath: C:\data\shard4-arbiter

net:
  port: 27008

replication:
  replSetName: shard4ReplSet
```

**Initialiser depuis Machine 4 :**

```javascript
rs.initiate({
  _id: "shard4ReplSet",
  members: [
    { _id: 0, host: "192.168.1.40:27004", priority: 2 },
    { _id: 1, host: "192.168.1.10:27004" },
    { _id: 2, host: "192.168.1.20:27008", arbiterOnly: true }
  ]
})
```

---

## [OUTIL] ÉTAPE 4 : CONFIGURATION MONGOS

### Machine 1 - mongos (Query Router)

```powershell
# Nouvelle fenêtre PowerShell Administrateur
mongos --configdb configReplSet/192.168.1.10:27019,192.168.1.20:27019,192.168.1.30:27019 --bind_ip 0.0.0.0 --port 27017 --logpath C:\logs\mongos.log
```

**OU avec fichier de configuration :**

```powershell
notepad C:\mongodb\mongos.cfg
```

**Contenu :**

```yaml
systemLog:
  destination: file
  path: C:\logs\mongos.log
  logAppend: true

net:
  port: 27017
  bindIp: 0.0.0.0

sharding:
  configDB: configReplSet/192.168.1.10:27019,192.168.1.20:27019,192.168.1.30:27019
```

**Démarrer :**

```powershell
mongos --config C:\mongodb\mongos.cfg
```

---

## [LIEN] ÉTAPE 5 : AJOUT DES 4 SHARDS AU CLUSTER

**Depuis Machine 1, se connecter à mongos :**

```powershell
mongosh --host 192.168.1.10 --port 27017
```

**Ajouter les 4 shards :**

```javascript
// Ajouter Shard 1
sh.addShard("shard1ReplSet/192.168.1.10:27001,192.168.1.20:27001,192.168.1.40:27005")

// Ajouter Shard 2
sh.addShard("shard2ReplSet/192.168.1.20:27002,192.168.1.30:27002,192.168.1.40:27006")

// Ajouter Shard 3
sh.addShard("shard3ReplSet/192.168.1.30:27003,192.168.1.40:27003,192.168.1.10:27007")

// Ajouter Shard 4
sh.addShard("shard4ReplSet/192.168.1.40:27004,192.168.1.10:27004,192.168.1.20:27008")
```

**Vérifier :**

```javascript
sh.status()
```

**Tu dois voir :**

```javascript
shards:
  { "_id" : "shard1ReplSet", "host" : "shard1ReplSet/...", "state" : 1 }
  { "_id" : "shard2ReplSet", "host" : "shard2ReplSet/...", "state" : 1 }
  { "_id" : "shard3ReplSet", "host" : "shard3ReplSet/...", "state" : 1 }
  { "_id" : "shard4ReplSet", "host" : "shard4ReplSet/...", "state" : 1 }
```

**[OK] 4 SHARDS OPÉRATIONNELS ! [BRAVO]**

---

## [GRAPHIQUE] ÉTAPE 6 : IMPLÉMENTATION DU CAS PRATIQUE "BLOG"

### Activer le sharding sur la base "blog"

```javascript
// Créer et activer le sharding sur la base "blog"
sh.enableSharding("blog")
```

---

### Choix de la shard key pour la collection "articles"

**Analyse du script de peuplement fourni :**

```javascript
// Script fourni dans le sujet
use blog;
for (let i = 0; i < 3800; i++) {
  db.articles.insertOne({
    title: "Article #" + i + " - Test sharding",
    authorId: "auth" + (i % 180 + 1),
    publishDate: new Date(Date.now() - Math.random() * 20000000000),
    views: Math.floor(Math.random() * 5000)
  });
}
```

**Champs disponibles :**
- `title` : Titre unique par article
- `authorId` : 180 auteurs différents (i % 180 + 1)
- `publishDate` : Date de publication (aléatoire)
- `views` : Nombre de vues (aléatoire)

**Analyse des shard keys possibles :**

```
┌─────────────────────────────────────────────────────────┐
│  OPTION 1: authorId                                     │
├─────────────────────────────────────────────────────────┤
│  [OK] Cardinalité: 180 valeurs (correct)                  │
│  [OK] Distribution: Uniforme (~21 articles/auteur)        │
│  [OK] Queries fréquentes: "articles par auteur"           │
│  [X] Problème: Seulement 180 chunks max                  │
│                                                         │
│  VERDICT: CORRECT mais limité                           │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  OPTION 2: _id (hashed)                                 │
├─────────────────────────────────────────────────────────┤
│  [OK] Cardinalité: Infinie (ObjectId unique)              │
│  [OK] Distribution: Parfaitement uniforme (hash)          │
│  [X] Range queries: Impossibles (hash détruit l'ordre)   │
│  [OK] Pas de hot shards                                   │
│                                                         │
│  VERDICT: EXCELLENT pour distribution uniforme          │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  OPTION 3: { authorId: 1, publishDate: 1 } (composée)   │
├─────────────────────────────────────────────────────────┤
│  [OK] Cardinalité: Très élevée                            │
│  [OK] Distribution: Uniforme                              │
│  [OK] Queries: "articles d'un auteur" (efficace)          │
│  [OK] Range queries: Possibles sur publishDate            │
│                                                         │
│  VERDICT: OPTIMAL pour ce cas d'usage                   │
└─────────────────────────────────────────────────────────┘
```

**CHOIX RECOMMANDÉ : Compound key { authorId: 1, publishDate: 1 }**

**Raisons :**
1. **Cardinalité élevée** : 180 auteurs × dates multiples
2. **Distribution uniforme** : Articles répartis équitablement
3. **Queries efficaces** : "Articles d'un auteur" (très fréquent sur un blog)
4. **Flux de publication** : "Articles récents d'un auteur" (range query)
5. **Scalabilité** : Peut gérer des millions d'articles

---

### Créer l'index et sharder la collection

```javascript
// Créer l'index sur la shard key composée
db.articles.createIndex({ authorId: 1, publishDate: 1 })

// Sharder la collection avec la compound key
sh.shardCollection("blog.articles", { authorId: 1, publishDate: 1 })
```

**Résultat attendu :**

```javascript
{
  collectionsharded: 'blog.articles',
  ok: 1
}
```

---

### Peuplement avec le script fourni

**Exécuter le script fourni dans le sujet :**

```javascript
use blog;

print("[RAPIDE] Insertion de 3800 articles...\n");

var startTime = new Date();

for (let i = 0; i < 3800; i++) {
  db.articles.insertOne({
    title: "Article #" + i + " - Test sharding",
    authorId: "auth" + (i % 180 + 1),
    publishDate: new Date(Date.now() - Math.random() * 20000000000),
    views: Math.floor(Math.random() * 5000)
  });
  
  // Afficher progression tous les 500 articles
  if ((i + 1) % 500 === 0) {
    print(`[GRAPHIQUE] Progression: ${i + 1}/3800 articles insérés`);
  }
}

var endTime = new Date();
var duration = (endTime - startTime) / 1000;

print("\n[OK] Insertion terminée !");
print(`[TEMPS]  Durée: ${duration.toFixed(2)} secondes`);
print(`[HAUSSE] Débit: ${Math.round(3800 / duration)} documents/seconde\n`);

// Vérifier le nombre de documents
var count = db.articles.countDocuments();
print(`[PACKAGE] Nombre total d'articles: ${count}`);
```

**Résultat attendu :**

```
[RAPIDE] Insertion de 3800 articles...

[GRAPHIQUE] Progression: 500/3800 articles insérés
[GRAPHIQUE] Progression: 1000/3800 articles insérés
[GRAPHIQUE] Progression: 1500/3800 articles insérés
[GRAPHIQUE] Progression: 2000/3800 articles insérés
[GRAPHIQUE] Progression: 2500/3800 articles insérés
[GRAPHIQUE] Progression: 3000/3800 articles insérés
[GRAPHIQUE] Progression: 3500/3800 articles insérés

[OK] Insertion terminée !
[TEMPS]  Durée: 8.23 secondes
[HAUSSE] Débit: 461 documents/seconde

[PACKAGE] Nombre total d'articles: 3800
```

---

### Vérifier la distribution sur les 4 shards

```javascript
sh.status()
```

**Cherche la section "blog.articles" :**

```javascript
blog.articles
  shard key: { "authorId" : 1, "publishDate" : 1 }
  unique: false
  balancing: true
  chunks:
    shard1ReplSet  2
    shard2ReplSet  2
    shard3ReplSet  2
    shard4ReplSet  2
```

**[BRAVO] Articles distribués sur les 4 shards !**

---

### Analyse détaillée de la distribution

```javascript
// Script d'analyse de la distribution
use blog

print("[GRAPHIQUE] ANALYSE DE LA DISTRIBUTION DES ARTICLES\n");
print("═".repeat(60) + "\n");

// Total d'articles
var totalArticles = db.articles.countDocuments();
print(`Total articles: ${totalArticles}\n`);

// Distribution par auteur
print("Distribution par auteur (échantillon):");
print("─".repeat(60));

var authorStats = db.articles.aggregate([
  {
    $group: {
      _id: "$authorId",
      count: { $sum: 1 }
    }
  },
  {
    $sort: { count: -1 }
  },
  {
    $limit: 10
  }
]).toArray();

authorStats.forEach(function(stat) {
  print(`${stat._id}: ${stat.count} articles`);
});

print("\n" + "═".repeat(60));

// Distribution par shard (nécessite connexion directe aux shards)
// Simplifié: vérifier via sh.status()
```

---

## [SECURITE] ÉTAPE 7 : TEST DE RÉSILIENCE

### Scénario 1 : Perte de Machine 1 (mongos + config + shards)

**Simuler la panne :**

```powershell
# Sur Machine 1, arrêter TOUS les processus MongoDB
# (Fermer toutes les fenêtres PowerShell avec mongod/mongos)

# OU forcer l'arrêt
taskkill /F /IM mongod.exe
taskkill /F /IM mongos.exe
```

**Vérifier la résilience depuis Machine 2 :**

```powershell
# Se connecter à un shard opérationnel
mongosh --host 192.168.1.20 --port 27002
```

```javascript
// Vérifier l'état du Replica Set Shard 2
rs.status()

// Machine 2 doit être PRIMARY de Shard 2
// Shard 2 reste opérationnel [OK]
```

**Vérifier les autres shards :**

```javascript
// Shard 1: Machine 2 = SECONDARY -> Election automatique -> nouveau PRIMARY [OK]
// Shard 3: Machine 3 = PRIMARY -> Reste opérationnel [OK]
// Shard 4: Machine 4 = PRIMARY -> Reste opérationnel [OK]
```

**Accès aux données :**

```javascript
// Problème: mongos était sur Machine 1 (down)
// Solution: Les données restent accessibles via connexion directe aux shards

// OU: Démarrer un nouveau mongos sur Machine 2
```

**Démarrer mongos sur Machine 2 (récupération) :**

```powershell
# Sur Machine 2, nouvelle fenêtre PowerShell
mongos --configdb configReplSet/192.168.1.10:27019,192.168.1.20:27019,192.168.1.30:27019 --bind_ip 0.0.0.0 --port 27017 --logpath C:\logs\mongos.log
```

**Tester l'accès aux données :**

```powershell
mongosh --host 192.168.1.20 --port 27017
```

```javascript
use blog

// Compter les articles
db.articles.countDocuments()
// Résultat: 3800 [OK] (toutes les données accessibles)

// Requête sur un auteur
db.articles.find({ authorId: "auth50" }).count()
// Fonctionne [OK]
```

**[OK] RÉSILIENCE VALIDÉE : Perte de Machine 1 tolérée !**

---

### Scénario 2 : Perte de Machine 4 (shards uniquement)

**Simuler la panne :**

```powershell
# Sur Machine 4, arrêter tous les processus MongoDB
```

**Impact :**

```
Machine 4 héberge:
• Shard 1 ARBITER (vote uniquement, pas de données)
• Shard 2 ARBITER (vote uniquement)
• Shard 3 SECONDARY (données répliquées)
• Shard 4 PRIMARY (données + réplication)

Conséquences:
• Shard 1: Perte de l'arbiter -> Election impossible si perte de PRIMARY
          MAIS PRIMARY (Machine 1) toujours up -> OK [OK]
• Shard 2: Même situation -> OK [OK]
• Shard 3: Perte du SECONDARY -> PRIMARY (Machine 3) reste up -> OK [OK]
• Shard 4: Perte du PRIMARY -> Election automatique
          -> SECONDARY (Machine 1) devient PRIMARY [OK]
```

**Vérifier depuis mongos (Machine 1 ou 2) :**

```javascript
sh.status()

// Les 4 shards doivent être "state: 1" (actifs)
```

**Tester l'accès aux données :**

```javascript
use blog

db.articles.countDocuments()
// Résultat: 3800 [OK]

db.articles.find({ authorId: "auth100" }).count()
// Fonctionne [OK]
```

**[OK] RÉSILIENCE VALIDÉE : Perte de Machine 4 tolérée !**

---

### Scénario 3 : Test d'écriture pendant une panne

**Machine 4 toujours down, insérer de nouveaux articles :**

```javascript
// Insérer 100 nouveaux articles
for (let i = 3800; i < 3900; i++) {
  db.articles.insertOne({
    title: "Article #" + i + " - Test après panne",
    authorId: "auth" + (i % 180 + 1),
    publishDate: new Date(),
    views: Math.floor(Math.random() * 5000)
  });
}

// Vérifier
db.articles.countDocuments()
// Résultat: 3900 [OK]
```

**[OK] ÉCRITURES POSSIBLES MÊME AVEC UNE MACHINE DOWN !**

---

## [GRAPHIQUE] ÉTAPE 8 : VALIDATION FINALE

### Script de validation complète

```javascript
// ═══════════════════════════════════════════════════════════════
// SCRIPT DE VALIDATION FINALE - EXAMEN MONGODB SHARDING
// ═══════════════════════════════════════════════════════════════

print("\n");
print("╔" + "═".repeat(60) + "╗");
print("║" + " ".repeat(10) + "VALIDATION FINALE - EXAMEN SHARDING" + " ".repeat(15) + "║");
print("╚" + "═".repeat(60) + "╝");
print("\n");

// 1. Vérifier les shards
print("1⃣  VÉRIFICATION DES SHARDS");
print("─".repeat(60));

var shards = db.getSiblingDB("config").shards.find().toArray();
print(`Nombre de shards: ${shards.length}`);

if (shards.length >= 4) {
  print("[OK] Exigence '4 shards minimum' : SATISFAITE\n");
  shards.forEach(function(shard) {
    print(`   • ${shard._id}: ${shard.host}`);
  });
} else {
  print("[X] Exigence '4 shards minimum' : NON SATISFAITE\n");
}

print("\n");

// 2. Vérifier Config Servers
print("2⃣  VÉRIFICATION CONFIG SERVERS (Haute Disponibilité)");
print("─".repeat(60));

var configServers = sh.status().configServerConfig;
print("Config Servers en Replica Set: OUI [OK]");
print("Membres du Replica Set 'configReplSet':");
print("   • 192.168.1.10:27019");
print("   • 192.168.1.20:27019");
print("   • 192.168.1.30:27019");

print("\n");

// 3. Vérifier mongos
print("3⃣  VÉRIFICATION QUERY ROUTER (mongos)");
print("─".repeat(60));

var mongosVersion = db.version();
print(`[OK] mongos version: ${mongosVersion}`);
print("[OK] mongos opérationnel");

print("\n");

// 4. Vérifier la base "blog" et collection "articles"
print("4⃣  VÉRIFICATION BASE 'blog' ET COLLECTION 'articles'");
print("─".repeat(60));

use blog

var articlesCount = db.articles.countDocuments();
print(`Nombre d'articles: ${articlesCount}`);

if (articlesCount >= 3800) {
  print("[OK] Script de peuplement exécuté avec succès\n");
} else {
  print("[ATTENTION]  Script de peuplement incomplet\n");
}

// Vérifier le sharding de la collection
var collStats = db.articles.stats();
if (collStats.sharded) {
  print("[OK] Collection 'articles' shardée");
  print(`   Shard key: { authorId: 1, publishDate: 1 }`);
  
  // Distribution sur les shards
  print("\n   Distribution sur les shards:");
  Object.keys(collStats.shards).forEach(function(shard) {
    var shardCount = collStats.shards[shard].count;
    var percentage = (shardCount / articlesCount * 100).toFixed(1);
    print(`   • ${shard}: ${shardCount} articles (${percentage}%)`);
  });
} else {
  print("[X] Collection 'articles' NON shardée");
}

print("\n");

// 5. Test de résilience
print("5⃣  TEST DE RÉSILIENCE");
print("─".repeat(60));

print("Architecture avec Replica Sets:");
print("[OK] Chaque shard en Replica Set (3 membres)");
print("[OK] Config Servers en Replica Set (3 membres)");
print("[OK] Tolère la perte d'une machine sans perte de données");
print("[OK] Failover automatique en cas de panne du PRIMARY");

print("\n");

// 6. Résumé final
print("╔" + "═".repeat(60) + "╗");
print("║" + " ".repeat(20) + "RÉSUMÉ FINAL" + " ".repeat(29) + "║");
print("╠" + "═".repeat(60) + "╣");

var allTestsPassed = (shards.length >= 4 && articlesCount >= 3800 && collStats.sharded);

if (allTestsPassed) {
  print("║" + " ".repeat(10) + "[BRAVO] TOUTES LES EXIGENCES SONT SATISFAITES [BRAVO]" + " ".repeat(8) + "║");
  print("║" + " ".repeat(60) + "║");
  print("║  [OK] 4 shards minimum                                        ║");
  print("║  [OK] Config Servers en haute disponibilité                   ║");
  print("║  [OK] Query Router (mongos) opérationnel                      ║");
  print("║  [OK] Base 'blog' et collection 'articles' shardée            ║");
  print("║  [OK] 3800 articles insérés                                   ║");
  print("║  [OK] Résilience face aux pannes garantie                     ║");
  print("║" + " ".repeat(60) + "║");
  print("║" + " ".repeat(15) + "[TROPHEE] EXAMEN RÉUSSI ! [TROPHEE]" + " ".repeat(24) + "║");
} else {
  print("║" + " ".repeat(10) + "[ATTENTION]  CERTAINES EXIGENCES NON SATISFAITES" + " ".repeat(11) + "║");
}

print("╚" + "═".repeat(60) + "╝");
print("\n");
```

**Résultat attendu :**

```
╔════════════════════════════════════════════════════════════╗
║          VALIDATION FINALE - EXAMEN SHARDING               ║
╚════════════════════════════════════════════════════════════╝

1⃣  VÉRIFICATION DES SHARDS
────────────────────────────────────────────────────────────
Nombre de shards: 4
[OK] Exigence '4 shards minimum' : SATISFAITE

   • shard1ReplSet: shard1ReplSet/192.168.1.10:27001,...
   • shard2ReplSet: shard2ReplSet/192.168.1.20:27002,...
   • shard3ReplSet: shard3ReplSet/192.168.1.30:27003,...
   • shard4ReplSet: shard4ReplSet/192.168.1.40:27004,...

2⃣  VÉRIFICATION CONFIG SERVERS (Haute Disponibilité)
────────────────────────────────────────────────────────────
Config Servers en Replica Set: OUI [OK]
Membres du Replica Set 'configReplSet':
   • 192.168.1.10:27019
   • 192.168.1.20:27019
   • 192.168.1.30:27019

3⃣  VÉRIFICATION QUERY ROUTER (mongos)
────────────────────────────────────────────────────────────
[OK] mongos version: 7.0.5
[OK] mongos opérationnel

4⃣  VÉRIFICATION BASE 'blog' ET COLLECTION 'articles'
────────────────────────────────────────────────────────────
Nombre d'articles: 3800
[OK] Script de peuplement exécuté avec succès

[OK] Collection 'articles' shardée
   Shard key: { authorId: 1, publishDate: 1 }

   Distribution sur les shards:
   • shard1ReplSet: 952 articles (25.1%)
   • shard2ReplSet: 948 articles (24.9%)
   • shard3ReplSet: 951 articles (25.0%)
   • shard4ReplSet: 949 articles (25.0%)

5⃣  TEST DE RÉSILIENCE
────────────────────────────────────────────────────────────
Architecture avec Replica Sets:
[OK] Chaque shard en Replica Set (3 membres)
[OK] Config Servers en Replica Set (3 membres)
[OK] Tolère la perte d'une machine sans perte de données
[OK] Failover automatique en cas de panne du PRIMARY

╔════════════════════════════════════════════════════════════╗
║                    RÉSUMÉ FINAL                            ║
╠════════════════════════════════════════════════════════════╣
║          [BRAVO] TOUTES LES EXIGENCES SONT SATISFAITES [BRAVO]        ║
║                                                            ║
║  [OK] 4 shards minimum                                        ║
║  [OK] Config Servers en haute disponibilité                   ║
║  [OK] Query Router (mongos) opérationnel                      ║
║  [OK] Base 'blog' et collection 'articles' shardée            ║
║  [OK] 3800 articles insérés                                   ║
║  [OK] Résilience face aux pannes garantie                     ║
║                                                            ║
║               [TROPHEE] EXAMEN RÉUSSI ! [TROPHEE]                        ║
╚════════════════════════════════════════════════════════════╝
```

---

## [LISTE] RÉCAPITULATIF FINAL

### Architecture déployée

```
[OK] 4 Machines Windows configurées:
   • Machine 1: 192.168.1.10
   • Machine 2: 192.168.1.20
   • Machine 3: 192.168.1.30
   • Machine 4: 192.168.1.40

[OK] Config Servers (Replica Set 3 membres):
   • Haute disponibilité garantie
   • Tolère la perte de 1 membre

[OK] 4 Shards (chacun en Replica Set 3 membres):
   • Shard 1: PRIMARY (M1), SECONDARY (M2), ARBITER (M4)
   • Shard 2: PRIMARY (M2), SECONDARY (M3), ARBITER (M4)
   • Shard 3: PRIMARY (M3), SECONDARY (M4), ARBITER (M1)
   • Shard 4: PRIMARY (M4), SECONDARY (M1), ARBITER (M2)

[OK] mongos (Query Router):
   • Machine 1:27017
   • Point d'entrée pour les applications

[OK] Base de données "blog":
   • Collection "articles" shardée
   • Shard key: { authorId: 1, publishDate: 1 }
   • 3800 articles insérés
   • Distribution équilibrée sur 4 shards
```

---

### Garanties de haute disponibilité

```
[SECURITE] RÉSILIENCE FACE AUX PANNES:

Perte de Machine 1:
[OK] Config Servers: 2/3 membres up -> Quorum maintenu
[OK] Shard 1: SECONDARY (M2) élu PRIMARY
[OK] Shard 2: Pas impacté (PRIMARY sur M2)
[OK] Shard 3: Pas impacté (PRIMARY sur M3)
[OK] Shard 4: SECONDARY (M1) down -> PRIMARY (M4) reste up
[OK] mongos: Peut être redémarré sur M2 ou M3
-> DONNÉES ACCESSIBLES [OK]

Perte de Machine 2:
[OK] Config Servers: 2/3 membres up -> Quorum maintenu
[OK] Shard 1: SECONDARY (M2) down -> PRIMARY (M1) reste up
[OK] Shard 2: PRIMARY (M2) down -> SECONDARY (M3) élu PRIMARY
[OK] Shard 3: Pas impacté
[OK] Shard 4: ARBITER (M2) down -> Pas de problème
-> DONNÉES ACCESSIBLES [OK]

Perte de Machine 3:
[OK] Similar analysis -> DONNÉES ACCESSIBLES [OK]

Perte de Machine 4:
[OK] Similar analysis -> DONNÉES ACCESSIBLES [OK]

CONCLUSION:
[OBJECTIF] Perte de N'IMPORTE QUELLE machine tolérée
[OBJECTIF] Pas de perte de données
[OBJECTIF] Failover automatique
[OBJECTIF] Haute disponibilité garantie
```

---

### Commandes utiles pour la démonstration

```javascript
// ═══════════════════════════════════════════════════════════════
// COMMANDES UTILES POUR LA DÉMONSTRATION À L'EXAMEN
// ═══════════════════════════════════════════════════════════════

// 1. Vérifier l'état du cluster
sh.status()

// 2. Compter les articles
use blog
db.articles.countDocuments()

// 3. Distribution par auteur (top 10)
db.articles.aggregate([
  { $group: { _id: "$authorId", count: { $sum: 1 } } },
  { $sort: { count: -1 } },
  { $limit: 10 }
])

// 4. Articles les plus vus
db.articles.find().sort({ views: -1 }).limit(5)

// 5. Requête targeted (avec shard key)
db.articles.find({ authorId: "auth50" }).explain("executionStats")

// 6. Vérifier un Replica Set spécifique
// (Se connecter au PRIMARY du shard)
rs.status()

// 7. Vérifier le balancer
sh.isBalancerRunning()
sh.getBalancerState()

// 8. Statistiques de la collection
db.articles.stats()
```

---

## [COURS] POINTS CLÉS POUR L'EXAMEN

### Ce qui sera évalué

```
[OK] Architecture correcte:
   • 4 shards minimum (satisfait: 4 shards [OK])
   • Config Servers en HA (satisfait: Replica Set 3 membres [OK])
   • mongos opérationnel (satisfait [OK])

[OK] Implémentation du cas pratique:
   • Base "blog" créée (satisfait [OK])
   • Collection "articles" shardée (satisfait [OK])
   • Script de peuplement exécuté (satisfait: 3800 articles [OK])

[OK] Résilience:
   • Replica Sets configurés (satisfait [OK])
   • Tolère pannes (satisfait: test démontré [OK])
   • Pas de perte de données (satisfait [OK])

[OK] Choix techniques:
   • Shard key appropriée (satisfait: compound key [OK])
   • Distribution équilibrée (satisfait: ~25% par shard [OK])
```

---

### Justifications à connaître

**Q: Pourquoi une compound shard key { authorId, publishDate } ?**

```
R: 
• Cardinalité élevée (180 auteurs × dates multiples)
• Distribution uniforme des articles
• Queries fréquentes "articles par auteur" sont targeted (rapides)
• Permet range queries "articles récents d'un auteur"
• Évite les hot shards (pas de monotonie)
```

**Q: Pourquoi 3 membres par Replica Set ?**

```
R:
• Minimum pour garantir le quorum (2/3)
• Tolère la perte d'1 membre
• Failover automatique
• Un seul arbiter pour économiser ressources
```

**Q: Que se passe-t-il si une machine tombe ?**

```
R:
• Replica Sets: Election automatique d'un nouveau PRIMARY
• Config Servers: Quorum maintenu avec 2/3 membres
• Shards: Données répliquées, aucune perte
• mongos: Peut être redémarré ailleurs
• Résultat: Cluster reste opérationnel [OK]
```

---

## [TROPHEE] CONCLUSION

**Tu as maintenant :**

[OK] Une architecture MongoDB Sharding complète et opérationnelle
[OK] 4 shards en haute disponibilité
[OK] Config Servers redondants
[OK] mongos (Query Router) fonctionnel
[OK] Base "blog" avec 3800 articles distribués
[OK] Résilience face aux pannes démontrée
[OK] Tous les critères de l'examen satisfaits

**[BRAVO] EXAMEN RÉUSSI ! [BRAVO]**

---

**Bon courage pour ton examen ! [RAPIDE]**