Module 6 : Performance et Administration

Analyser les performances

explain() - Plan d'exécution

// Modes explain
db.users.find({ ville: "Paris" }).explain()              // queryPlanner
db.users.find({ ville: "Paris" }).explain("executionStats")
db.users.find({ ville: "Paris" }).explain("allPlansExecution")

// Points clés à analyser
{
    "queryPlanner": {
        "winningPlan": {
            "stage": "IXSCAN",         // IXSCAN = index, COLLSCAN = full scan
            "indexName": "ville_1"
        }
    },
    "executionStats": {
        "nReturned": 100,              // Documents retournés
        "totalDocsExamined": 100,      // Documents examinés
        "totalKeysExamined": 100,      // Entrées d'index
        "executionTimeMillis": 5       // Temps (ms)
    }
}

// Ratio optimal: nReturned == totalDocsExamined

Profiler

// Activer le profiler
db.setProfilingLevel(1, { slowms: 100 })  // Log queries > 100ms
db.setProfilingLevel(2)                    // Log toutes les queries
db.setProfilingLevel(0)                    // Désactiver

// Voir les requêtes lentes
db.system.profile.find().sort({ ts: -1 }).limit(10)

// Requêtes lentes > 100ms
db.system.profile.find({ millis: { $gt: 100 } })

currentOp - Operations en cours

// Voir les opérations en cours
db.currentOp()

// Filtrer les opérations longues
db.currentOp({ "secs_running": { $gt: 10 } })

// Killer une opération
db.killOp(opid)

Monitoring

// Stats serveur
db.serverStatus()

// Stats base de données
db.stats()

// Stats collection
db.users.stats()

// Métriques importantes
db.serverStatus().connections      // Connexions
db.serverStatus().opcounters       // Operations
db.serverStatus().mem              // Mémoire
db.serverStatus().wiredTiger       // Storage engine

MongoDB Atlas Monitoring

Atlas fournit :
  • Dashboard temps réel
  • Alertes configurables
  • Query Profiler
  • Performance Advisor (recommandations index)
  • Data Explorer

Optimisation des requêtes

// 1. Utiliser des index appropriés
db.users.createIndex({ ville: 1, age: 1 })

// 2. Projeter seulement les champs nécessaires
db.users.find({ ville: "Paris" }, { nom: 1, email: 1 })

// 3. Utiliser limit() pour grandes collections
db.users.find({ ville: "Paris" }).limit(100)

// 4. Eviter $regex sans ancre
// Mauvais (full scan):
db.users.find({ nom: { $regex: /dupont/i } })
// Bon (utilise index):
db.users.find({ nom: { $regex: /^Dupont/i } })

// 5. Eviter $where (JavaScript)
// Mauvais:
db.users.find({ $where: "this.age > 30" })
// Bon:
db.users.find({ age: { $gt: 30 } })

// 6. Utiliser hint() pour forcer un index
db.users.find({ ville: "Paris" }).hint({ ville: 1, age: 1 })

Replica Sets


+----------------------------------------------------------+
|                   REPLICA SET                             |
+----------------------------------------------------------+
|                                                           |
|   +----------+    +----------+    +----------+           |
|   | PRIMARY  |    |SECONDARY |    |SECONDARY |           |
|   | (R/W)    |--->| (R)      |--->| (R)      |           |
|   +----------+    +----------+    +----------+           |
|        |                                                  |
|        v          Replication asynchrone                  |
|   Ecritures                                               |
|                                                           |
+----------------------------------------------------------+
            
// Configuration replica set
rs.initiate({
    _id: "rs0",
    members: [
        { _id: 0, host: "mongo1:27017", priority: 2 },
        { _id: 1, host: "mongo2:27017", priority: 1 },
        { _id: 2, host: "mongo3:27017", priority: 1 }
    ]
})

// Status du replica set
rs.status()

// Ajouter un membre
rs.add("mongo4:27017")

// Retirer un membre
rs.remove("mongo4:27017")

Read Preference

// Où lire les données ?
primary           // Seulement PRIMARY (défaut)
primaryPreferred  // PRIMARY, sinon SECONDARY
secondary         // Seulement SECONDARY
secondaryPreferred // SECONDARY, sinon PRIMARY
nearest           // Plus proche (latence)

// Utilisation
db.users.find().readPref("secondaryPreferred")

// Connection string
mongodb://host1,host2,host3/?replicaSet=rs0&readPreference=secondaryPreferred

Write Concern

// Niveau d'acquittement des écritures
w: 0          // Pas d'acquittement
w: 1          // PRIMARY seulement (défaut)
w: "majority" // Majorite des membres
w: 3          // 3 membres spécifiques

j: true       // Journal écrit sur disque

// Utilisation
db.users.insertOne(
    { nom: "Test" },
    { writeConcern: { w: "majority", j: true, wtimeout: 5000 } }
)

Sharding


+----------------------------------------------------------+
|                      SHARDED CLUSTER                      |
+----------------------------------------------------------+
|                                                           |
|   +--------+    +--------+    +--------+                 |
|   | mongos |    | mongos |    | mongos |    Routeurs     |
|   +--------+    +--------+    +--------+                 |
|        |            |            |                        |
|        v            v            v                        |
|   +------------------------------------------+           |
|   |            Config Servers               |           |
|   +------------------------------------------+           |
|        |            |            |                        |
|        v            v            v                        |
|   +--------+    +--------+    +--------+                 |
|   | Shard1 |    | Shard2 |    | Shard3 |    Données      |
|   +--------+    +--------+    +--------+                 |
|                                                           |
+----------------------------------------------------------+
            
// Activer le sharding sur une base
sh.enableSharding("folab")

// Choisir une shard key et sharder une collection
sh.shardCollection("folab.users", { region: 1 })          // Range
sh.shardCollection("folab.logs", { _id: "hashed" })       // Hashed

// Status du cluster
sh.status()

// Distribution des chunks
db.users.getShardDistribution()

Choisir une shard key

Critères d'une bonne shard key :
  • Cardinalité élevée - Beaucoup de valeurs distinctes
  • Distribution uniforme - Éviter les hotspots
  • Non-monotone - Pas toujours croissante (éviter timestamps seuls)
  • Présente dans les requêtes - Pour le routage efficace
// Bonnes shard keys
{ region: 1, date: 1 }     // Compound
{ _id: "hashed" }          // Distribution uniforme
{ userId: "hashed" }       // Pour données par utilisateur

// Mauvaises shard keys
{ createdAt: 1 }           // Monotone, hotspot sur dernier shard
{ status: 1 }              // Cardinalité faible

Backup et restauration

# mongodump - Backup
mongodump --uri="mongodb://localhost:27017" --out=/backup/

# Collection spécifique
mongodump --uri="mongodb://..." --db=folab --collection=users

# mongorestore - Restauration
mongorestore --uri="mongodb://localhost:27017" /backup/

# Collection spécifique
mongorestore --uri="mongodb://..." --db=folab --collection=users /backup/folab/users.bson

# Export JSON/CSV
mongoexport --uri="mongodb://..." --db=folab --collection=users --out=users.json
mongoexport --uri="mongodb://..." --db=folab --collection=users --type=csv --fields=nom,email --out=users.csv

# Import JSON/CSV
mongoimport --uri="mongodb://..." --db=folab --collection=users --file=users.json

Atlas Backups

# Atlas propose:
# - Continuous Backups (Point-in-time recovery)
# - Snapshots periodiques
# - Restauration vers un nouveau cluster

# Via Atlas CLI
atlas backups snapshots list --clusterName myCluster
atlas backups restores start --clusterName myCluster

Sécurité

// Activer l'authentification (mongod.conf)
security:
    authorization: enabled

// Créer un admin
use admin
db.createUser({
    user: "admin",
    pwd: "securePassword",
    roles: ["root"]
})

// Créer un utilisateur applicatif
use folab
db.createUser({
    user: "appUser",
    pwd: "appPassword",
    roles: [
        { role: "readWrite", db: "folab" },
        { role: "read", db: "logs" }
    ]
})

// Roles built-in
read, readWrite             // Base de données
dbAdmin, userAdmin          // Administration
clusterAdmin, clusterMonitor // Cluster
backup, restore             // Backup
root                        // Super admin

Checklist production

  • [ ] Replica Set avec au moins 3 membres
  • [ ] Authentification activée
  • [ ] Chiffrement TLS/SSL
  • [ ] Backups automatisés
  • [ ] Monitoring et alertes
  • [ ] Index optimisés
  • [ ] Write Concern "majority" pour données critiques
  • [ ] Connection pooling configuré
  • [ ] Timeouts définis