Je vais créer un guide ultra-détaillé sur le sharding MongoDB, en suivant la même structure exceptionnelle que le guide sur les Replica Sets.

Je vais commencer par lire les skills disponibles pour m'assurer de suivre les meilleures pratiques.

Excellent ! Je vais maintenant créer un guide complet sur le sharding MongoDB, structuré en plusieurs parties comme le guide Replica Set. Commençons par la Partie 1.

# [COURS] GUIDE MONGODB SHARDING - PARTIE 1

## [DOCS] INTRODUCTION ET CONCEPTS FONDAMENTAUXF

### * BIENVENUE DANS LE MONDE DU SHARDING MONGODB !

Ce guide est conçu pour un **étudiant en génie logiciel débutant** qui veut comprendre **TOUT** sur le Sharding MongoDB, de A à Z.

**Promesse de ce guide :**
[OK] Tu n'auras PLUS BESOIN de chercher ailleurs
[OK] Chaque concept est expliqué avec le POURQUOI et le COMMENT
[OK] Des exemples concrets à chaque étape
[OK] Des exercices pratiques pour consolider
[OK] Des scripts d'automatisation prêts à l'emploi
[OK] Configuration 2 machines physiques complète

---

## [REFLEXION] QU'EST-CE QUE LE SHARDING ?

### Définition simple

**Sharding** = Technique de partitionnement horizontal des données sur plusieurs machines

**Traduction en langage simple :**
Au lieu de stocker TOUTES tes données sur UN SEUL serveur, MongoDB les **découpe et répartit** sur PLUSIEURS serveurs.

**Analogie de la bibliothèque :**

```
SANS Sharding (Base de données classique)
═══════════════════════════════════════════════════════

┌─────────────────────────────────────────────────────┐
│          UNE SEULE BIBLIOTHÈQUE                     │
│                                                     │
│  [DOCS] TOUS les livres (1 million)                     │
│  [GUIDE] Livres A-Z                                      │
│  [LIVRE] Fiction + Non-fiction                           │
│  [LIVRE] Français + Anglais                              │
│  [LIVRE] Anciens + Nouveaux                              │
│                                                     │
│  Problèmes:                                         │
│  [LENT] Recherche lente (chercher parmi 1M livres)     │
│  [SAUVEGARDE] Espace limité (bâtiment plein)                 │
│  [UTILISATEURS] Files d'attente (trop de visiteurs)            │
│  [HOT] Point de défaillance unique                    │
│                                                     │
└─────────────────────────────────────────────────────┘


AVEC Sharding (Distribution intelligente)
═══════════════════════════════════════════════════════

┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│  BIBLIOTHÈQUE 1 │  │  BIBLIOTHÈQUE 2 │  │  BIBLIOTHÈQUE 3 │
│  (Shard 1)      │  │  (Shard 2)      │  │  (Shard 3)      │
├─────────────────┤  ├─────────────────┤  ├─────────────────┤
│  [DOCS] A-H         │  │  [DOCS] I-P         │  │  [DOCS] Q-Z         │
│  (333K livres)  │  │  (333K livres)  │  │  (334K livres)  │
│                 │  │                 │  │                 │
│  [RECHERCHE] Recherche   │  │  [RECHERCHE] Recherche   │  │  [RECHERCHE] Recherche   │
│     rapide      │  │     rapide      │  │     rapide      │
│  [UTILISATEURS] Moins de    │  │  [UTILISATEURS] Moins de    │  │  [UTILISATEURS] Moins de    │
│     monde       │  │     monde       │  │     monde       │
└─────────────────┘  └─────────────────┘  └─────────────────┘
         ^                   ^                   ^
         └───────────────────┼───────────────────┘
                             │
                    ┌────────[BLACK_DOWN-POINTING_TRIANGLE]─────────┐
                    │   BIBLIOTHÉCAIRE │
                    │   (mongos)       │
                    │                  │
                    │ "Livre 'MongoDB' │
                    │  -> Bibliothèque 2"│
                    └──────────────────┘

Avantages:
[OK] Recherche 3× plus rapide (moins de livres par site)
[OK] Capacité × 3 (3 bâtiments au lieu d'1)
[OK] Moins d'attente (charge répartie)
[OK] Si une bibliothèque ferme, les 2 autres restent ouvertes
```

**En termes MongoDB :**

```
Collection "users" avec 10 millions de documents

SANS Sharding:
┌─────────────────────────────────────┐
│  UN SEUL SERVEUR                    │
│  └─ 10 000 000 documents            │
│     └─ Limite: Capacité 1 machine   │
└─────────────────────────────────────┘

AVEC Sharding (3 shards):
┌───────────┐  ┌───────────┐  ┌───────────┐
│  Shard 1  │  │  Shard 2  │  │  Shard 3  │
│  3.3M docs│  │  3.3M docs│  │  3.4M docs│
└───────────┘  └───────────┘  └───────────┘

Capacité totale = Somme des capacités ! [RAPIDE]
```

---

## [OBJECTIF] POURQUOI UTILISER LE SHARDING ?

### 1⃣ SCALABILITÉ HORIZONTALE

**Problème : Limites d'une machine unique**

```
Une machine a des LIMITES PHYSIQUES:

┌─────────────────────────────────────────────────────┐
│  SERVEUR MONGODB UNIQUE                             │
├─────────────────────────────────────────────────────┤
│  CPU: 64 cœurs (maximum pratique)                   │
│  RAM: 1 TB (maximum pratique)                       │
│  Disque: 100 TB SSD (très coûteux)                  │
│                                                     │
│  Mais que faire si tu as besoin de:                 │
│  • 500 TB de données ?                              │
│  • 100 000 requêtes/seconde ?                       │
│  • 500 TB RAM pour tout mettre en cache ?           │
│                                                     │
│  IMPOSSIBLE avec UNE machine ! [X]                    │
└─────────────────────────────────────────────────────┘

Coûts:
[HAUSSE] CPU: 1 000$ -> 10 000$ (croissance exponentielle)
[HAUSSE] RAM: 1 000$ -> 50 000$ (très cher au-delà de 256GB)
[HAUSSE] SSD: 10 000$ -> 100 000$ (coût prohibitif)

Scaling Vertical (augmenter la puissance d'1 machine):
[ARGENT] Coût exponentiellement croissant
[ALARM_CLOCK] Limite physique atteinte rapidement
[OUTIL] Maintenance complexe (downtime pour upgrade)
```

**Solution : Sharding (Scaling Horizontal)**

```
┌───────────────┐  ┌───────────────┐  ┌───────────────┐
│  Machine 1    │  │  Machine 2    │  │  Machine 3    │
│  16 cœurs     │  │  16 cœurs     │  │  16 cœurs     │
│  64 GB RAM    │  │  64 GB RAM    │  │  64 GB RAM    │
│  10 TB SSD    │  │  10 TB SSD    │  │  10 TB SSD    │
│  Coût: 5 000$ │  │  Coût: 5 000$ │  │  Coût: 5 000$ │
└───────────────┘  └───────────────┘  └───────────────┘

TOTAL:
CPU: 48 cœurs (3× plus)
RAM: 192 GB (3× plus)
Disque: 30 TB (3× plus)
Coût: 15 000$ (vs 100 000$+ pour équivalent vertical)

Avantages:
[OK] Coût linéaire (double de machines = double de capacité)
[OK] Pas de limite théorique (ajoute autant de machines que nécessaire)
[OK] Maintenance facile (une machine à la fois)
[OK] Croissance progressive (ajoute des shards au fil du temps)
```

**Exemple concret : Instagram**

```
2010: 1 serveur PostgreSQL
      v Croissance utilisateurs
2011: PostgreSQL à la limite
      v Migration vers sharding
2012: 12 shards MongoDB
      v Croissance explosive
2023: 1000+ shards
      2+ milliards d'utilisateurs
      100+ To de photos/jour

Sans sharding: IMPOSSIBLE à gérer avec une BD unique
```

---

### 2⃣ PERFORMANCE : LECTURE ET ÉCRITURE

**Sans Sharding : Goulot d'étranglement**

```
Application avec 100 000 requêtes/seconde
              v
        ┌─────────────┐
        │  1 SERVEUR  │
        │  MongoDB    │
        └─────────────┘
              v
    Limite: 10 000 req/s
              v
    90 000 requêtes en file d'attente
              v
    Temps de réponse: 5-10 secondes
              v
    Utilisateurs mécontents [X]
```

**Avec Sharding : Charge distribuée**

```
Application avec 100 000 requêtes/seconde
              v
        ┌─────────────┐
        │   MONGOS    │
        │  (Routeur)  │
        └─────────────┘
              v Distribution intelligente
    ┌─────────┼─────────┐
    v         v         v
┌───────┐ ┌───────┐ ┌───────┐
│Shard 1│ │Shard 2│ │Shard 3│
│33K r/s│ │33K r/s│ │34K r/s│
└───────┘ └───────┘ └───────┘
    v         v         v
Chaque shard: < 50% capacité
    v
Temps de réponse: 50-100ms
    v
Utilisateurs satisfaits [OK]
```

**Métriques réelles :**

| Configuration | Requêtes/sec | Latence | Coût |
|---------------|-------------|---------|------|
| **1 serveur puissant** | 10 000 | 500ms | 50 000$ |
| **3 shards moyens** | 30 000 | 100ms | 15 000$ |
| **10 shards moyens** | 100 000 | 50ms | 50 000$ |

**ROI évident : Plus de performance pour le même budget !**

---

### 3⃣ LOCALISATION GÉOGRAPHIQUE

**Problème : Latence réseau**

```
Utilisateurs mondiaux accédant à 1 serveur aux USA

┌──────────────┐              ┌──────────────┐
│ Utilisateur  │              │  Serveur     │
│ FRANCE       │─────300ms────│  USA         │
└──────────────┘              └──────────────┘

┌──────────────┐              ┌──────────────┐
│ Utilisateur  │              │  Serveur     │
│ AUSTRALIE    │─────400ms────│  USA         │
└──────────────┘              └──────────────┘

Latence réseau = 300-400ms
Temps de réponse application = 500-800ms
Expérience utilisateur = Médiocre [DISAPPOINTED_FACE]
```

**Solution : Sharding géographique (Zone Sharding)**

```
┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│ Utilisateurs│         │ Utilisateurs│         │ Utilisateurs│
│ EUROPE      │         │ ASIE        │         │ AMÉRIQUE    │
└──────┬──────┘         └──────┬──────┘         └──────┬──────┘
       │ 20ms                  │ 20ms                  │ 20ms
       v                       v                       v
┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│  Shard EU   │         │ Shard ASIA  │         │  Shard USA  │
│  FRANCE     │         │  SINGAPORE  │         │  NEW YORK   │
│             │         │             │         │             │
│ Données EU  │         │ Données ASIA│         │ Données USA │
└─────────────┘         └─────────────┘         └─────────────┘

Latence réseau = 20-50ms (10× plus rapide !)
Conformité RGPD = Données EU restent en EU [OK]
```

**Cas d'usage réel : Application de chat mondiale**

```
users collection shardée par "region":

{
  _id: ObjectId("..."),
  username: "alice",
  region: "EU",  <- Shard key
  messages: [...]
}

-> Données d'Alice stockées sur Shard EU
-> Requêtes depuis l'Europe -> Shard EU (rapide)
-> Conformité RGPD automatique
```

---

### 4⃣ ISOLATION DES CHARGES (WORKLOAD ISOLATION)

**Problème : Différents types de charges**

```
Application e-commerce:

┌─────────────────────────────────────────────────┐
│  UN SEUL CLUSTER                                │
├─────────────────────────────────────────────────┤
│                                                 │
│  Trafic clients (lecture produits):             │
│  └─ 90% des requêtes                            │
│  └─ Requêtes légères (100ms)                    │
│                                                 │
│  Analytics (calculs complexes):                 │
│  └─ 10% des requêtes                            │
│  └─ Requêtes LOURDES (30 secondes)              │
│                                                 │
│  PROBLÈME:                                      │
│  Les analytics ralentissent les clients ! [X]    │
│                                                 │
└─────────────────────────────────────────────────┘
```

**Solution : Sharding avec isolation**

```
┌──────────────────┐          ┌──────────────────┐
│  Shard 1 & 2     │          │  Shard 3         │
│  CLIENTS         │          │  ANALYTICS       │
├──────────────────┤          ├──────────────────┤
│                  │          │                  │
│  Produits        │          │  Rapports        │
│  Commandes       │          │  Statistiques    │
│  Panier          │          │  Data Mining     │
│                  │          │                  │
│  Rapide [RAPIDE]       │          │  Lent [LENT]         │
│  90% requêtes    │          │  10% requêtes    │
│                  │          │                  │
└──────────────────┘          └──────────────────┘
         v                            v
  Clients satisfaits          Analytics sans impact
```

**Configuration avec Zones :**

```javascript
// Définir des zones
sh.addShardToZone("shard1", "clients")
sh.addShardToZone("shard2", "clients")
sh.addShardToZone("shard3", "analytics")

// Router les données
sh.updateZoneKeyRange(
  "ecommerce.products",
  { type: "client" }, { type: "client" },
  "clients"
)

sh.updateZoneKeyRange(
  "ecommerce.analytics",
  { type: "report" }, { type: "report" },
  "analytics"
)
```

---

### 5⃣ DISPONIBILITÉ ET RÉSILIENCE

**Sharding + Replica Sets = Maximum Availability**

```
Configuration: 3 Shards, chacun avec Replica Set (3 membres)

┌─────────────────────────────────────────────────────┐
│  SHARD 1 (Replica Set)                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐          │
│  │ PRIMARY  │  │SECONDARY │  │SECONDARY │          │
│  │ Machine1 │  │ Machine2 │  │ Machine3 │          │
│  └──────────┘  └──────────┘  └──────────┘          │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│  SHARD 2 (Replica Set)                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐          │
│  │ PRIMARY  │  │SECONDARY │  │SECONDARY │          │
│  │ Machine4 │  │ Machine5 │  │ Machine6 │          │
│  └──────────┘  └──────────┘  └──────────┘          │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│  SHARD 3 (Replica Set)                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐          │
│  │ PRIMARY  │  │SECONDARY │  │SECONDARY │          │
│  │ Machine7 │  │ Machine8 │  │ Machine9 │          │
│  └──────────┘  └──────────┘  └──────────┘          │
└─────────────────────────────────────────────────────┘

RÉSILIENCE:
• Shard 1 PRIMARY down -> SECONDARY prend le relais (10s)
• Shard 1 ENTIER down -> Shards 2 & 3 continuent (66% de données accessibles)
• Multi-datacenter -> Survivre à la perte d'un datacenter complet !

Temps d'arrêt = QUASI ZERO [OBJECTIF]
```

---

## [CONSTRUCTION] ARCHITECTURE D'UN CLUSTER SHARDÉ

### Composants principaux

```
┌─────────────────────────────────────────────────────────┐
│           APPLICATION                                    │
└────────────────┬────────────────────────────────────────┘
                 │
                 │ Connexion
                 v
┌─────────────────────────────────────────────────────────┐
│           MONGOS (Query Router)                          │
│  • Point d'entrée unique                                │
│  • Route les requêtes vers les bons shards              │
│  • Agrège les résultats                                 │
│  • Cache la complexité du sharding                      │
└────────────────┬────────────────────────────────────────┘
                 │
                 │ Consulte métadonnées
                 v
┌─────────────────────────────────────────────────────────┐
│        CONFIG SERVERS (Replica Set)                     │
│  • Stockent les métadonnées du cluster                  │
│  • Quelles données sont sur quel shard ?                │
│  • Configuration du sharding                            │
│  • Toujours un Replica Set (3 membres minimum)          │
└────────────────┬────────────────────────────────────────┘
                 │
                 │ Indique où sont les données
                 v
┌─────────────────────────────────────────────────────────┐
│                    SHARDS                                │
│                                                         │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐         │
│  │ SHARD 1  │    │ SHARD 2  │    │ SHARD 3  │         │
│  │ (RS)     │    │ (RS)     │    │ (RS)     │         │
│  │          │    │          │    │          │         │
│  │ Chunk 1  │    │ Chunk 3  │    │ Chunk 5  │         │
│  │ Chunk 2  │    │ Chunk 4  │    │ Chunk 6  │         │
│  └──────────┘    └──────────┘    └──────────┘         │
│                                                         │
│  Chaque shard = Replica Set (haute disponibilité)      │
└─────────────────────────────────────────────────────────┘
```

---

### 1. MONGOS (Query Router)

**Rôle : Routeur intelligent**

```
┌─────────────────────────────────────────────────────┐
│  MONGOS = Routeur de requêtes                        │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Fonctions:                                         │
│  1. Recevoir requêtes de l'application              │
│  2. Consulter config servers (où sont les données?) │
│  3. Router vers le(s) bon(s) shard(s)               │
│  4. Agréger les résultats                           │
│  5. Retourner à l'application                       │
│                                                     │
│  IMPORTANT:                                         │
│  • Pas de stockage de données                       │
│  • Léger (500 MB RAM suffit)                        │
│  • Peut en avoir plusieurs (load balancing)         │
│  • Application se connecte à mongos (transparent)   │
│                                                     │
└─────────────────────────────────────────────────────┘
```

**Exemple de routing :**

```javascript
// Application envoie cette requête à mongos
db.users.find({ country: "France" })

// Mongos:
// 1. Regarde shard key (supposons: country)
// 2. Consulte config servers
// 3. Découvre: données "France" sur Shard 2
// 4. Envoie requête UNIQUEMENT à Shard 2 (targeted query)
// 5. Retourne résultats à l'application

EFFICACE: Pas besoin d'interroger Shard 1 et 3 ! [OK]


// Requête sans shard key
db.users.find({ age: 25 })

// Mongos:
// 1. Pas de shard key dans la requête
// 2. Doit interroger TOUS les shards (scatter-gather)
// 3. Envoie à Shard 1, 2 et 3
// 4. Agrège les résultats
// 5. Retourne à l'application

MOINS EFFICACE: Tous les shards sollicités [ATTENTION]
```

---

### 2. CONFIG SERVERS

**Rôle : Base de données des métadonnées**

```
┌─────────────────────────────────────────────────────┐
│  CONFIG SERVERS = Cerveau du cluster                │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Stockent:                                          │
│  • Mapping: chunk -> shard                           │
│  • Définition des shard keys                        │
│  • Configuration zones                              │
│  • Historique des migrations                        │
│  • État du cluster                                  │
│                                                     │
│  Exemple de données stockées:                       │
│  {                                                  │
│    collection: "mydb.users",                        │
│    chunk: { min: 0, max: 1000 },                    │
│    shard: "shard1"                                  │
│  }                                                  │
│                                                     │
│  CRITIQUE:                                          │
│  • TOUJOURS un Replica Set (3+ membres)            │
│  • Si config servers down -> Cluster inopérant [X]   │
│  • Backup régulier OBLIGATOIRE                     │
│                                                     │
└─────────────────────────────────────────────────────┘
```

**Exemple de métadonnées :**

```javascript
// Collection shardée
{
  _id: "mydb.users",
  lastmod: ISODate("2024-12-16T10:00:00Z"),
  dropped: false,
  key: { userId: 1 },  // Shard key
  unique: false
}

// Chunks
{
  _id: "mydb.users-userId_MinKey",
  ns: "mydb.users",
  min: { userId: MinKey },
  max: { userId: 1000000 },
  shard: "shard1",
  lastmod: Timestamp(1, 0)
}

{
  _id: "mydb.users-userId_1000000",
  ns: "mydb.users",
  min: { userId: 1000000 },
  max: { userId: 2000000 },
  shard: "shard2",
  lastmod: Timestamp(1, 1)
}
```

---

### 3. SHARDS

**Rôle : Stockage des données**

```
┌─────────────────────────────────────────────────────┐
│  SHARD = Replica Set qui stocke une partie des      │
│          données                                    │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Structure d'un shard:                              │
│                                                     │
│  ┌──────────────────────────────────────────┐      │
│  │  SHARD 1 (Replica Set "rs-shard1")      │      │
│  ├──────────────────────────────────────────┤      │
│  │                                          │      │
│  │  PRIMARY   : Machine A (192.168.1.10)    │      │
│  │  SECONDARY : Machine B (192.168.1.11)    │      │
│  │  SECONDARY : Machine C (192.168.1.12)    │      │
│  │                                          │      │
│  │  Stocke: Chunks 1, 2, 5, 8               │      │
│  │  Taille: 333 GB                          │      │
│  │                                          │      │
│  └──────────────────────────────────────────┘      │
│                                                     │
│  Pourquoi Replica Set ?                             │
│  • Haute disponibilité (failover auto)              │
│  • Redondance des données                           │
│  • Scalabilité lecture                              │
│                                                     │
│  Un shard peut être:                                │
│  • Replica Set (RECOMMANDÉ) [OK]                      │
│  • Standalone (DÉCONSEILLÉ en prod) [X]              │
│                                                     │
└─────────────────────────────────────────────────────┘
```

---

### 4. CHUNKS

**Concept : Unité de distribution des données**

```
┌─────────────────────────────────────────────────────┐
│  CHUNK = Sous-ensemble continu de documents         │
│          basé sur la shard key                      │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Collection users (10M documents)                   │
│  Shard key: { userId: 1 }                           │
│                                                     │
│  MongoDB découpe en chunks:                         │
│                                                     │
│  Chunk 1: userId [MinKey -> 1000000)    -> Shard 1   │
│  Chunk 2: userId [1000000 -> 2000000)   -> Shard 2   │
│  Chunk 3: userId [2000000 -> 3000000)   -> Shard 3   │
│  Chunk 4: userId [3000000 -> 4000000)   -> Shard 1   │
│  Chunk 5: userId [4000000 -> 5000000)   -> Shard 2   │
│  Chunk 6: userId [5000000 -> MaxKey]    -> Shard 3   │
│                                                     │
│  Taille par défaut: 64 MB (configurable)           │
│                                                     │
│  Balancing automatique:                             │
│  • Si Shard 1 a trop de chunks -> Migration auto    │
│  • Équilibrage en arrière-plan                     │
│  • Pas d'interruption de service                   │
│                                                     │
└─────────────────────────────────────────────────────┘
```

**Visualisation :**

```
users collection shardée par userId

┌─────────────────────────────────────────────────────┐
│                    TIMELINE                          │
├─────────────────────────────────────────────────────┤
│                                                     │
│  MinKey    1M      2M      3M      4M      5M  MaxKey│
│    │───────│───────│───────│───────│───────│────│  │
│    └──┬────┘       └──┬────┘       └──┬────┘    │  │
│       │               │               │         │  │
│    Chunk 1         Chunk 3         Chunk 5      │  │
│    Shard 1         Shard 3         Shard 2      │  │
│                                                     │
└─────────────────────────────────────────────────────┘

Requête: db.users.find({ userId: 1500000 })
-> mongos sait: 1500000 est dans Chunk 2 (1M-2M)
-> Route vers Shard 2 uniquement
-> Efficace ! [OK]
```

---

## [CLE] SHARD KEY : LE CONCEPT LE PLUS IMPORTANT

### Qu'est-ce qu'une Shard Key ?

```
┌─────────────────────────────────────────────────────┐
│  SHARD KEY = Champ(s) qui détermine(nt)             │
│              comment les données sont distribuées    │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Analogie du tri postal:                            │
│                                                     │
│  Sans shard key:                                    │
│  • Lettres envoyées aléatoirement                   │
│  • Désorganisation totale                           │
│  • Impossible de retrouver une lettre               │
│                                                     │
│  Avec shard key (code postal):                      │
│  • Lettre 75001 -> Bureau Paris                      │
│  • Lettre 69001 -> Bureau Lyon                       │
│  • Organisation claire                              │
│  • Recherche rapide                                 │
│                                                     │
└─────────────────────────────────────────────────────┘
```

### Caractéristiques d'une bonne Shard Key

#### [OK] CARDINALITÉ ÉLEVÉE (High Cardinality)

```
MAUVAIS EXEMPLE: genre ("homme" | "femme")
┌────────────────┐  ┌────────────────┐
│  Shard 1       │  │  Shard 2       │
│  genre: homme  │  │  genre: femme  │
│  50% données   │  │  50% données   │
└────────────────┘  └────────────────┘
│
└─ Problème: Seulement 2 valeurs possibles
   • Impossible d'ajouter un 3ème shard !
   • Pas de distribution fine
   • Scalabilité limitée [X]


BON EXEMPLE: userId (millions de valeurs)
┌────────┐  ┌────────┐  ┌────────┐  ┌────────┐
│ Shard 1│  │ Shard 2│  │ Shard 3│  │ Shard 4│
│userId: │  │userId: │  │userId: │  │userId: │
│0-250K  │  │250K-500│  │500K-750│  │750K-1M │
└────────┘  └────────┘  └────────┘  └────────┘
│
└─ Avantages:
   • Millions de valeurs possibles
   • Distribution fine
   • Scalabilité illimitée [OK]
```

#### [OK] DISTRIBUTION UNIFORME (Even Distribution)

```
MAUVAIS: createdAt (avec croissance temporelle)

Janvier 2024: 1000 docs -> Shard 1
Février 2024: 1000 docs -> Shard 1 (même chunk)
Mars 2024: 1000 docs -> Shard 1 (toujours même chunk)
...
Décembre 2024: 1000 docs -> Shard 1 (encore!)

Résultat:
┌────────────┐  ┌────────┐  ┌────────┐
│  Shard 1   │  │ Shard 2│  │ Shard 3│
│            │  │        │  │        │
│  12 000    │  │   0    │  │   0    │
│  docs      │  │  docs  │  │  docs  │
│            │  │        │  │        │
│  HOT SHARD │  │  IDLE  │  │  IDLE  │
│  (surchargé│  │        │  │        │
└────────────┘  └────────┘  └────────┘

Problème: Écriture toujours sur Shard 1 (hot shard) [X]


BON: { userId: 1, createdAt: 1 } (composé)

Utilisateur A crée -> Shard 1
Utilisateur B crée -> Shard 2
Utilisateur C crée -> Shard 3
Utilisateur A crée à nouveau -> Shard 1
Utilisateur D crée -> Shard 1
...

Résultat:
┌────────────┐  ┌────────────┐  ┌────────────┐
│  Shard 1   │  │  Shard 2   │  │  Shard 3   │
│            │  │            │  │            │
│  4 000     │  │  4 000     │  │  4 000     │
│  docs      │  │  docs      │  │  docs      │
│            │  │            │  │            │
│  ÉQUILIBRÉ │  │  ÉQUILIBRÉ │  │  ÉQUILIBRÉ │
└────────────┘  └────────────────────────────┘

Avantage: Distribution uniforme [OK]
```

#### [OK] FRÉQUENCE DES REQUÊTES (Query Isolation)

```
MAUVAIS: email (rarement utilisé dans les requêtes)

90% des requêtes:
db.users.find({ userId: 123 })  <- PAS la shard key !

Conséquence:
-> mongos doit interroger TOUS les shards (scatter-gather)
-> Lent [X]


BON: userId (utilisé dans 90% des requêtes)

90% des requêtes:
db.users.find({ userId: 123 })  <- C'EST la shard key !

Conséquence:
-> mongos interroge UNIQUEMENT le shard concerné (targeted)
-> Rapide [OK]
```

#### [OK] ÉVITER LES MONOTONIES (Avoid Monotonically Increasing)

```
MAUVAIS: _id (ObjectId) ou auto-incrémenté

_id: ObjectId("...00001")  -> Chunk 1 -> Shard 1
_id: ObjectId("...00002")  -> Chunk 1 -> Shard 1 (même chunk)
_id: ObjectId("...00003")  -> Chunk 1 -> Shard 1 (encore)
...

Résultat:
• TOUTES les insertions vont sur le même chunk
• Ce chunk est toujours sur le même shard
• Hot shard (surcharge) [X]
• Autres shards inutilisés


BON: Hashed _id

_id: ObjectId("...00001")  -> hash() -> Shard 2
_id: ObjectId("...00002")  -> hash() -> Shard 1
_id: ObjectId("...00003")  -> hash() -> Shard 3
...

Résultat:
• Insertions distribuées uniformément
• Tous les shards utilisés
• Pas de hot shard [OK]
```

---

### Types de Shard Keys

#### 1. RANGED SHARD KEY

```javascript
// Exemple
sh.shardCollection("mydb.users", { userId: 1 })

// Distribution par plages
userId: 0-1000000     -> Shard 1
userId: 1000000-2000000 -> Shard 2
userId: 2000000-3000000 -> Shard 3
```

**Avantages :**
[OK] Range queries efficaces : `db.users.find({ userId: { $gt: 500000, $lt: 1500000 } })`
[OK] Groupements logiques (même plage = même shard)

**Inconvénients :**
[X] Risque de hot shards si données non uniformes
[X] Pas adapté aux valeurs monotones

**Cas d'usage :**
- Données géographiques (latitude/longitude)
- Dates avec distribution connue uniforme
- IDs custom avec bonne distribution

---

#### 2. HASHED SHARD KEY

```javascript
// Exemple
sh.shardCollection("mydb.users", { _id: "hashed" })

// Distribution par hash
_id: ObjectId("...")  -> hash: 123456  -> Shard 1
_id: ObjectId("...")  -> hash: 789012  -> Shard 3
_id: ObjectId("...")  -> hash: 345678  -> Shard 2
```

**Avantages :**
[OK] Distribution TOUJOURS uniforme (garanti par le hash)
[OK] Pas de hot shards
[OK] Fonctionne avec valeurs monotones

**Inconvénients :**
[X] Range queries impossibles (hash détruit l'ordre)
[X] Pas de groupements logiques

**Cas d'usage :**
- _id par défaut
- Insertions à fort volume
- Pas de besoin de range queries

---

#### 3. COMPOUND SHARD KEY (Composé)

```javascript
// Exemple
sh.shardCollection("mydb.orders", { userId: 1, orderDate: 1 })

// Distribution par combinaison
{ userId: 123, orderDate: 2024-01 }  -> Shard 1
{ userId: 456, orderDate: 2024-01 }  -> Shard 2
{ userId: 123, orderDate: 2024-02 }  -> Shard 1 (même user)
```

**Avantages :**
[OK] Combine cardinalité + distribution
[OK] Queries multi-critères efficaces
[OK] Évite hot shards sur timestamp

**Inconvénients :**
[X] Plus complexe
[X] Toutes les queries doivent inclure le préfixe de la clé

**Cas d'usage :**
- Logs : `{ appId: 1, timestamp: 1 }`
- E-commerce : `{ userId: 1, orderDate: 1 }`
- Multi-tenant : `{ tenantId: 1, userId: 1 }`

---

## [GRAPHIQUE] COMPARAISON : REPLICA SET vs SHARDING

| Critère | Replica Set | Sharding (+ Replica Sets) |
|---------|-------------|---------------------------|
| **Objectif** | Haute disponibilité | Scalabilité horizontale |
| **Données** | Même données sur tous les membres | Données réparties |
| **Capacité** | Limitée à 1 machine | Illimitée (somme des shards) |
| **Performance lecture** | Scalable (N×) | Très scalable (N×M) |
| **Performance écriture** | 1× (PRIMARY seul) | N× (N shards) |
| **Complexité** | ** Moyenne | **** Élevée |
| **Coût** | [ARGENT][ARGENT] Moyen | [ARGENT][ARGENT][ARGENT][ARGENT] Élevé |
| **Use case** | Disponibilité, redondance | Gros volumes, haute performance |
| **Configuration minimale** | 3 membres | 2 shards (RS) + 3 config (RS) + 1 mongos = 7+ machines |

---

## [OBJECTIF] QUAND UTILISER LE SHARDING ?

### [OK] UTILISE LE SHARDING SI :

**1. Volume de données important :**
```
[OK] > 500 GB de données actives
[OK] Croissance rapide (TB/mois)
[OK] Projection dépassant capacité d'une machine
```

**2. Performance insuffisante :**
```
[OK] > 10 000 requêtes/seconde
[OK] Latence élevée (> 100ms)
[OK] CPU/RAM/IO saturés sur le serveur
```

**3. Distribution géographique :**
```
[OK] Utilisateurs mondiaux
[OK] Conformité réglementaire (RGPD)
[OK] Latence réseau importante
```

**4. Isolation de charges :**
```
[OK] Analytics impactant la production
[OK] Différents types de clients (free/premium)
[OK] Multi-tenant avec isolation
```

---

### [X] N'UTILISE PAS LE SHARDING SI :

**1. Petit volume :**
```
[X] < 100 GB de données
[X] Croissance lente
[X] Un Replica Set suffit largement
```

**2. Complexité non justifiée :**
```
[X] Équipe petite (< 5 personnes)
[X] Pas de compétences ops avancées
[X] Budget limité
```

**3. Requêtes incompatibles :**
```
[X] Beaucoup de queries sans shard key
[X] Transactions multi-documents fréquentes sur plusieurs shards
[X] Joins complexes
```

**Règle d'or :**
```
Development : Standalone
Staging : Replica Set (3 membres)
Production (PME) : Replica Set (5 membres)
Production (Scale) : Sharding (2+ shards en Replica Set)
```

---

## [LISTE] RÉCAPITULATIF PARTIE 1

**Ce que tu as appris :**

[OK] **Sharding** = Distribution horizontale des données sur plusieurs machines
[OK] **Composants** :
   - mongos (routeur)
   - Config Servers (métadonnées)
   - Shards (stockage en Replica Sets)
   - Chunks (unités de distribution)

[OK] **Shard Key** = Clé qui détermine la distribution
   - Cardinalité élevée
   - Distribution uniforme
   - Fréquence de requêtes
   - Éviter monotonie

[OK] **Avantages** :
   - Scalabilité illimitée
   - Performance × N
   - Distribution géographique
   - Isolation charges

[OK] **Quand utiliser** :
   - Gros volumes (> 500 GB)
   - Haute performance requise
   - Distribution mondiale

---

## [OBJECTIF] PROCHAINES PARTIES

**PARTIE 2 : Installation et configuration réseau**
- Prérequis matériels (2 machines)
- Mise en réseau des machines
- Installation MongoDB sur chaque machine
- Préparation de l'environnement

**PARTIE 3 : Configuration du cluster shardé**
- Config Servers (Replica Set)
- Shards (Replica Sets)
- mongos (routeurs)
- Initialisation du cluster

**PARTIE 4 : Sharding des collections**
- Choix de la shard key
- Activation du sharding
- Tests et validation
- Monitoring

**PARTIE 5 : Opérations avancées**
- Balancing
- Zones
- Migrations
- Ajout/Suppression de shards

**PARTIE 6 : Production et optimisation**
- Sécurité
- Backup
- Monitoring
- Performance tuning

**[RAPIDE] Prêt pour la PARTIE 2 ? ->**

J'ai créé la Partie 1 du guide MongoDB Sharding. Voulez-vous que je continue avec les parties suivantes ? Je vais créer chaque partie dans des artifacts séparés pour une meilleure organisation.


Parfait ! Je vais continuer avec la Partie 2 en utilisant une configuration à 4 machines physiques. Cela permettra une architecture plus robuste et réaliste.

# [COURS] GUIDE MONGODB SHARDING - PARTIE 2

## [PACKAGE] INSTALLATION ET CONFIGURATION RÉSEAU (4 MACHINES)

### [OBJECTIF] OBJECTIF DE CETTE PARTIE

À la fin de cette partie, tu auras :
[OK] 4 machines physiques configurées et en réseau
[OK] MongoDB installé sur les 4 machines
[OK] Connectivité réseau vérifiée
[OK] Pare-feu configuré correctement
[OK] Prêt pour la configuration du cluster shardé

**[TEMPS] Durée estimée : 1h30 - 2h**

---

## [ECRAN] PRÉREQUIS MATÉRIELS (4 MACHINES)

### Architecture à 4 machines (Configuration recommandée)

```
┌─────────────────────────────────────────────────────────────────┐
│                    CLUSTER SHARDÉ (4 MACHINES)                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  MACHINE 1 (Config Server + mongos + Shard 1 PRIMARY)    │  │
│  │  IP: 192.168.1.10                                         │  │
│  │  Rôles:                                                   │  │
│  │  • Config Server RS membre 1 (port 27019)                │  │
│  │  • mongos routeur (port 27017)                           │  │
│  │  • Shard 1 PRIMARY (port 27018)                          │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  MACHINE 2 (Config Server + Shard 1 SECONDARY)           │  │
│  │  IP: 192.168.1.20                                         │  │
│  │  Rôles:                                                   │  │
│  │  • Config Server RS membre 2 (port 27019)                │  │
│  │  • Shard 1 SECONDARY (port 27018)                        │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  MACHINE 3 (Config Server + Shard 2 PRIMARY)             │  │
│  │  IP: 192.168.1.30                                         │  │
│  │  Rôles:                                                   │  │
│  │  • Config Server RS membre 3 (port 27019)                │  │
│  │  • Shard 2 PRIMARY (port 27018)                          │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  MACHINE 4 (Shard 2 SECONDARY + Shard 1 ARBITER)         │  │
│  │  IP: 192.168.1.40                                         │  │
│  │  Rôles:                                                   │  │
│  │  • Shard 2 SECONDARY (port 27018)                        │  │
│  │  • Shard 1 ARBITER (port 27020)                          │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RÉSUMÉ:
• Config Servers: Replica Set à 3 membres (Machines 1, 2, 3)
• Shard 1: Replica Set (PRIMARY sur M1, SECONDARY sur M2, ARBITER sur M4)
• Shard 2: Replica Set (PRIMARY sur M3, SECONDARY sur M4)
• mongos: Machine 1 (peut être dupliqué sur M2 et M3 pour HA)

PORTS UTILISÉS:
• 27017: mongos (routeur - applications se connectent ici)
• 27018: Shards (stockage des données)
• 27019: Config Servers (métadonnées)
• 27020: Arbiter Shard 1
```

**[IDEE] Pourquoi cette architecture ?**

```
[OK] Optimise l'utilisation de 4 machines
[OK] Config Servers en HA (3 membres sur M1, M2, M3)
[OK] 2 Shards complets avec redondance
[OK] Pas de machine inutilisée
[OK] Balance bien la charge
[OK] Production-ready avec 4 machines seulement
```

---

### Spécifications matérielles par machine

#### Configuration MINIMALE (Développement/Test)

| Composant | Machine 1 | Machine 2 | Machine 3 | Machine 4 |
|-----------|-----------|-----------|-----------|-----------|
| **CPU** | 4 cœurs | 2 cœurs | 4 cœurs | 2 cœurs |
| **RAM** | 8 GB | 4 GB | 8 GB | 4 GB |
| **Disque** | 100 GB SSD | 50 GB | 100 GB SSD | 50 GB |
| **Réseau** | 1 Gbps | 1 Gbps | 1 Gbps | 1 Gbps |
| **OS** | Ubuntu 22.04 | Ubuntu 22.04 | Ubuntu 22.04 | Ubuntu 22.04 |

**Total minimal : ~20 CPU cœurs, 24 GB RAM, 300 GB stockage**

---

#### Configuration RECOMMANDÉE (Production PME)

| Composant | Machine 1 | Machine 2 | Machine 3 | Machine 4 |
|-----------|-----------|-----------|-----------|-----------|
| **CPU** | 8 cœurs | 4 cœurs | 8 cœurs | 4 cœurs |
| **RAM** | 16 GB | 8 GB | 16 GB | 8 GB |
| **Disque** | 500 GB NVMe | 250 GB SSD | 500 GB NVMe | 250 GB SSD |
| **Réseau** | 10 Gbps | 10 Gbps | 10 Gbps | 10 Gbps |
| **OS** | Ubuntu 22.04 | Ubuntu 22.04 | Ubuntu 22.04 | Ubuntu 22.04 |

**Total recommandé : ~24 CPU cœurs, 48 GB RAM, 1.5 TB stockage**

---

#### Configuration IDÉALE (Production Entreprise)

| Composant | Machine 1 | Machine 2 | Machine 3 | Machine 4 |
|-----------|-----------|-----------|-----------|-----------|
| **CPU** | 16 cœurs | 8 cœurs | 16 cœurs | 8 cœurs |
| **RAM** | 32 GB | 16 GB | 32 GB | 16 GB |
| **Disque** | 2 TB NVMe RAID | 1 TB NVMe | 2 TB NVMe RAID | 1 TB NVMe |
| **Réseau** | 10 Gbps + Bonding | 10 Gbps | 10 Gbps + Bonding | 10 Gbps |
| **OS** | Ubuntu 22.04 LTS | Ubuntu 22.04 LTS | Ubuntu 22.04 LTS | Ubuntu 22.04 LTS |

**Total idéal : ~48 CPU cœurs, 96 GB RAM, 6 TB stockage**

---

### Répartition des rôles détaillée

```
╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 1 (192.168.1.10)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27017: mongos (Query Router)                           ║
║  └─ Rôle: Point d'entrée pour les applications               ║
║  └─ RAM: ~500 MB                                              ║
║  └─ CPU: Léger (routage uniquement)                           ║
║                                                               ║
║  PORT 27018: Shard 1 - PRIMARY                                ║
║  └─ Rôle: Stockage données Shard 1                            ║
║  └─ RAM: ~3-6 GB (dépend du dataset)                          ║
║  └─ CPU: Moyen (queries + réplication)                        ║
║                                                               ║
║  PORT 27019: Config Server RS - Membre 1                      ║
║  └─ Rôle: Métadonnées du cluster                              ║
║  └─ RAM: ~500 MB                                              ║
║  └─ CPU: Léger (peu de requêtes)                              ║
║                                                               ║
║  CHARGE TOTALE: ~4-7 GB RAM, CPU moyen                        ║
╚═══════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 2 (192.168.1.20)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27018: Shard 1 - SECONDARY                              ║
║  └─ Rôle: Réplication Shard 1                                 ║
║  └─ RAM: ~3-6 GB                                              ║
║  └─ CPU: Moyen (réplication + lectures possibles)             ║
║                                                               ║
║  PORT 27019: Config Server RS - Membre 2                      ║
║  └─ Rôle: Réplication métadonnées                             ║
║  └─ RAM: ~500 MB                                              ║
║  └─ CPU: Léger                                                ║
║                                                               ║
║  CHARGE TOTALE: ~3.5-6.5 GB RAM, CPU moyen                    ║
╚═══════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 3 (192.168.1.30)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27018: Shard 2 - PRIMARY                                ║
║  └─ Rôle: Stockage données Shard 2                            ║
║  └─ RAM: ~3-6 GB                                              ║
║  └─ CPU: Moyen (queries + réplication)                        ║
║                                                               ║
║  PORT 27019: Config Server RS - Membre 3                      ║
║  └─ Rôle: Réplication métadonnées                             ║
║  └─ RAM: ~500 MB                                              ║
║  └─ CPU: Léger                                                ║
║                                                               ║
║  CHARGE TOTALE: ~3.5-6.5 GB RAM, CPU moyen                    ║
╚═══════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════╗
║                    MACHINE 4 (192.168.1.40)                   ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  PORT 27018: Shard 2 - SECONDARY                              ║
║  └─ Rôle: Réplication Shard 2                                 ║
║  └─ RAM: ~3-6 GB                                              ║
║  └─ CPU: Moyen                                                ║
║                                                               ║
║  PORT 27020: Shard 1 - ARBITER                                ║
║  └─ Rôle: Vote uniquement (pas de données)                    ║
║  └─ RAM: ~50 MB                                               ║
║  └─ CPU: Minimal                                              ║
║                                                               ║
║  CHARGE TOTALE: ~3-6 GB RAM, CPU moyen-léger                  ║
╚═══════════════════════════════════════════════════════════════╝
```

---

## [WEB] MISE EN RÉSEAU DES 4 MACHINES

### Option 1 : Réseau local avec routeur/box (LE PLUS SIMPLE [OK])

**Scénario : Tu as une box internet et 4 ordinateurs**

```
┌────────────────────────────────────────────────────────┐
│              TA BOX INTERNET / ROUTEUR                  │
│              192.168.1.1 (passerelle)                   │
│              Réseau: 192.168.1.0/24                     │
└───────┬──────────┬──────────┬──────────┬───────────────┘
        │          │          │          │
        │ Ethernet │ Ethernet │ Ethernet │ Ethernet
        │ ou WiFi  │ ou WiFi  │ ou WiFi  │ ou WiFi
        v          v          v          v
    ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
    │Machine1│ │Machine2│ │Machine3│ │Machine4│
    │.10     │ │.20     │ │.30     │ │.40     │
    └────────┘ └────────┘ └────────┘ └────────┘
```

#### Étape 1 : Connecter les machines au réseau

**Méthode A : DHCP automatique (simple mais IPs peuvent changer)**

```bash
# Sur chaque machine, vérifier l'IP obtenue
ip addr show

# Ou sur Windows
ipconfig

# Note l'IP de chaque machine
Machine 1: 192.168.1.X
Machine 2: 192.168.1.Y
Machine 3: 192.168.1.Z
Machine 4: 192.168.1.W
```

**[ATTENTION] Problème : Les IPs peuvent changer au redémarrage !**

---

**Méthode B : IPs statiques (RECOMMANDÉ [OK])**

##### Sur Machine 1 (Linux - Ubuntu/Debian)

```bash
# Identifier l'interface réseau
ip link show

# Résultat exemple:
# 1: lo: <LOOPBACK...
# 2: enp0s3: <BROADCAST,MULTICAST,UP...  <- Interface principale
#          ^^^^^^ Note ce nom

# Éditer la configuration réseau
sudo nano /etc/netplan/01-netcfg.yaml
```

**Contenu du fichier :**

```yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:  # <- Remplace par ton interface
      addresses:
        - 192.168.1.10/24  # <- IP statique Machine 1
      routes:
        - to: default
          via: 192.168.1.1  # <- IP de ta box/routeur
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4
```

**Appliquer la configuration :**

```bash
sudo netplan apply

# Vérifier
ip addr show enp0s3
```

**Résultat attendu :**

```
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP>
    inet 192.168.1.10/24 brd 192.168.1.255 scope global enp0s3
         ^^^^^^^^^^^^^ IP statique configurée [OK]
```

---

##### Sur Machine 1 (Windows 10/11)

```
1. Ouvrir "Paramètres"
2. Réseau et Internet
3. Ethernet (ou WiFi)
4. Cliquer sur ta connexion active
5. Modifier les paramètres de l'adaptateur
6. Clic droit sur ta carte réseau -> Propriétés
7. Double-clic sur "Protocole Internet version 4 (TCP/IPv4)"
8. Sélectionner "Utiliser l'adresse IP suivante"

Configuration:
   Adresse IP: 192.168.1.10
   Masque de sous-réseau: 255.255.255.0
   Passerelle par défaut: 192.168.1.1 (IP de ta box)
   Serveur DNS préféré: 8.8.8.8
   Serveur DNS auxiliaire: 8.8.4.4

9. OK -> OK
10. Fermer
```

**Vérifier (PowerShell) :**

```powershell
ipconfig

# Tu dois voir:
# Adresse IPv4. . . . . . . . . . . . . .: 192.168.1.10
# Masque de sous-réseau. . . . . . . . . : 255.255.255.0
# Passerelle par défaut. . . . . . . . . : 192.168.1.1
```

---

##### Sur Machine 1 (macOS)

```
1. Préférences Système
2. Réseau
3. Sélectionner ta connexion (Ethernet ou WiFi)
4. Configurer IPv4: Manuellement

Configuration:
   Adresse IP: 192.168.1.10
   Masque de sous-réseau: 255.255.255.0
   Routeur: 192.168.1.1
   DNS: 8.8.8.8

5. Appliquer
```

**Vérifier (Terminal) :**

```bash
ifconfig

# ou
networksetup -getinfo "Ethernet"
```

---

#### Étape 2 : Configurer les 3 autres machines

**Répète la configuration sur chaque machine avec l'IP correspondante :**

| Machine | IP | Masque | Passerelle | DNS |
|---------|----|----|-----------|-----|
| Machine 1 | 192.168.1.10 | 255.255.255.0 | 192.168.1.1 | 8.8.8.8 |
| Machine 2 | 192.168.1.20 | 255.255.255.0 | 192.168.1.1 | 8.8.8.8 |
| Machine 3 | 192.168.1.30 | 255.255.255.0 | 192.168.1.1 | 8.8.8.8 |
| Machine 4 | 192.168.1.40 | 255.255.255.0 | 192.168.1.1 | 8.8.8.8 |

---

#### Étape 3 : Tester la connectivité

**Depuis Machine 1, teste les 3 autres :**

```bash
# Linux/macOS
ping -c 3 192.168.1.20
ping -c 3 192.168.1.30
ping -c 3 192.168.1.40

# Windows
ping 192.168.1.20
ping 192.168.1.30
ping 192.168.1.40
```

**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=0.234 ms
64 bytes from 192.168.1.20: icmp_seq=2 ttl=64 time=0.198 ms
64 bytes from 192.168.1.20: icmp_seq=3 ttl=64 time=0.211 ms

--- 192.168.1.20 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
           Tout fonctionne ! [OK]
```

**Répète ce test depuis CHAQUE machine vers les 3 autres !**

```
Machine 1 -> ping Machine 2, 3, 4 [OK]
Machine 2 -> ping Machine 1, 3, 4 [OK]
Machine 3 -> ping Machine 1, 2, 4 [OK]
Machine 4 -> ping Machine 1, 2, 3 [OK]

Total: 12 tests de ping (tous doivent fonctionner)
```

---

### Option 2 : Switch réseau sans Internet

**Scénario : 4 machines + 1 switch, pas de box/routeur**

```
        ┌─────────────────┐
        │  SWITCH RÉSEAU  │
        │  (non managé)   │
        └─────────────────┘
         │    │    │    │
    ┌────┴─┬──┴─┬──┴─┬──┴────┐
    │      │    │    │       │
┌───┴──┐ ┌─┴──┐ ┌──┴┐ ┌─────┴┐
│  M1  │ │ M2 │ │ M3│ │  M4  │
│ .10  │ │.20 │ │.30│ │ .40  │
└──────┘ └────┘ └───┘ └──────┘
```

**Configuration (même principe que Option 1) :**

```yaml
# Sur chaque machine
network:
  version: 2
  ethernets:
    enp0s3:
      addresses:
        - 192.168.1.XX/24  # XX = 10, 20, 30, 40
      # PAS de passerelle (pas d'Internet)
      # PAS de DNS nécessaire
```

**[ATTENTION] Limitation : Pas d'accès Internet**
- Pas de mises à jour système
- Installation MongoDB par clé USB ou partage fichiers
- OK pour environnement de test isolé

---

### Option 3 : Réseau virtuel (VMs)

**Scénario : 4 VMs sur 1 ou 2 machines physiques**

#### VirtualBox - Configuration "Réseau interne"

**Sur CHAQUE VM :**

```
1. Sélectionner la VM
2. Configuration -> Réseau
3. Adaptateur 1:
   - Activer la carte réseau
   - Mode d'accès réseau: Réseau interne
   - Nom: mongodb-cluster  (<- MÊME NOM sur toutes les VMs)
4. OK
```

**Puis configurer les IPs statiques comme dans Option 1.**

---

#### VMware - Configuration "Custom Network"

**Sur CHAQUE VM :**

```
1. VM Settings -> Network Adapter
2. Network Connection: Custom (VMnet2)  <- Crée VMnet2 si nécessaire
3. OK
```

**Configurer les IPs statiques ensuite.**

---

## [PACKAGE] INSTALLATION DE MONGODB (SUR LES 4 MACHINES)

**Tu dois installer MongoDB sur CHAQUE machine.**

### Installation Ubuntu/Debian (Recommandée)

**Répète ces étapes sur les 4 machines :**

#### Machine 1, 2, 3 et 4 - Installation

```bash
# 1. Importer la clé GPG MongoDB
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
   sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor

# 2. Ajouter le dépôt MongoDB
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] \
https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" | \
sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list

# 3. Mettre à jour les paquets
sudo apt update

# 4. Installer MongoDB
sudo apt install -y mongodb-org

# 5. Vérifier l'installation
mongod --version
```

**Résultat attendu :**

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

**[ATTENTION] NE PAS démarrer MongoDB maintenant !**

```bash
# Vérifier que MongoDB n'est PAS démarré
sudo systemctl status mongod

# Si démarré, l'arrêter
sudo systemctl stop mongod
sudo systemctl disable mongod
```

**Répète l'installation sur les 3 autres machines !**

---

### Installation Windows (si nécessaire)

**Si une ou plusieurs machines sont sous Windows :**

```
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:
   - Complete installation
   - NE PAS démarrer comme service (décocher)
   
4. Vérifier dans PowerShell:
   mongod --version
   
5. Arrêter le service si démarré:
   Stop-Service -Name MongoDB
   Set-Service -Name MongoDB -StartupType Manual
```

---

## [HOT] CONFIGURATION DU PARE-FEU (4 MACHINES)

**[ATTENTION] CRITIQUE : Sans cette étape, les machines ne pourront PAS communiquer !**

### Ports à ouvrir

| Port | Service | Machines concernées |
|------|---------|---------------------|
| **27017** | mongos | Machine 1 |
| **27018** | Shards | Machines 1, 2, 3, 4 |
| **27019** | Config Servers | Machines 1, 2, 3 |
| **27020** | Arbiter Shard 1 | Machine 4 |

---

### Configuration Linux (Ubuntu/Debian)

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

#### Machine 1

```bash
# Activer UFW
sudo ufw enable

# Autoriser SSH (important !)
sudo ufw allow 22/tcp

# Ouvrir les ports MongoDB
sudo ufw allow from 192.168.1.0/24 to any port 27017 proto tcp  # mongos
sudo ufw allow from 192.168.1.0/24 to any port 27018 proto tcp  # Shard 1
sudo ufw allow from 192.168.1.0/24 to any port 27019 proto tcp  # Config Server

# Vérifier
sudo ufw status numbered
```

**Résultat :**

```
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere
[ 2] 27017/tcp                  ALLOW IN    192.168.1.0/24
[ 3] 27018/tcp                  ALLOW IN    192.168.1.0/24
[ 4] 27019/tcp                  ALLOW IN    192.168.1.0/24
```

---

#### Machine 2

```bash
sudo ufw enable
sudo ufw allow 22/tcp
sudo ufw allow from 192.168.1.0/24 to any port 27018 proto tcp  # Shard 1 SECONDARY
sudo ufw allow from 192.168.1.0/24 to any port 27019 proto tcp  # Config Server

sudo ufw status numbered
```

---

#### Machine 3

```bash
sudo ufw enable
sudo ufw allow 22/tcp
sudo ufw allow from 192.168.1.0/24 to any port 27018 proto tcp  # Shard 2 PRIMARY
sudo ufw allow from 192.168.1.0/24 to any port 27019 proto tcp  # Config Server

sudo ufw status numbered
```

---

#### Machine 4

```bash
sudo ufw enable
sudo ufw allow 22/tcp
sudo ufw allow from 192.168.1.0/24 to any port 27018 proto tcp  # Shard 2 SECONDARY
sudo ufw allow from 192.168.1.0/24 to any port 27020 proto tcp  # Arbiter Shard 1

sudo ufw status numbered
```

---

### Configuration Windows (PowerShell Administrateur)

#### Machine 1 (si Windows)

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

# Règle pour Shard 1
New-NetFirewallRule -DisplayName "MongoDB Shard 1" `
  -Direction Inbound -Protocol TCP -LocalPort 27018 -Action Allow

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

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

---

#### Machines 2, 3, 4 (adapter selon les ports nécessaires)

**Machine 2 :**
```powershell
New-NetFirewallRule -DisplayName "MongoDB Shard 1 Secondary" `
  -Direction Inbound -Protocol TCP -LocalPort 27018 -Action Allow

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

**Machine 3 :**
```powershell
New-NetFirewallRule -DisplayName "MongoDB Shard 2 Primary" `
  -Direction Inbound -Protocol TCP -LocalPort 27018 -Action Allow

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

**Machine 4 :**
```powershell
New-NetFirewallRule -DisplayName "MongoDB Shard 2 Secondary" `
  -Direction Inbound -Protocol TCP -LocalPort 27018 -Action Allow

New-NetFirewallRule -DisplayName "MongoDB Arbiter" `
  -Direction Inbound -Protocol TCP -LocalPort 27020 -Action Allow
```

---

## [TEST] TESTS DE CONNECTIVITÉ RÉSEAU

### Test 1 : Ping entre toutes les machines

**Matrice de tests (depuis chaque machine) :**

```bash
# Depuis Machine 1
ping -c 3 192.168.1.20  # -> Machine 2
ping -c 3 192.168.1.30  # -> Machine 3
ping -c 3 192.168.1.40  # -> Machine 4

# Depuis Machine 2
ping -c 3 192.168.1.10  # -> Machine 1
ping -c 3 192.168.1.30  # -> Machine 3
ping -c 3 192.168.1.40  # -> Machine 4

# Depuis Machine 3
ping -c 3 192.168.1.10  # -> Machine 1
ping -c 3 192.168.1.20  # -> Machine 2
ping -c 3 192.168.1.40  # -> Machine 4

# Depuis Machine 4
ping -c 3 192.168.1.10  # -> Machine 1
ping -c 3 192.168.1.20  # -> Machine 2
ping -c 3 192.168.1.30  # -> Machine 3
```

**[OK] TOUS les pings doivent fonctionner (12 tests au total)**

---

### Test 2 : Connectivité sur les ports MongoDB

**Utilise `netcat` pour tester les ports :**

#### Depuis Machine 1, teste les ports sur Machine 2

```bash
# Installer netcat si nécessaire
sudo apt install netcat -y

# Tester le port 27018 de Machine 2
nc -zv 192.168.1.20 27018
```

**Résultat attendu :**

```
Connection to 192.168.1.20 27018 port [tcp/*] succeeded!
```

**[X] Si échec :**

```
nc: connect to 192.168.1.20 port 27018 (tcp) failed: Connection refused
                                                       ^^^^^^^^^^^^^^^^^^^
-> Problème: Pare-feu bloque OU port pas encore ouvert
```

---

#### Script de test complet

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

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

**Contenu :**

```bash
#!/bin/bash

# ═══════════════════════════════════════════════════════════════
# SCRIPT DE TEST DE CONNECTIVITÉ - CLUSTER MONGODB 4 MACHINES
# ═══════════════════════════════════════════════════════════════

echo "[RECHERCHE] Test de connectivité du cluster MongoDB (4 machines)"
echo ""

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

# Fonction de test
test_connection() {
    local host=$1
    local port=$2
    local description=$3
    
    if nc -z -w 2 $host $port 2>/dev/null; then
        echo -e "${GREEN}[OK] $description ($host:$port)${NC}"
        return 0
    else
        echo -e "${RED}[X] $description ($host:$port)${NC}"
        return 1
    fi
}

# Tests Machine 1
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Machine 1 (192.168.1.10)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
test_connection 192.168.1.10 27017 "mongos"
test_connection 192.168.1.10 27018 "Shard 1 PRIMARY"
test_connection 192.168.1.10 27019 "Config Server"
echo ""

# Tests Machine 2
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Machine 2 (192.168.1.20)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
test_connection 192.168.1.20 27018 "Shard 1 SECONDARY"
test_connection 192.168.1.20 27019 "Config Server"
echo ""

# Tests Machine 3
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Machine 3 (192.168.1.30)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
test_connection 192.168.1.30 27018 "Shard 2 PRIMARY"
test_connection 192.168.1.30 27019 "Config Server"
echo ""

# Tests Machine 4
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Machine 4 (192.168.1.40)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
test_connection 192.168.1.40 27018 "Shard 2 SECONDARY"
test_connection 192.168.1.40 27020 "Shard 1 ARBITER"
echo ""

echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "[ATTENTION]  NOTE: Les tests échoueront jusqu'à ce que"
echo "   MongoDB soit démarré sur chaque machine."
echo "   C'est normal à ce stade !"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
```

**Rendre exécutable et lancer :**

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

**À ce stade, tous les tests échoueront (normal, MongoDB pas encore démarré) :**

```
[RECHERCHE] Test de connectivité du cluster MongoDB (4 machines)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Machine 1 (192.168.1.10)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[X] mongos (192.168.1.10:27017)
[X] Shard 1 PRIMARY (192.168.1.10:27018)
[X] Config Server (192.168.1.10:27019)

(... tous échouent pour l'instant)

[ATTENTION]  NOTE: Les tests échoueront jusqu'à ce que
   MongoDB soit démarré sur chaque machine.
   C'est normal à ce stade !
```

**Garde ce script ! Tu l'utiliseras après la configuration MongoDB. [IMPORTANT]**

---

## [DOSSIER] CRÉATION DES RÉPERTOIRES DE DONNÉES

**Sur CHAQUE machine, crée les répertoires nécessaires.**

### Machine 1

```bash
# Répertoires de données
sudo mkdir -p /data/mongos
sudo mkdir -p /data/shard1
sudo mkdir -p /data/configdb

# Répertoires de logs
sudo mkdir -p /var/log/mongodb

# Permissions
sudo chown -R mongodb:mongodb /data
sudo chown -R mongodb:mongodb /var/log/mongodb

# Vérifier
ls -la /data
```

---

### Machine 2

```bash
sudo mkdir -p /data/shard1
sudo mkdir -p /data/configdb
sudo mkdir -p /var/log/mongodb

sudo chown -R mongodb:mongodb /data
sudo chown -R mongodb:mongodb /var/log/mongodb
```

---

### Machine 3

```bash
sudo mkdir -p /data/shard2
sudo mkdir -p /data/configdb
sudo mkdir -p /var/log/mongodb

sudo chown -R mongodb:mongodb /data
sudo chown -R mongodb:mongodb /var/log/mongodb
```

---

### Machine 4

```bash
sudo mkdir -p /data/shard2
sudo mkdir -p /data/arbiter
sudo mkdir -p /var/log/mongodb

sudo chown -R mongodb:mongodb /data
sudo chown -R mongodb:mongodb /var/log/mongodb
```

---

## [LISTE] RÉCAPITULATIF PARTIE 2

**État actuel du cluster :**

```
[OK] 4 machines configurées avec IPs statiques:
   • 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] Connectivité réseau vérifiée (ping OK)

[OK] MongoDB 7.0.5 installé sur les 4 machines

[OK] Pare-feu configuré sur les 4 machines:
   • Ports 27017, 27018, 27019, 27020 ouverts

[OK] Répertoires de données créés:
   • /data/shard1, /data/shard2
   • /data/configdb
   • /data/mongos
   • /data/arbiter

[OK] Prêt pour la configuration du cluster ! [OBJECTIF]
```

---

## [OBJECTIF] PROCHAINE ÉTAPE

**PARTIE 3 : Configuration du cluster shardé**

Tu vas maintenant :
1. Configurer et démarrer les Config Servers (Replica Set)
2. Configurer et démarrer Shard 1 (Replica Set)
3. Configurer et démarrer Shard 2 (Replica Set)
4. Configurer et démarrer mongos
5. Initialiser le cluster shardé
6. Ajouter les shards au cluster

**[RAPIDE] Prêt pour la PARTIE 3 ? ->**

J'ai créé la Partie 2 complète avec une configuration à 4 machines physiques. Cette architecture optimise l'utilisation des ressources tout en offrant une configuration production-ready.

Voulez-vous que je continue avec la Partie 3 (Configuration du cluster shardé) ?

Parfait ! Je vais créer la Partie 3 en détaillant au maximum chaque étape de la configuration du cluster shardé.

# [COURS] GUIDE MONGODB SHARDING - PARTIE 3

## [CONFIG] CONFIGURATION DU CLUSTER SHARDÉ (4 MACHINES)

### [OBJECTIF] OBJECTIF DE CETTE PARTIE

À la fin de cette partie, tu auras :
[OK] Config Servers (Replica Set 3 membres) opérationnels
[OK] Shard 1 (Replica Set 3 membres) opérationnel
[OK] Shard 2 (Replica Set 2 membres) opérationnel
[OK] mongos (Query Router) configuré et connecté
[OK] Cluster shardé initialisé et fonctionnel
[OK] Les 2 shards ajoutés au cluster

**[TEMPS] Durée estimée : 2h - 2h30**

---

## [MESURE] RAPPEL DE L'ARCHITECTURE

```
┌─────────────────────────────────────────────────────────────────┐
│                    CLUSTER SHARDÉ COMPLET                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  CONFIG SERVERS (Replica Set "configReplSet")          │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │   │
│  │  │   Member 1  │  │   Member 2  │  │   Member 3  │    │   │
│  │  │  Machine 1  │  │  Machine 2  │  │  Machine 3  │    │   │
│  │  │  :27019     │  │  :27019     │  │  :27019     │    │   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘    │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  SHARD 1 (Replica Set "shard1ReplSet")                 │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │   │
│  │  │   PRIMARY   │  │  SECONDARY  │  │   ARBITER   │    │   │
│  │  │  Machine 1  │  │  Machine 2  │  │  Machine 4  │    │   │
│  │  │  :27018     │  │  :27018     │  │  :27020     │    │   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘    │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  SHARD 2 (Replica Set "shard2ReplSet")                 │   │
│  │  ┌─────────────┐  ┌─────────────┐                      │   │
│  │  │   PRIMARY   │  │  SECONDARY  │                      │   │
│  │  │  Machine 3  │  │  Machine 4  │                      │   │
│  │  │  :27018     │  │  :27018     │                      │   │
│  │  └─────────────┘  └─────────────┘                      │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  QUERY ROUTER (mongos)                                  │   │
│  │  ┌─────────────┐                                        │   │
│  │  │   mongos    │  <- Point d'entrée applications        │   │
│  │  │  Machine 1  │                                        │   │
│  │  │  :27017     │                                        │   │
│  │  └─────────────┘                                        │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

ORDRE DE CONFIGURATION:
1. Config Servers (PREMIER - indispensable)
2. Shard 1 (Replica Set)
3. Shard 2 (Replica Set)
4. mongos (Query Router)
5. Initialisation du cluster
6. Ajout des shards
```

---

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

### Pourquoi commencer par les Config Servers ?

```
┌─────────────────────────────────────────────────────────┐
│  CONFIG SERVERS = Cerveau du cluster                    │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Les Config Servers stockent TOUTES les métadonnées:   │
│  • Quelles collections sont shardées ?                  │
│  • Quelle est la shard key ?                            │
│  • Quel chunk est sur quel shard ?                      │
│  • Configuration des zones                              │
│  • Historique des migrations                            │
│                                                         │
│  SANS Config Servers:                                   │
│  [X] mongos ne sait pas où envoyer les requêtes          │
│  [X] Impossible d'initialiser le cluster                 │
│  [X] Shards ne peuvent pas communiquer                   │
│                                                         │
│  AVEC Config Servers:                                   │
│  [OK] mongos route intelligemment                         │
│  [OK] Cluster opérationnel                                │
│  [OK] Métadonnées redondantes (Replica Set)              │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

### Configuration Machine 1 - Config Server Membre 1

**Fichier de configuration : `/etc/mongod-config.conf`**

```bash
# Créer le fichier de configuration
sudo nano /etc/mongod-config.conf
```

**Contenu complet du fichier :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION CONFIG SERVER - MACHINE 1
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 1
# IP: 192.168.1.10
# Port: 27019
# Rôle: Config Server Replica Set - Membre 1
# Replica Set Name: configReplSet
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# STOCKAGE DES DONNÉES
# ───────────────────────────────────────────────────────────────
storage:
  # Chemin de stockage des métadonnées du cluster
  dbPath: /data/configdb
  
  # Journal pour garantir la durabilité
  journal:
    enabled: true
    commitIntervalMs: 100  # Flush toutes les 100ms (par défaut)
  
  # Moteur de stockage
  engine: wiredTiger
  
  # Configuration WiredTiger
  wiredTiger:
    engineConfig:
      # Cache : 50% de (RAM - 1GB) par défaut
      # Pour Config Server, 512 MB suffit généralement
      cacheSizeGB: 0.5
      
      # Compression du journal
      journalCompressor: snappy
      
    collectionConfig:
      # Compression des collections
      blockCompressor: snappy
    
    indexConfig:
      # Compression des index
      prefixCompression: true

# ───────────────────────────────────────────────────────────────
# LOGS SYSTÈME
# ───────────────────────────────────────────────────────────────
systemLog:
  # Destination : fichier
  destination: file
  
  # Chemin du fichier de log
  path: /var/log/mongodb/mongod-config.log
  
  # Ajouter aux logs existants (ne pas écraser)
  logAppend: true
  
  # Niveau de verbosité (0 = info, 1-5 = debug)
  verbosity: 0
  
  # Logs détaillés pour certains composants
  component:
    replication:
      verbosity: 1  # Plus de détails sur la réplication
    sharding:
      verbosity: 1  # Plus de détails sur le sharding

# ───────────────────────────────────────────────────────────────
# RÉSEAU
# ───────────────────────────────────────────────────────────────
net:
  # Port d'écoute pour Config Server
  port: 27019
  
  # Écouter sur TOUTES les interfaces réseau
  # IMPORTANT pour communication entre machines
  bindIp: 0.0.0.0
  
  # Nombre maximum de connexions simultanées
  maxIncomingConnections: 1000
  
  # Compression réseau (réduit la bande passante)
  compression:
    compressors: snappy,zstd,zlib
  
  # IPv6 (désactivé si non utilisé)
  ipv6: false

# ───────────────────────────────────────────────────────────────
# SHARDING - RÔLE CONFIG SERVER
# ───────────────────────────────────────────────────────────────
sharding:
  # Définit cette instance comme Config Server
  clusterRole: configsvr
  # [ATTENTION] CRITIQUE: Sans cette ligne, MongoDB ne sait pas que c'est un Config Server !

# ───────────────────────────────────────────────────────────────
# RÉPLICATION (Config Servers = Replica Set obligatoire)
# ───────────────────────────────────────────────────────────────
replication:
  # Nom du Replica Set pour les Config Servers
  # DOIT être identique sur les 3 Config Servers
  replSetName: configReplSet
  
  # Taille de l'oplog (optionnel, auto-calculé par défaut)
  # Pour Config Server, 1GB suffit généralement
  # oplogSizeMB: 1024

# ───────────────────────────────────────────────────────────────
# GESTION DES PROCESSUS
# ───────────────────────────────────────────────────────────────
processManagement:
  # Fork en arrière-plan (pour systemd : false)
  fork: false
  
  # Fichier PID
  pidFilePath: /var/run/mongodb/mongod-config.pid
  
  # Fuseau horaire
  timeZoneInfo: /usr/share/zoneinfo

# ───────────────────────────────────────────────────────────────
# SÉCURITÉ (À activer APRÈS initialisation du cluster)
# ───────────────────────────────────────────────────────────────
#security:
#  authorization: enabled
#  keyFile: /etc/mongodb-keyfile
#  clusterAuthMode: keyFile

# ───────────────────────────────────────────────────────────────
# OPÉRATIONS
# ───────────────────────────────────────────────────────────────
operationProfiling:
  # Profiler désactivé (Config Server a peu de requêtes)
  mode: off
  
  # Seuil pour "requête lente"
  slowOpThresholdMs: 100

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION CONFIG SERVER - MACHINE 1
# ═══════════════════════════════════════════════════════════════
```

**[SAUVEGARDE] Sauvegarder : Ctrl+O, Entrée, Ctrl+X**

---

### Configuration Machine 2 - Config Server Membre 2

```bash
# Sur Machine 2
sudo nano /etc/mongod-config.conf
```

**Contenu (IDENTIQUE à Machine 1 sauf commentaires) :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION CONFIG SERVER - MACHINE 2
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 2
# IP: 192.168.1.20
# Port: 27019
# Rôle: Config Server Replica Set - Membre 2
# Replica Set Name: configReplSet
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /data/configdb
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 0.5
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

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

net:
  port: 27019
  bindIp: 0.0.0.0
  maxIncomingConnections: 1000
  compression:
    compressors: snappy,zstd,zlib
  ipv6: false

sharding:
  clusterRole: configsvr

replication:
  replSetName: configReplSet

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

operationProfiling:
  mode: off
  slowOpThresholdMs: 100

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION CONFIG SERVER - MACHINE 2
# ═══════════════════════════════════════════════════════════════
```

---

### Configuration Machine 3 - Config Server Membre 3

```bash
# Sur Machine 3
sudo nano /etc/mongod-config.conf
```

**Contenu (IDENTIQUE aux autres sauf commentaires) :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION CONFIG SERVER - MACHINE 3
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 3
# IP: 192.168.1.30
# Port: 27019
# Rôle: Config Server Replica Set - Membre 3
# Replica Set Name: configReplSet
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /data/configdb
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 0.5
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

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

net:
  port: 27019
  bindIp: 0.0.0.0
  maxIncomingConnections: 1000
  compression:
    compressors: snappy,zstd,zlib
  ipv6: false

sharding:
  clusterRole: configsvr

replication:
  replSetName: configReplSet

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

operationProfiling:
  mode: off
  slowOpThresholdMs: 100

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION CONFIG SERVER - MACHINE 3
# ═══════════════════════════════════════════════════════════════
```

---

### Démarrage des Config Servers

**[ATTENTION] IMPORTANT : Démarre les 3 Config Servers AVANT l'initialisation !**

#### Sur Machine 1

```bash
# Démarrer le Config Server
sudo mongod --config /etc/mongod-config.conf

# OU si tu veux l'exécuter en arrière-plan
sudo mongod --config /etc/mongod-config.conf --fork
```

**Résultat attendu :**

```
about to fork child process, waiting until server is ready for connections.
forked process: 12345
child process started successfully, parent exiting
```

**Vérifier que le processus tourne :**

```bash
ps aux | grep mongod-config

# Tu dois voir une ligne comme:
mongodb  12345  ... mongod --config /etc/mongod-config.conf
```

---

#### Sur Machine 2

```bash
sudo mongod --config /etc/mongod-config.conf --fork

# Vérifier
ps aux | grep mongod-config
```

---

#### Sur Machine 3

```bash
sudo mongod --config /etc/mongod-config.conf --fork

# Vérifier
ps aux | grep mongod-config
```

---

### Initialisation du Replica Set Config Servers

**Se connecter à UN des Config Servers (par exemple Machine 1) :**

```bash
# Depuis Machine 1
mongosh --host 192.168.1.10 --port 27019
```

**Tu devrais voir :**

```
Current Mongosh Log ID: 64f3e7a8b5c2d4e8f1a2b3c4
Connecting to:    mongodb://192.168.1.10:27019/
Using MongoDB:    7.0.5
Using Mongosh:    1.10.6

test>
```

---

**Initialiser le Replica Set des Config Servers :**

```javascript
rs.initiate({
  _id: "configReplSet",
  configsvr: true,  // [ATTENTION] CRITIQUE: Indique que c'est un Config Server RS
  members: [
    {
      _id: 0,
      host: "192.168.1.10:27019",
      priority: 2  // Priorité plus haute -> préféré comme PRIMARY
    },
    {
      _id: 1,
      host: "192.168.1.20:27019",
      priority: 1
    },
    {
      _id: 2,
      host: "192.168.1.30:27019",
      priority: 1
    }
  ]
})
```

**Explication ligne par ligne :**

```javascript
rs.initiate({
  // Nom du Replica Set (DOIT correspondre à replSetName dans mongod-config.conf)
  _id: "configReplSet",
  
  // TRÈS IMPORTANT: Indique que ce Replica Set est pour les Config Servers
  // Sans cette ligne, MongoDB ne saura pas que c'est un Config Server !
  configsvr: true,
  
  members: [
    {
      _id: 0,                        // ID unique du membre (0, 1, 2...)
      host: "192.168.1.10:27019",    // IP:Port du membre
      priority: 2                    // Priorité d'élection (plus haut = plus de chances d'être PRIMARY)
                                     // Machine 1 préférée comme PRIMARY
    },
    {
      _id: 1,
      host: "192.168.1.20:27019",
      priority: 1                    // Priorité standard
    },
    {
      _id: 2,
      host: "192.168.1.30:27019",
      priority: 1
    }
  ]
})
```

**Résultat attendu :**

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

**[OK] Si tu vois `ok: 1`, le Replica Set Config Servers est initialisé ! [BRAVO]**

---

### Vérification du Replica Set Config Servers

**Après quelques secondes, vérifie le statut :**

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

**Tu devrais voir :**

```javascript
{
  set: 'configReplSet',
  members: [
    {
      _id: 0,
      name: '192.168.1.10:27019',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',  // <- Un des membres est PRIMARY
      uptime: 123,
      ...
    },
    {
      _id: 1,
      name: '192.168.1.20:27019',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',  // <- Les autres sont SECONDARY
      uptime: 118,
      ...
    },
    {
      _id: 2,
      name: '192.168.1.30:27019',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 115,
      ...
    }
  ],
  ok: 1
}
```

**Points importants à vérifier :**

```javascript
[OK] set: 'configReplSet'           // Nom correct
[OK] health: 1 (sur tous les membres) // Tous en bonne santé
[OK] Un PRIMARY                       // Élection réussie
[OK] Deux SECONDARY                   // Réplication en place
[OK] ok: 1                           // Commande réussie
```

**Affichage simplifié :**

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

**Résultat :**

```
192.168.1.10:27019        | PRIMARY    | Health: 1
192.168.1.20:27019        | SECONDARY  | Health: 1
192.168.1.30:27019        | SECONDARY  | Health: 1

[OK] Config Servers Replica Set opérationnel !
```

---

## [OUTIL] ÉTAPE 2 : CONFIGURATION SHARD 1

### Pourquoi configurer les Shards maintenant ?

```
┌─────────────────────────────────────────────────────────┐
│  Config Servers [OK] Opérationnels                        │
│         v                                               │
│  Maintenant on configure les SHARDS                     │
│  = Là où les DONNÉES seront stockées                    │
│                                                         │
│  Shard 1:                                               │
│  • PRIMARY sur Machine 1                                │
│  • SECONDARY sur Machine 2                              │
│  • ARBITER sur Machine 4                                │
│                                                         │
│  Configuration en Replica Set pour:                     │
│  [OK] Haute disponibilité                                 │
│  [OK] Redondance des données                              │
│  [OK] Lectures distribuées                                │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

### Configuration Machine 1 - Shard 1 PRIMARY

**Fichier de configuration : `/etc/mongod-shard1.conf`**

```bash
# Sur Machine 1
sudo nano /etc/mongod-shard1.conf
```

**Contenu complet :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SHARD 1 PRIMARY - MACHINE 1
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 1
# IP: 192.168.1.10
# Port: 27018
# Rôle: Shard 1 - PRIMARY
# Replica Set Name: shard1ReplSet
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# STOCKAGE DES DONNÉES
# ───────────────────────────────────────────────────────────────
storage:
  # Chemin de stockage des données du Shard 1
  dbPath: /data/shard1
  
  journal:
    enabled: true
    commitIntervalMs: 100
  
  engine: wiredTiger
  
  wiredTiger:
    engineConfig:
      # Cache plus important pour un shard (stockage de données)
      # Par défaut: 50% de (RAM - 1GB)
      # Pour une machine avec 8 GB RAM: ~3.5 GB
      # On peut spécifier manuellement si besoin
      cacheSizeGB: 3
      
      journalCompressor: snappy
      
    collectionConfig:
      blockCompressor: snappy
    
    indexConfig:
      prefixCompression: true

# ───────────────────────────────────────────────────────────────
# LOGS SYSTÈME
# ───────────────────────────────────────────────────────────────
systemLog:
  destination: file
  path: /var/log/mongodb/mongod-shard1.log
  logAppend: true
  verbosity: 0
  
  component:
    replication:
      verbosity: 1
    sharding:
      verbosity: 1
    query:
      verbosity: 0  # Mettre à 1 pour débugger les requêtes lentes

# ───────────────────────────────────────────────────────────────
# RÉSEAU
# ───────────────────────────────────────────────────────────────
net:
  # Port pour le Shard 1
  port: 27018
  
  # Écouter sur toutes les interfaces
  bindIp: 0.0.0.0
  
  # Plus de connexions possibles (applications + mongos)
  maxIncomingConnections: 2000
  
  compression:
    compressors: snappy,zstd,zlib
  
  ipv6: false

# ───────────────────────────────────────────────────────────────
# SHARDING - RÔLE SHARD
# ───────────────────────────────────────────────────────────────
sharding:
  # Définit cette instance comme membre d'un Shard
  clusterRole: shardsvr
  # [ATTENTION] IMPORTANT: Indique que c'est un serveur de shard (pas config, pas standalone)

# ───────────────────────────────────────────────────────────────
# RÉPLICATION
# ───────────────────────────────────────────────────────────────
replication:
  # Nom du Replica Set pour Shard 1
  # DOIT être identique sur tous les membres du Shard 1
  replSetName: shard1ReplSet
  
  # Taille de l'oplog (important pour les shards)
  # Plus la taille est grande, plus longtemps un SECONDARY peut être arrêté
  # sans nécessiter resynchronisation complète
  # Pour 100 GB de données: 5-10 GB recommandé
  oplogSizeMB: 5120  # 5 GB

# ───────────────────────────────────────────────────────────────
# GESTION DES PROCESSUS
# ───────────────────────────────────────────────────────────────
processManagement:
  fork: false
  pidFilePath: /var/run/mongodb/mongod-shard1.pid
  timeZoneInfo: /usr/share/zoneinfo

# ───────────────────────────────────────────────────────────────
# OPÉRATIONS
# ───────────────────────────────────────────────────────────────
operationProfiling:
  # Profiler pour identifier les requêtes lentes
  mode: slowOp
  
  # Requêtes > 100ms sont considérées lentes
  slowOpThresholdMs: 100
  
  # Les requêtes lentes sont loggées dans system.profile

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION SHARD 1 PRIMARY - MACHINE 1
# ═══════════════════════════════════════════════════════════════
```

---

### Configuration Machine 2 - Shard 1 SECONDARY

```bash
# Sur Machine 2
sudo nano /etc/mongod-shard1.conf
```

**Contenu (IDENTIQUE sauf chemins et commentaires) :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SHARD 1 SECONDARY - MACHINE 2
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 2
# IP: 192.168.1.20
# Port: 27018
# Rôle: Shard 1 - SECONDARY
# Replica Set Name: shard1ReplSet
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /data/shard1
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 2  # Machine 2 a 4 GB RAM -> ~2 GB cache
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

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

net:
  port: 27018
  bindIp: 0.0.0.0
  maxIncomingConnections: 2000
  compression:
    compressors: snappy,zstd,zlib
  ipv6: false

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard1ReplSet
  oplogSizeMB: 5120

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

operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION SHARD 1 SECONDARY - MACHINE 2
# ═══════════════════════════════════════════════════════════════
```

---

### Configuration Machine 4 - Shard 1 ARBITER

**[ATTENTION] Rappel : L'ARBITER ne stocke PAS de données, juste vote aux élections**

```bash
# Sur Machine 4
sudo nano /etc/mongod-shard1-arbiter.conf
```

**Contenu (configuration minimaliste pour arbiter) :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SHARD 1 ARBITER - MACHINE 4
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 4
# IP: 192.168.1.40
# Port: 27020  <- Port différent (Machine 4 héberge aussi Shard 2 SECONDARY)
# Rôle: Shard 1 - ARBITER (vote uniquement, pas de données)
# Replica Set Name: shard1ReplSet
# ═══════════════════════════════════════════════════════════════

storage:
  # Arbiter stocke très peu (juste métadonnées du RS)
  dbPath: /data/arbiter
  journal:
    enabled: true
  engine: wiredTiger

systemLog:
  destination: file
  path: /var/log/mongodb/mongod-shard1-arbiter.log
  logAppend: true
  verbosity: 0

net:
  # Port 27020 (différent de Shard 2 sur la même machine)
  port: 27020
  bindIp: 0.0.0.0
  maxIncomingConnections: 200  # Peu de connexions nécessaires
  ipv6: false

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard1ReplSet
  # Pas d'oplog pour un arbiter (il ne réplique pas)

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

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION SHARD 1 ARBITER - MACHINE 4
# ═══════════════════════════════════════════════════════════════
```

---

### Démarrage des membres du Shard 1

#### Machine 1 - Shard 1 PRIMARY

```bash
# Sur Machine 1
sudo mongod --config /etc/mongod-shard1.conf --fork

# Vérifier
ps aux | grep mongod-shard1
```

---

#### Machine 2 - Shard 1 SECONDARY

```bash
# Sur Machine 2
sudo mongod --config /etc/mongod-shard1.conf --fork

# Vérifier
ps aux | grep mongod-shard1
```

---

#### Machine 4 - Shard 1 ARBITER

```bash
# Sur Machine 4
sudo mongod --config /etc/mongod-shard1-arbiter.conf --fork

# Vérifier
ps aux | grep mongod-shard1-arbiter
```

---

### Initialisation du Replica Set Shard 1

**Se connecter au futur PRIMARY (Machine 1) :**

```bash
# Depuis Machine 1
mongosh --host 192.168.1.10 --port 27018
```

**Initialiser le Replica Set :**

```javascript
rs.initiate({
  _id: "shard1ReplSet",
  members: [
    {
      _id: 0,
      host: "192.168.1.10:27018",
      priority: 10  // Priorité très haute -> toujours PRIMARY si disponible
    },
    {
      _id: 1,
      host: "192.168.1.20:27018",
      priority: 5   // Peut devenir PRIMARY si Machine 1 down
    },
    {
      _id: 2,
      host: "192.168.1.40:27020",
      arbiterOnly: true  // ARBITER : vote uniquement, pas de données
    }
  ]
})
```

**Résultat attendu :**

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

---

### Vérification du Replica Set Shard 1

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

**Affichage simplifié :**

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

**Résultat attendu :**

```
192.168.1.10:27018        | PRIMARY    | Health: 1
192.168.1.20:27018        | SECONDARY  | Health: 1
192.168.1.40:27020        | ARBITER    | Health: 1

[OK] Shard 1 Replica Set opérationnel !
```

---

## [OUTIL] ÉTAPE 3 : CONFIGURATION SHARD 2

### Configuration Machine 3 - Shard 2 PRIMARY

```bash
# Sur Machine 3
sudo nano /etc/mongod-shard2.conf
```

**Contenu :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SHARD 2 PRIMARY - MACHINE 3
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 3
# IP: 192.168.1.30
# Port: 27018
# Rôle: Shard 2 - PRIMARY
# Replica Set Name: shard2ReplSet
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /data/shard2
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 3  # Machine 3 a 8 GB RAM
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

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

net:
  port: 27018
  bindIp: 0.0.0.0
  maxIncomingConnections: 2000
  compression:
    compressors: snappy,zstd,zlib
  ipv6: false

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard2ReplSet
  oplogSizeMB: 5120

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

operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION SHARD 2 PRIMARY - MACHINE 3
# ═══════════════════════════════════════════════════════════════
```

---

### Configuration Machine 4 - Shard 2 SECONDARY

```bash
# Sur Machine 4
sudo nano /etc/mongod-shard2.conf
```

**Contenu :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SHARD 2 SECONDARY - MACHINE 4
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 4
# IP: 192.168.1.40
# Port: 27018  <- MÊME PORT que Shard 2 PRIMARY (machines différentes)
# Rôle: Shard 2 - SECONDARY
# Replica Set Name: shard2ReplSet
# ═══════════════════════════════════════════════════════════════

storage:
  dbPath: /data/shard2
  journal:
    enabled: true
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 2  # Machine 4 a 4 GB RAM
      journalCompressor: snappy
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true

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

net:
  port: 27018
  bindIp: 0.0.0.0
  maxIncomingConnections: 2000
  compression:
    compressors: snappy,zstd,zlib
  ipv6: false

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard2ReplSet
  oplogSizeMB: 5120

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

operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION SHARD 2 SECONDARY - MACHINE 4
# ═══════════════════════════════════════════════════════════════
```

---

### Démarrage des membres du Shard 2

#### Machine 3 - Shard 2 PRIMARY

```bash
# Sur Machine 3
sudo mongod --config /etc/mongod-shard2.conf --fork

# Vérifier
ps aux | grep mongod-shard2
```

---

#### Machine 4 - Shard 2 SECONDARY

```bash
# Sur Machine 4
sudo mongod --config /etc/mongod-shard2.conf --fork

# Vérifier
ps aux | grep mongod-shard2

# [ATTENTION] Note: Machine 4 a maintenant 2 processus MongoDB:
# 1. Shard 1 ARBITER (port 27020)
# 2. Shard 2 SECONDARY (port 27018)
```

**Vérifier les 2 processus sur Machine 4 :**

```bash
ps aux | grep mongod

# Tu dois voir:
# mongod ... /etc/mongod-shard1-arbiter.conf
# mongod ... /etc/mongod-shard2.conf
```

---

### Initialisation du Replica Set Shard 2

**Se connecter au futur PRIMARY (Machine 3) :**

```bash
# Depuis Machine 3
mongosh --host 192.168.1.30 --port 27018
```

**Initialiser le Replica Set :**

```javascript
rs.initiate({
  _id: "shard2ReplSet",
  members: [
    {
      _id: 0,
      host: "192.168.1.30:27018",
      priority: 10  // PRIMARY préféré
    },
    {
      _id: 1,
      host: "192.168.1.40:27018",
      priority: 5   // SECONDARY
    }
  ]
})
```

**Résultat attendu :**

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

---

### Vérification du Replica Set Shard 2

```javascript
rs.status()

// Affichage simplifié
rs.status().members.forEach(m => {
  print(`${m.name.padEnd(25)} | ${m.stateStr.padEnd(10)} | Health: ${m.health}`)
})
```

**Résultat attendu :**

```
192.168.1.30:27018        | PRIMARY    | Health: 1
192.168.1.40:27018        | SECONDARY  | Health: 1

[OK] Shard 2 Replica Set opérationnel !
```

---

## [OUTIL] ÉTAPE 4 : CONFIGURATION MONGOS (QUERY ROUTER)

### Qu'est-ce que mongos ?

```
┌─────────────────────────────────────────────────────────┐
│  mongos = Query Router (Routeur de requêtes)            │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Rôles:                                                 │
│  1. Recevoir les requêtes des applications              │
│  2. Consulter les Config Servers                        │
│  3. Router vers le(s) bon(s) shard(s)                   │
│  4. Agréger les résultats                               │
│  5. Retourner à l'application                           │
│                                                         │
│  IMPORTANT:                                             │
│  • Pas de stockage de données                           │
│  • Léger (500 MB RAM suffit)                            │
│  • Peut en avoir plusieurs (haute disponibilité)        │
│  • Applications se connectent à mongos                  │
│                                                         │
│  mongos cache les métadonnées en mémoire:               │
│  • Où est chaque chunk                                  │
│  • Configuration du sharding                            │
│  • Définitions des shard keys                           │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

### Configuration Machine 1 - mongos

**[ATTENTION] NOTE : mongos n'utilise PAS de fichier de configuration classique**

**Méthode 1 : Démarrage direct (Recommandée pour débuter)**

```bash
# Sur Machine 1
sudo 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 /var/log/mongodb/mongos.log \
  --fork
```

**Explication des paramètres :**

```bash
mongos \
  # Config Servers (Replica Set)
  # Format: replSetName/host1:port,host2:port,host3:port
  --configdb configReplSet/192.168.1.10:27019,192.168.1.20:27019,192.168.1.30:27019 \
  
  # Écouter sur toutes les interfaces
  --bind_ip 0.0.0.0 \
  
  # Port (27017 = port par défaut MongoDB, utilisé par les applications)
  --port 27017 \
  
  # Fichier de logs
  --logpath /var/log/mongodb/mongos.log \
  
  # Exécuter en arrière-plan
  --fork
```

**Résultat attendu :**

```
about to fork child process, waiting until server is ready for connections.
forked process: 23456
child process started successfully, parent exiting
```

---

**Méthode 2 : Fichier de configuration (Production)**

```bash
# Créer le fichier de configuration
sudo nano /etc/mongos.conf
```

**Contenu :**

```yaml
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MONGOS - MACHINE 1
# ═══════════════════════════════════════════════════════════════
# Machine: Machine 1
# IP: 192.168.1.10
# Port: 27017
# Rôle: Query Router (routeur de requêtes)
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# LOGS SYSTÈME
# ───────────────────────────────────────────────────────────────
systemLog:
  destination: file
  path: /var/log/mongodb/mongos.log
  logAppend: true
  verbosity: 0
  
  component:
    sharding:
      verbosity: 1  # Plus de détails sur le routing

# ───────────────────────────────────────────────────────────────
# RÉSEAU
# ───────────────────────────────────────────────────────────────
net:
  # Port par défaut MongoDB (applications se connectent ici)
  port: 27017
  
  # Écouter sur toutes les interfaces
  bindIp: 0.0.0.0
  
  # Beaucoup de connexions (toutes les applications)
  maxIncomingConnections: 10000
  
  compression:
    compressors: snappy,zstd,zlib
  
  ipv6: false

# ───────────────────────────────────────────────────────────────
# SHARDING - CONFIG SERVERS
# ───────────────────────────────────────────────────────────────
sharding:
  # Connexion aux Config Servers (Replica Set)
  # Format: replSetName/host1:port,host2:port,host3:port
  configDB: configReplSet/192.168.1.10:27019,192.168.1.20:27019,192.168.1.30:27019

# ───────────────────────────────────────────────────────────────
# GESTION DES PROCESSUS
# ───────────────────────────────────────────────────────────────
processManagement:
  fork: false
  pidFilePath: /var/run/mongodb/mongos.pid
  timeZoneInfo: /usr/share/zoneinfo

# ═══════════════════════════════════════════════════════════════
# FIN CONFIGURATION MONGOS - MACHINE 1
# ═══════════════════════════════════════════════════════════════
```

**Démarrer avec le fichier de configuration :**

```bash
sudo mongos --config /etc/mongos.conf --fork
```

---

### Vérification de mongos

```bash
# Vérifier que mongos tourne
ps aux | grep mongos

# Se connecter à mongos
mongosh --host 192.168.1.10 --port 27017
```

**Tu devrais voir :**

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

mongos>
         ^^^^^^
   Prompt "mongos" (pas "test" ou "rs0")
```

**Vérifier la connexion aux Config Servers :**

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

**À ce stade, tu devrais voir :**

```javascript
--- Sharding Status ---
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("...")
  }
  shards:
        // Vide pour l'instant (pas encore ajouté les shards)
  active mongoses:
        "7.0.5" : 1  // <- mongos opérationnel !
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled: yes
        Currently running: no
  databases:
        // Vide pour l'instant
```

**[OK] Si tu vois `active mongoses: ... : 1`, mongos fonctionne !**

---

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

**Maintenant, on va dire à mongos :** "Voici les shards disponibles pour stocker les données"

### Se connecter à mongos

```bash
# Depuis Machine 1 (ou n'importe quelle machine)
mongosh --host 192.168.1.10 --port 27017
```

---

### Ajouter Shard 1

```javascript
sh.addShard("shard1ReplSet/192.168.1.10:27018,192.168.1.20:27018,192.168.1.40:27020")
```

**Explication :**

```javascript
sh.addShard(
  // Format: "replSetName/host1:port,host2:port,host3:port"
  "shard1ReplSet/192.168.1.10:27018,192.168.1.20:27018,192.168.1.40:27020"
  //           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  //           Liste TOUS les membres du Replica Set Shard 1
  //           mongos découvrira automatiquement qui est PRIMARY
)
```

**Résultat attendu :**

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

**[OK] `shardAdded: 'shard1ReplSet'` = Shard 1 ajouté avec succès !**

---

### Ajouter Shard 2

```javascript
sh.addShard("shard2ReplSet/192.168.1.30:27018,192.168.1.40:27018")
```

**Résultat attendu :**

```javascript
{
  shardAdded: 'shard2ReplSet',
  ok: 1,
  ...
}
```

**[OK] Shard 2 ajouté !**

---

### Vérifier le statut du cluster

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

**Tu devrais maintenant voir :**

```javascript
--- Sharding Status ---
  sharding version: { ... }
  
  shards:
        {  "_id" : "shard1ReplSet",  "host" : "shard1ReplSet/192.168.1.10:27018,192.168.1.20:27018",  "state" : 1 }
        {  "_id" : "shard2ReplSet",  "host" : "shard2ReplSet/192.168.1.30:27018,192.168.1.40:27018",  "state" : 1 }
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                        LES 2 SHARDS SONT PRÉSENTS ! [OK]
  
  active mongoses:
        "7.0.5" : 1
  
  autosplit:
        Currently enabled: yes
  
  balancer:
        Currently enabled: yes
        Currently running: no
        
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
        // Base "config" = métadonnées du cluster
```

**[OK] Cluster shardé COMPLET et opérationnel ! [BRAVO]**

---

## [TEST] TESTS DE VALIDATION

### Test 1 : Vérifier tous les composants

**Script de vérification complète :**

```javascript
// ═══════════════════════════════════════════════════════════════
// SCRIPT DE VALIDATION CLUSTER SHARDÉ
// À exécuter dans mongos (mongo --host 192.168.1.10 --port 27017)
// ═══════════════════════════════════════════════════════════════

print("[RECHERCHE] Validation du cluster shardé MongoDB\n");

// 1. Vérifier mongos
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
print("1. Vérification mongos");
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

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

// 2. Vérifier Config Servers
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
print("2. Vérification Config Servers");
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

var configRS = db.getSiblingDB("config").shards.findOne()
if (configRS) {
  print("[OK] Config Servers: Connectés");
  
  // Lister les membres
  var configStatus = sh.status();
  print("   Membres du Replica Set 'configReplSet':");
  print("   • 192.168.1.10:27019");
  print("   • 192.168.1.20:27019");
  print("   • 192.168.1.30:27019");
} else {
  print("[X] Config Servers: Problème de connexion");
}
print("");

// 3. Vérifier Shards
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
print("3. Vérification Shards");
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

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

shards.forEach(function(shard) {
  print(`[OK] Shard: ${shard._id}`);
  print(`   Host: ${shard.host}`);
  print(`   État: ${shard.state === 1 ? 'Actif' : 'Inactif'}`);
});
print("");

// 4. Vérifier Balancer
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
print("4. Vérification Balancer");
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

var balancerStatus = sh.getBalancerState();
print(`Balancer activé: ${balancerStatus ? 'OUI [OK]' : 'NON [X]'}`);

var balancerRunning = sh.isBalancerRunning();
print(`Balancer en cours: ${balancerRunning ? 'OUI' : 'NON'}`);
print("");

// 5. Résumé
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
print("5. Résumé");
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");

if (shards.length >= 2 && balancerStatus) {
  print("[BRAVO] CLUSTER SHARDÉ OPÉRATIONNEL !");
  print("");
  print("Composants validés:");
  print("  [OK] mongos (Query Router)");
  print("  [OK] Config Servers (Replica Set)");
  print(`  [OK] ${shards.length} Shards`);
  print("  [OK] Balancer actif");
  print("");
  print("[RAPIDE] Prêt pour le sharding de collections !");
} else {
  print("[ATTENTION]  CLUSTER INCOMPLET");
  print("Vérifier les composants manquants ci-dessus.");
}

print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
```

**Copie ce script et exécute-le dans mongos.**

**Résultat attendu :**

```
[RECHERCHE] Validation du cluster shardé MongoDB

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Vérification mongos
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[OK] mongos version: 7.0.5

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2. Vérification Config Servers
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[OK] Config Servers: Connectés
   Membres du Replica Set 'configReplSet':
   • 192.168.1.10:27019
   • 192.168.1.20:27019
   • 192.168.1.30:27019

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3. Vérification Shards
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Nombre de shards: 2
[OK] Shard: shard1ReplSet
   Host: shard1ReplSet/192.168.1.10:27018,192.168.1.20:27018
   État: Actif
[OK] Shard: shard2ReplSet
   Host: shard2ReplSet/192.168.1.30:27018,192.168.1.40:27018
   État: Actif

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4. Vérification Balancer
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Balancer activé: OUI [OK]
Balancer en cours: NON

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
5. Résumé
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[BRAVO] CLUSTER SHARDÉ OPÉRATIONNEL !

Composants validés:
  [OK] mongos (Query Router)
  [OK] Config Servers (Replica Set)
  [OK] 2 Shards
  [OK] Balancer actif

[RAPIDE] Prêt pour le sharding de collections !
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```

---

### Test 2 : Test réseau complet

**Utilise le script créé en Partie 2 :**

```bash
# Sur Machine 1
./test-connectivity.sh
```

**Maintenant, TOUS les tests doivent passer :**

```
[RECHERCHE] Test de connectivité du cluster MongoDB (4 machines)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Machine 1 (192.168.1.10)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[OK] mongos (192.168.1.10:27017)
[OK] Shard 1 PRIMARY (192.168.1.10:27018)
[OK] Config Server (192.168.1.10:27019)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Machine 2 (192.168.1.20)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[OK] Shard 1 SECONDARY (192.168.1.20:27018)
[OK] Config Server (192.168.1.20:27019)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Machine 3 (192.168.1.30)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[OK] Shard 2 PRIMARY (192.168.1.30:27018)
[OK] Config Server (192.168.1.30:27019)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Machine 4 (192.168.1.40)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[OK] Shard 2 SECONDARY (192.168.1.40:27018)
[OK] Shard 1 ARBITER (192.168.1.40:27020)

[OK] TOUS LES COMPOSANTS SONT ACCESSIBLES ! [BRAVO]
```

---

## [LISTE] RÉCAPITULATIF PARTIE 3

**État final du cluster :**

```
[OK] Config Servers (Replica Set 3 membres):
   • Machine 1:27019 (PRIMARY)
   • Machine 2:27019 (SECONDARY)
   • Machine 3:27019 (SECONDARY)
   État: Opérationnel [OK]

[OK] Shard 1 (Replica Set 3 membres):
   • Machine 1:27018 (PRIMARY)
   • Machine 2:27018 (SECONDARY)
   • Machine 4:27020 (ARBITER)
   État: Opérationnel [OK]

[OK] Shard 2 (Replica Set 2 membres):
   • Machine 3:27018 (PRIMARY)
   • Machine 4:27018 (SECONDARY)
   État: Opérationnel [OK]

[OK] mongos (Query Router):
   • Machine 1:27017
   État: Opérationnel [OK]

[OK] Cluster shardé:
   • 2 Shards ajoutés
   • Balancer actif
   • Prêt pour sharding de collections
```

---

## [OBJECTIF] PROCHAINE ÉTAPE

**PARTIE 4 : Sharding des collections**

Tu vas maintenant :
1. Activer le sharding sur une base de données
2. Choisir une shard key appropriée
3. Sharder des collections
4. Insérer des données et voir la distribution
5. Tester les requêtes
6. Observer le balancing automatique

**[RAPIDE] Prêt pour la PARTIE 4 ? ->**

J'ai créé une Partie 3 ultra-détaillée avec toutes les explications nécessaires. Le cluster shardé est maintenant complètement opérationnel sur 4 machines !

Voulez-vous que je continue avec la Partie 4 (Sharding des collections) ?

Je vais créer la Partie 4 du guide MongoDB Sharding en détaillant le sharding des collections avec des exemples pratiques.

# [COURS] GUIDE MONGODB SHARDING - PARTIE 4

## [GRAPHIQUE] SHARDING DES COLLECTIONS

### [OBJECTIF] OBJECTIF DE CETTE PARTIE

À la fin de cette partie, tu auras :
[OK] Compris comment activer le sharding sur une base de données
[OK] Maîtrisé le choix et la configuration d'une shard key
[OK] Shardé plusieurs collections avec différentes stratégies
[OK] Inséré des données de test et observé leur distribution
[OK] Testé différents types de requêtes (targeted vs scatter-gather)
[OK] Observé le balancer en action
[OK] Analysé les performances du cluster

**[TEMPS] Durée estimée : 2h - 2h30**

---

## [CLE] RAPPEL : QU'EST-CE QU'UNE SHARD KEY ?

```
┌─────────────────────────────────────────────────────────┐
│  SHARD KEY = Clé qui détermine la DISTRIBUTION          │
│              des données sur les shards                  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  La shard key est comme un CODE POSTAL:                 │
│                                                         │
│  Document avec userId: 123456                           │
│  -> MongoDB calcule: "123456 appartient au chunk 5"      │
│  -> Chunk 5 est sur Shard 2                              │
│  -> Document stocké sur Shard 2                          │
│                                                         │
│  Une fois choisie, la shard key:                        │
│  [ATTENTION]  NE PEUT PAS être changée                          │
│  [ATTENTION]  NE PEUT PAS être mise à jour sur les documents    │
│  [ATTENTION]  Doit exister dans CHAQUE document                 │
│                                                         │
│  Caractéristiques d'une BONNE shard key:               │
│  [OK] Cardinalité élevée (beaucoup de valeurs uniques)   │
│  [OK] Distribution uniforme                               │
│  [OK] Utilisée fréquemment dans les requêtes             │
│  [OK] Évite la monotonie (croissance séquentielle)       │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

## [NOTE] ÉTAPE 1 : CRÉATION D'UNE BASE DE DONNÉES

### Se connecter à mongos

```bash
# Depuis n'importe quelle machine du réseau
mongosh --host 192.168.1.10 --port 27017
```

**Tu es maintenant connecté au routeur mongos.**

---

### Créer une base de données de test

```javascript
// ═══════════════════════════════════════════════════════════════
// CRÉATION BASE DE DONNÉES "ecommerce"
// ═══════════════════════════════════════════════════════════════

// Passer à la base de données (elle sera créée au premier insert)
use ecommerce

// Vérifier que tu es sur la bonne base
db.getName()
// Résultat: "ecommerce"
```

**À ce stade, la base existe en mémoire mais pas encore physiquement.**

---

### Activer le sharding sur la base de données

```javascript
// Activer le sharding pour la base "ecommerce"
sh.enableSharding("ecommerce")
```

**Résultat attendu :**

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

**[OK] `ok: 1` = Sharding activé sur la base "ecommerce" !**

---

### Vérifier l'activation du sharding

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

**Tu devrais voir :**

```javascript
databases:
  {
    "_id" : "config",
    "primary" : "config",
    "partitioned" : true
  }
  {
    "_id" : "ecommerce",
    "primary" : "shard1ReplSet",  <- Base créée sur Shard 1 par défaut
    "partitioned" : true,         <- Sharding activé [OK]
    "version" : {
      "uuid" : UUID("..."),
      "timestamp" : Timestamp(...),
      "lastMod" : 1
    }
  }
```

**Explications :**

```javascript
{
  "_id" : "ecommerce",           // Nom de la base
  "primary" : "shard1ReplSet",   // Shard "primaire" pour cette base
                                 // (collections non-shardées iront ici)
  "partitioned" : true,          // Sharding activé sur cette base
  "version" : { ... }            // Métadonnées de version
}
```

---

## [OBJECTIF] ÉTAPE 2 : SHARDER UNE COLLECTION "users"

### Cas d'usage : Collection users (utilisateurs)

```
┌─────────────────────────────────────────────────────────┐
│  COLLECTION: ecommerce.users                            │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Structure de document:                                 │
│  {                                                      │
│    _id: ObjectId("..."),                                │
│    userId: 123456,           <- Identifiant unique       │
│    username: "alice",                                   │
│    email: "alice@example.com",                          │
│    country: "France",                                   │
│    registeredAt: ISODate("2024-01-15"),                 │
│    orders: 25,                                          │
│    totalSpent: 1234.56                                  │
│  }                                                      │
│                                                         │
│  Requêtes typiques:                                     │
│  • Chercher par userId (très fréquent)                  │
│  • Chercher par email (fréquent)                        │
│  • Chercher par country (occasionnel)                   │
│  • Lister tous les users (rare)                         │
│                                                         │
│  Choix de shard key: userId                             │
│  Raison: Utilisé dans 80% des requêtes                  │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

### Créer un index sur la shard key

**[ATTENTION] OBLIGATOIRE : Avant de sharder, créer un index sur la shard key !**

```javascript
// Créer un index sur userId (notre future shard key)
db.users.createIndex({ userId: 1 })
```

**Résultat attendu :**

```javascript
{
  numIndexesBefore: 1,  // Index sur _id (par défaut)
  numIndexesAfter: 2,   // _id + userId
  createdCollectionAutomatically: true,  // Collection créée automatiquement
  ok: 1
}
```

**Vérifier les index :**

```javascript
db.users.getIndexes()
```

**Résultat :**

```javascript
[
  { v: 2, key: { _id: 1 }, name: '_id_' },           // Index par défaut
  { v: 2, key: { userId: 1 }, name: 'userId_1' }     // Notre index [OK]
]
```

---

### Sharder la collection avec la shard key

```javascript
// Sharder la collection "users" avec userId comme shard key
sh.shardCollection("ecommerce.users", { userId: 1 })
```

**Explication :**

```javascript
sh.shardCollection(
  "ecommerce.users",    // <base>.<collection>
  { userId: 1 }         // Shard key: userId en ordre croissant
                        // 1 = croissant, -1 = décroissant, "hashed" = hashé
)
```

**Résultat attendu :**

```javascript
{
  collectionsharded: 'ecommerce.users',  <- Collection shardée [OK]
  ok: 1,
  '$clusterTime': { ... },
  operationTime: Timestamp({ ... })
}
```

**[OK] Collection "users" shardée avec succès !**

---

### Vérifier le sharding de la collection

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

**Dans la sortie, cherche la section "ecommerce.users" :**

```javascript
databases:
  {
    "_id" : "ecommerce",
    "primary" : "shard1ReplSet",
    "partitioned" : true,
    "version" : { ... }
  }
  
  ecommerce.users
    shard key: { "userId" : 1 }        <- Shard key confirmée [OK]
    unique: false
    balancing: true
    chunks:
      shard1ReplSet  1               <- 1 chunk initial sur Shard 1
    { "userId" : { "$minKey" : 1 } } -->> { "userId" : { "$maxKey" : 1 } } on : shard1ReplSet Timestamp(1, 0)
```

**Explications :**

```javascript
ecommerce.users
  shard key: { "userId" : 1 }       // Clé de distribution
  unique: false                     // Shard key n'est pas unique
  balancing: true                   // Balancer actif pour cette collection
  
  chunks:
    shard1ReplSet  1                // 1 chunk sur Shard 1 (pour l'instant)
  
  // Détails du chunk:
  { "userId" : { "$minKey" : 1 } }  // Début du chunk (valeur min possible)
  -->>
  { "userId" : { "$maxKey" : 1 } }  // Fin du chunk (valeur max possible)
  on : shard1ReplSet                // Shard où se trouve ce chunk
  Timestamp(1, 0)                   // Timestamp de création
```

**Pour l'instant : UN SEUL chunk contenant TOUTES les valeurs possibles de userId.**

---

## [ENTREE] ÉTAPE 3 : INSERTION DE DONNÉES DE TEST

### Script d'insertion de 100 000 utilisateurs

```javascript
// ═══════════════════════════════════════════════════════════════
// INSERTION DE 100 000 UTILISATEURS
// ═══════════════════════════════════════════════════════════════

use ecommerce

// Fonction helper pour générer un pays aléatoire
function randomCountry() {
  const countries = [
    "France", "USA", "Germany", "Japan", "UK", 
    "Spain", "Italy", "Canada", "Australia", "Brazil"
  ];
  return countries[Math.floor(Math.random() * countries.length)];
}

// Fonction helper pour générer un email
function generateEmail(userId) {
  return `user${userId}@example.com`;
}

// Insertion par batch de 1000 documents
print("[RAPIDE] Début de l'insertion de 100 000 utilisateurs...\n");

var batchSize = 1000;
var totalUsers = 100000;
var startTime = new Date();

for (var i = 0; i < totalUsers; i += batchSize) {
  var batch = [];
  
  for (var j = 0; j < batchSize && (i + j) < totalUsers; j++) {
    var userId = i + j + 1;  // userId de 1 à 100000
    
    batch.push({
      userId: userId,
      username: `user${userId}`,
      email: generateEmail(userId),
      country: randomCountry(),
      registeredAt: new Date(2023, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1),
      orders: Math.floor(Math.random() * 100),
      totalSpent: Math.round(Math.random() * 10000 * 100) / 100
    });
  }
  
  // Insertion du batch
  db.users.insertMany(batch, { ordered: false });
  
  // Afficher la progression
  var progress = ((i + batchSize) / totalUsers * 100).toFixed(1);
  print(`[GRAPHIQUE] Progression: ${progress}% (${i + batchSize}/${totalUsers} utilisateurs)`);
}

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(totalUsers / duration)} documents/seconde\n`);

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

**Copie-colle ce script dans mongosh et exécute-le.**

**Résultat attendu :**

```
[RAPIDE] Début de l'insertion de 100 000 utilisateurs...

[GRAPHIQUE] Progression: 1.0% (1000/100000 utilisateurs)
[GRAPHIQUE] Progression: 2.0% (2000/100000 utilisateurs)
[GRAPHIQUE] Progression: 3.0% (3000/100000 utilisateurs)
...
[GRAPHIQUE] Progression: 99.0% (99000/100000 utilisateurs)
[GRAPHIQUE] Progression: 100.0% (100000/100000 utilisateurs)

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

[PACKAGE] Nombre total de documents: 100000
```

---

### Observer la distribution des données

**Après l'insertion, vérifie le statut du sharding :**

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

**Cherche la section "ecommerce.users" :**

```javascript
ecommerce.users
  shard key: { "userId" : 1 }
  unique: false
  balancing: true
  chunks:
    shard1ReplSet  3               <- Plusieurs chunks maintenant !
    shard2ReplSet  2               <- Données distribuées sur Shard 2 aussi !
  
  // Détails des chunks:
  { "userId" : { "$minKey" : 1 } } -->> { "userId" : 20000 } on : shard1ReplSet
  { "userId" : 20000 } -->> { "userId" : 40000 } on : shard2ReplSet
  { "userId" : 40000 } -->> { "userId" : 60000 } on : shard1ReplSet
  { "userId" : 60000 } -->> { "userId" : 80000 } on : shard2ReplSet
  { "userId" : 80000 } -->> { "userId" : { "$maxKey" : 1 } } on : shard1ReplSet
```

**[BRAVO] Les données sont maintenant DISTRIBUÉES sur les 2 shards !**

**Visualisation :**

```
Shard 1: Chunks 1, 3, 5  (userId: MinKey-20K, 40K-60K, 80K-MaxKey)
Shard 2: Chunks 2, 4     (userId: 20K-40K, 60K-80K)

Distribution approximative:
Shard 1: ~60 000 documents
Shard 2: ~40 000 documents
```

---

### Vérifier la distribution exacte

```javascript
// Compter les documents sur chaque shard
db.users.aggregate([
  {
    $group: {
      _id: null,
      total: { $sum: 1 }
    }
  }
])
```

**Pour voir la distribution par shard (depuis un shard directement) :**

```javascript
// Se connecter à Shard 1 PRIMARY
use ecommerce
db.users.countDocuments()

// Répéter sur Shard 2 PRIMARY
// ...
```

---

## [RECHERCHE] ÉTAPE 4 : TESTER LES REQUÊTES

### Requête 1 : Targeted Query (avec shard key)

```javascript
// ═══════════════════════════════════════════════════════════════
// REQUÊTE TARGETED (avec shard key)
// ═══════════════════════════════════════════════════════════════

// Rechercher un utilisateur par userId
db.users.find({ userId: 50000 }).explain("executionStats")
```

**Analyse du plan d'exécution :**

```javascript
{
  queryPlanner: {
    winningPlan: {
      stage: 'SINGLE_SHARD',      <- UNE SEULE shard interrogée ! [OK]
      shards: [
        {
          shardName: 'shard1ReplSet',  <- Shard 1 uniquement
          ...
        }
      ]
    }
  },
  executionStats: {
    nReturned: 1,                 <- 1 document retourné
    executionTimeMillis: 2,       <- Très rapide ! 2ms
    totalKeysExamined: 1,         <- 1 clé examinée (index utilisé)
    totalDocsExamined: 1          <- 1 document examiné
  }
}
```

**[OK] Requête TARGETED : MongoDB sait exactement où chercher !**

---

### Requête 2 : Scatter-Gather (sans shard key)

```javascript
// ═══════════════════════════════════════════════════════════════
// REQUÊTE SCATTER-GATHER (sans shard key)
// ═══════════════════════════════════════════════════════════════

// Rechercher par pays (PAS dans la shard key)
db.users.find({ country: "France" }).explain("executionStats")
```

**Analyse du plan d'exécution :**

```javascript
{
  queryPlanner: {
    winningPlan: {
      stage: 'SHARD_MERGE',         <- TOUS les shards interrogés ! [ATTENTION]
      shards: [
        {
          shardName: 'shard1ReplSet',
          ...
        },
        {
          shardName: 'shard2ReplSet',
          ...
        }
      ]
    }
  },
  executionStats: {
    nReturned: 10053,               <- ~10K documents français
    executionTimeMillis: 45,        <- Plus lent : 45ms
    totalKeysExamined: 0,           <- Pas d'index sur country
    totalDocsExamined: 100000       <- TOUS les documents scannés ! [X]
  }
}
```

**[ATTENTION] Requête SCATTER-GATHER : MongoDB doit interroger TOUS les shards !**

---

### Optimisation : Créer un index sur country

```javascript
// Créer un index sur country
db.users.createIndex({ country: 1 })

// Refaire la requête
db.users.find({ country: "France" }).explain("executionStats")
```

**Nouveau résultat :**

```javascript
{
  executionStats: {
    nReturned: 10053,
    executionTimeMillis: 12,        <- Beaucoup plus rapide ! 12ms au lieu de 45ms
    totalKeysExamined: 10053,       <- Index utilisé [OK]
    totalDocsExamined: 10053        <- Seulement les documents français examinés [OK]
  }
}
```

**[OK] Même avec scatter-gather, l'index améliore grandement les performances !**

---

### Requête 3 : Range Query (avec shard key)

```javascript
// ═══════════════════════════════════════════════════════════════
// RANGE QUERY (plage de userId)
// ═══════════════════════════════════════════════════════════════

// Utilisateurs avec userId entre 30000 et 35000
db.users.find({
  userId: { $gte: 30000, $lte: 35000 }
}).explain("executionStats")
```

**Analyse :**

```javascript
{
  queryPlanner: {
    winningPlan: {
      stage: 'SHARD_MERGE',         <- Plusieurs shards (la plage chevauche)
      shards: [
        {
          shardName: 'shard1ReplSet',  <- Shard 1 (chunk 40K-60K)
          ...
        },
        {
          shardName: 'shard2ReplSet',  <- Shard 2 (chunk 20K-40K)
          ...
        }
      ]
    }
  },
  executionStats: {
    nReturned: 5001,                <- 5001 documents
    executionTimeMillis: 8,         <- Rapide : 8ms
    totalKeysExamined: 5001,        <- Index utilisé
    totalDocsExamined: 5001
  }
}
```

**[OK] Range query : MongoDB interroge intelligemment seulement les shards concernés !**

---

## [SYNC] ÉTAPE 5 : OBSERVER LE BALANCER

### Qu'est-ce que le Balancer ?

```
┌─────────────────────────────────────────────────────────┐
│  BALANCER = Processus automatique qui équilibre         │
│             les chunks entre les shards                  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Fonctionnement:                                        │
│  1. Surveille la distribution des chunks               │
│  2. Détecte les déséquilibres                          │
│  3. Migre les chunks automatiquement                   │
│  4. Maintient l'équilibre en continu                   │
│                                                         │
│  Déclenchement:                                        │
│  • Différence > 8 chunks entre shards                  │
│  • Ou différence > 20% de la taille totale             │
│                                                         │
│  Caractéristiques:                                     │
│  [OK] Automatique (pas d'intervention)                   │
│  [OK] En arrière-plan                                    │
│  [OK] Sans interruption de service                       │
│  [ATTENTION]  Impact performance pendant migration              │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

### Vérifier l'état du Balancer

```javascript
// Est-ce que le balancer est activé ?
sh.getBalancerState()
// Résultat: true [OK]

// Est-ce que le balancer est en train de tourner ?
sh.isBalancerRunning()
// Résultat: false (ou true si migration en cours)

// Statut détaillé du balancer
sh.balancerCollectionStatus("ecommerce.users")
```

**Résultat :**

```javascript
{
  balancerCompliant: true,        <- Collection équilibrée [OK]
  firstComplianceViolation: null,
  ok: 1
}
```

---

### Forcer une vérification du balancer

```javascript
// Forcer le balancer à vérifier maintenant
sh.startBalancer()

// Attendre quelques secondes
sleep(5000)

// Vérifier le statut
sh.status()
```

---

### Observer les migrations en cours

```javascript
// Voir les migrations actives
db.getSiblingDB("config").migrations.find().pretty()
```

**Si une migration est en cours :**

```javascript
{
  _id: "ecommerce.users-userId_40000",
  ns: "ecommerce.users",
  min: { userId: 40000 },
  max: { userId: 60000 },
  fromShard: "shard1ReplSet",     <- Source
  toShard: "shard2ReplSet",       <- Destination
  chunkVersion: [...],
  waitForDelete: false
}
```

---

### Historique des migrations

```javascript
// Voir l'historique complet des migrations
db.getSiblingDB("config").changelog.find({
  what: "moveChunk.commit"
}).sort({ time: -1 }).limit(10).pretty()
```

**Exemple de sortie :**

```javascript
{
  _id: "...",
  server: "192.168.1.10",
  time: ISODate("2024-12-16T15:30:45.123Z"),
  what: "moveChunk.commit",
  ns: "ecommerce.users",
  details: {
    min: { userId: 40000 },
    max: { userId: 60000 },
    from: "shard1ReplSet",
    to: "shard2ReplSet",
    cloned: 20000,               <- 20K documents migrés
    clonedBytes: 5242880,        <- ~5 MB
    catchup: 0,
    steady: 0
  }
}
```

---

## [OBJECTIF] ÉTAPE 6 : SHARDER UNE DEUXIÈME COLLECTION "orders"

### Cas d'usage : Collection orders (commandes)

```
┌─────────────────────────────────────────────────────────┐
│  COLLECTION: ecommerce.orders                           │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Structure de document:                                 │
│  {                                                      │
│    _id: ObjectId("..."),                                │
│    orderId: 987654,          <- Identifiant unique       │
│    userId: 123456,           <- Référence au user        │
│    products: [...],                                     │
│    totalAmount: 456.78,                                 │
│    status: "shipped",                                   │
│    createdAt: ISODate("2024-12-01")                     │
│  }                                                      │
│                                                         │
│  Requêtes typiques:                                     │
│  • Chercher les commandes d'un user (très fréquent)    │
│  • Chercher une commande spécifique (fréquent)         │
│  • Rapports par date (occasionnel)                     │
│                                                         │
│  Choix de shard key: { userId: 1, orderId: 1 }         │
│  Raison: Compound key pour:                             │
│    - Distribution par userId (équilibrée)               │
│    - Unicité avec orderId                               │
│    - Queries efficaces par userId                       │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

---

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

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

---

### Sharder la collection

```javascript
// Sharder avec une compound shard key
sh.shardCollection("ecommerce.orders", { userId: 1, orderId: 1 })
```

**Résultat :**

```javascript
{
  collectionsharded: 'ecommerce.orders',
  ok: 1
}
```

---

### Insérer des données de test

```javascript
// ═══════════════════════════════════════════════════════════════
// INSERTION DE 200 000 COMMANDES
// ═══════════════════════════════════════════════════════════════

print("[RAPIDE] Début de l'insertion de 200 000 commandes...\n");

var batchSize = 1000;
var totalOrders = 200000;
var startTime = new Date();

for (var i = 0; i < totalOrders; i += batchSize) {
  var batch = [];
  
  for (var j = 0; j < batchSize && (i + j) < totalOrders; j++) {
    var orderId = i + j + 1;
    var userId = Math.floor(Math.random() * 100000) + 1;  // Random user
    
    batch.push({
      orderId: orderId,
      userId: userId,
      products: [
        { productId: Math.floor(Math.random() * 1000), quantity: Math.floor(Math.random() * 5) + 1 }
      ],
      totalAmount: Math.round(Math.random() * 1000 * 100) / 100,
      status: ["pending", "processing", "shipped", "delivered"][Math.floor(Math.random() * 4)],
      createdAt: new Date(2024, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1)
    });
  }
  
  db.orders.insertMany(batch, { ordered: false });
  
  var progress = ((i + batchSize) / totalOrders * 100).toFixed(1);
  print(`[GRAPHIQUE] Progression: ${progress}% (${i + batchSize}/${totalOrders} commandes)`);
}

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(totalOrders / duration)} documents/seconde\n`);
```

---

### Vérifier la distribution

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

**Cherche "ecommerce.orders" :**

```javascript
ecommerce.orders
  shard key: { "userId" : 1, "orderId" : 1 }  <- Compound key [OK]
  unique: false
  balancing: true
  chunks:
    shard1ReplSet  4
    shard2ReplSet  3
  
  // Distribution des chunks entre les 2 shards
```

---

## [GRAPHIQUE] ÉTAPE 7 : ANALYSER LES PERFORMANCES

### Script d'analyse complète

```javascript
// ═══════════════════════════════════════════════════════════════
// ANALYSE COMPLÈTE DU CLUSTER SHARDÉ
// ═══════════════════════════════════════════════════════════════

print("[GRAPHIQUE] ANALYSE DU CLUSTER SHARDÉ\n");
print("═".repeat(60) + "\n");

// 1. Statistiques globales
print("1. STATISTIQUES GLOBALES");
print("─".repeat(60));

var dbStats = db.stats();
print(`Base de données: ${db.getName()}`);
print(`Collections: ${dbStats.collections}`);
print(`Documents totaux: ${dbStats.objects}`);
print(`Taille des données: ${(dbStats.dataSize / 1024 / 1024).toFixed(2)} MB`);
print(`Taille du stockage: ${(dbStats.storageSize / 1024 / 1024).toFixed(2)} MB`);
print(`Index: ${dbStats.indexes}`);
print(`Taille des index: ${(dbStats.indexSize / 1024 / 1024).toFixed(2)} MB`);
print("");

// 2. Distribution par collection
print("2. DISTRIBUTION PAR COLLECTION");
print("─".repeat(60));

["users", "orders"].forEach(function(collName) {
  print(`\nCollection: ${collName}`);
  
  var count = db[collName].countDocuments();
  var stats = db[collName].stats();
  
  print(`  Documents: ${count}`);
  print(`  Taille données: ${(stats.size / 1024 / 1024).toFixed(2)} MB`);
  print(`  Index: ${stats.nindexes}`);
  
  // Distribution sur les shards
  if (stats.sharded) {
    print(`  Shardée: OUI [OK]`);
    Object.keys(stats.shards).forEach(function(shard) {
      var shardCount = stats.shards[shard].count;
      var percentage = (shardCount / count * 100).toFixed(1);
      print(`    ${shard}: ${shardCount} docs (${percentage}%)`);
    });
  } else {
    print(`  Shardée: NON`);
  }
});

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

**Résultat attendu :**

```
[GRAPHIQUE] ANALYSE DU CLUSTER SHARDÉ

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

1. STATISTIQUES GLOBALES
────────────────────────────────────────────────────────────
Base de données: ecommerce
Collections: 2
Documents totaux: 300000
Taille des données: 125.34 MB
Taille du stockage: 48.56 MB
Index: 4
Taille des index: 12.45 MB

2. DISTRIBUTION PAR COLLECTION
────────────────────────────────────────────────────────────

Collection: users
  Documents: 100000
  Taille données: 42.15 MB
  Index: 3
  Shardée: OUI [OK]
    shard1ReplSet: 59823 docs (59.8%)
    shard2ReplSet: 40177 docs (40.2%)

Collection: orders
  Documents: 200000
  Taille données: 83.19 MB
  Index: 1
  Shardée: OUI [OK]
    shard1ReplSet: 101234 docs (50.6%)
    shard2ReplSet: 98766 docs (49.4%)

═══════════════════════════════════════════════════════════
```

---

## [LISTE] RÉCAPITULATIF PARTIE 4

**Ce que tu as accompli :**

```
[OK] Base de données "ecommerce" créée et sharding activé

[OK] Collection "users" shardée:
   • Shard key: { userId: 1 }
   • 100 000 documents insérés
   • Distribution: ~60K sur Shard 1, ~40K sur Shard 2
   • Index: userId, country

[OK] Collection "orders" shardée:
   • Shard key: { userId: 1, orderId: 1 } (composée)
   • 200 000 documents insérés
   • Distribution: ~50% sur chaque shard

[OK] Tests de requêtes:
   • Targeted queries (avec shard key) : Très rapides [OK]
   • Scatter-gather (sans shard key) : Plus lentes [ATTENTION]
   • Range queries : Optimisées automatiquement [OK]

[OK] Balancer observé:
   • Distribution automatique des chunks
   • Équilibrage en continu
   • Migrations transparentes

[OK] Performances analysées:
   • 300 000 documents au total
   • ~125 MB de données
   • Distribution équilibrée
```

---

## [OBJECTIF] PROCHAINE ÉTAPE

**PARTIE 5 : Opérations avancées**

Tu vas apprendre :
1. Zone Sharding (distribution géographique)
2. Tag-aware sharding (isolation des charges)
3. Chunk management manuel
4. Ajout/Suppression de shards
5. Resharding (changer la shard key)
6. Monitoring avancé

**[RAPIDE] Prêt pour la PARTIE 5 ? ->**