--- title: Howto MongoDB --- **Cette page a été importée automatiquement de notre ancien wiki mais n'a pas encore été révisée.** * Documentation (2.4) : * Référence de configuration (2.4) : * Documentation (3.4) : * Référence de configuration (3.4) : ## Installation ### Paquet Debian stable C'est la verison 2.4 qui est disponible dans les paquets stables de Debian : ~~~ # aptitude install mongodb ~~~ ### Paquet de 10Gen L'éditeur de MongoDB fourni des paquets pour Debian, depuis leur dépôt. La version 3.4 est disponible. ~~~ # apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6 # echo "deb http://repo.mongodb.org/apt/debian wheezy/mongodb-org/3.4 main" >> /etc/apt/sources.list.d/mongodb.list ~~~ Puis : ~~~ # apt install mongodb-org ~~~ Tous les détails sont disponibles sur . ## Logrotate ### 3.4 Les paquets fournis par 10Gen n'ont pas de logrotate ! On peut simplement ajouter cette configuration dans `/etc/logrotate.d/mongodb` ~~~ /var/log/mongod.log { daily missingok rotate 365 dateext compress delaycompress notifempty sharedscripts postrotate kill -0 $(cat /var/lib/mongodb/mongod.lock) && kill -USR1 $(cat /var/lib/mongodb/mongod.lock) endscript } ~~~ Il faut aussi penser à modifier la configuration (`/etc/mongod.conf`) pour forcer le mode _reopen_ : ~~~ systemLog: destination: file logRotate: reopen logAppend: true path: /var/log/mongod.log ~~~ Il y a tout un chapitre (pas toujours très clair) sur la maière de gérer la rotation de logs : . > **Note** : Attention, mongodb-org-server 2.4 génère des logs *mongodb.log** mais en 3.2 des logs *mongod.log** > **Note** : Attention, par défaut mongodb log les requêtes lentes de plus de 100ms. Ça peut générer beaucoup de logs… On pourra les modifier avec [slowOpThresholdMs](https://docs.mongodb.com/manual/reference/configuration-options/#operationProfiling.slowOpThresholdMs). ## Configuration ### 2.4 La configuration de MongoDB se trouve dans le fichier `/etc/mongodb.conf` : ~~~ bind_ip = 127.0.0.1 port = 27017 auth = true #cpu = true #verbose = true #slowms = 42 ~~~ ATTENTION : la configuration de MongoDB est *très* spéciale… si vous voulez désactiver les logs verbose par exemple, il ne faut pas faire _verbose # false_ car _verbose NIMPORTEQUOI_ active les logs verbeux !! Il faut donc se méfier et suivre la documentation à la lettre… ### 3.4 La configuration de MongoDB se trouve dans le fichier `/etc/mongod.conf` et le format a changé. ## Authentification ### 2.4 MongoDB a deux modes de fonctionnement pour l'authentification : * Un mode sans aucune authentification * Un mode avec authentification Info : activer l'authentification génère des logs à chaque requête d'authentification qu'il n'est pas possible de désactiver avant la version 2.8 : voir #### Mode sans aucune authentification La configuration sans authentification se fait ainsi : ~~~ noauth = true ~~~ Dans ce mode, il n'y a besoin d'aucun login / mot de passe pour accéder à l'ensemble des dbs, données, etc. Ce mode est donc assez dangereux : il faut s'assurer que seuls des programmes de confiance accèdent au port TCP de MongoDB. #### Mode avec authentification ATTENTION, ce mode doit être correctement configuré (ce qui n'est pas le cas par défaut). La configuration doit donc être ainsi : ~~~ auth = true ~~~ Mais surtout, il faut créer (au moins) un utilisateur "admin" : ~~~ $ mongo > use admin > db.addUser("mongoadmin", "PASS") { "user" : "mongoadmin", "readOnly" : false, "pwd" : "3882eaa67064707a7a6ae872504f310d" } > db.system.users.find() { "_id" : ObjectId("4e8e132c76a7c48c75393b81"), "user" : "mongoadmin", "readOnly" : false, "pwd" : "3882eaa67064707a7a6ae872504f310d" } ~~~ C'est seulement une fois ce premier utilisateur "admin" créé que l'authentication est activée !! Si il n'est pas créé, l'authentification reste inactive... On peut ensuite se connecter à la base "admin" ainsi : ~~~ $ mongo admin -u mongoadmin -p PASS ~~~ Pour les accès aux base, les utilisateurs sont stockés dans la collection _system.users_ propre à chaque base. Ainsi pour créer un utilisateur pour une base données : ~~~ > use mydb > db.addUser("foo","PASS"); ~~~ Les utilisateurs (admin ou associés à une base de données) peuvent n'avoir qu'un accès read-only si ils sont créés ainsi : ~~~ > db.addUser("foo","PASS",true); ~~~ Enfin, pour supprimer un utilisateur : ~~~ > use mydb > db.removeUser("foo"); ~~~ ### 3.4 ## Utilisation En ligne de commande : ~~~ $ mongo MongoDB shell version: 1.4.4 url: test connecting to: test type "help" for help ~~~ Voici les opérations de base : ~~~ > show dbs admin local test > use foo switched to db foo > show collections > db.bar.find() > db.bar.save( { a : 1 } ) > db.bar.save( { a : 2 } ) > show collections bar system.indexes > db.bar.find() { "_id" : ObjectId("4e64dbf619a27977131978ad"), "a" : 1 } { "_id" : ObjectId("4e64dbf919a27977131978ae"), "a" : 2 } > db.foo.find({a:1}) { "_id" : ObjectId("4e0674a47888d8941034f4e1"), "a" : 1 } > db.foo.find().limit(1) { "_id" : ObjectId("4e0674a47888d8941034f4e1"), "a" : 1 } > exit bye ~~~ Quelques commandes utiles : Voir le compteur des connexions : ~~~ db.serverStatus().connections ~~~ Modifier un champ d'un objet existant : ~~~ > db.bar.save( { a : 4, b : 0 } ) > db.bar.update( { "_id" : ObjectId("4e64de8a19a27977131978b0") } , { $set : {b:1} } ) > db.bar.update( { "_id" : ObjectId("4e64de8a19a27977131978b0") } , { $unset : {b:1} } ) ~~~ Voir uniquement certains champs : ~~~ > db.bar.find({a:1},{flip:1}) > db.bar.find({a:1},{flip:1,flap:1}) ~~~ Voir plus d'objets (en évitant le _has more_) : ~~~ > DBQuery.shellBatchSize = 100 > db.foo.find() ~~~ Requête sur des dates : ~~~ db.foo.find( { "date": {"$gte": ISODate("2011-12-05T00:21:00Z")} } ) db.foo.find( { "date": {"$lt": ISODate("2011-12-05T04:00:00Z")} } ) db.foo.find( { "date": {"$gte": ISODate("2011-12-05T00:21:00Z"), "$lt": ISODate("2011-12-05T04:00:00Z")} } ) ~~~ En PHP : ~~~ $m = new Mongo(); $db = $m->foo; $bar = $db->bar; $bar->insert(array("a"=>"1","a"=>"2")); $res = $bar->find(); foreach ($res as $obj) { echo $obj["a"] . "\n"; } ~~~ ## Sauvegarde ### 2.4 ~~~ # mkdir /home/backup/mongodump # cd /home/backup/mongodump # mongodump ~~~ ### 3.4 Il exise plus de possibilités de sauvegarde dans les versions récentes : ## Restauration ~~~ cd /home/backup/mongodump/ # mongorestore --db dbname dbname mongorestore --db admin admin ~~~ ## Réplication avec replica set La réplication avec "replica set" nécessite au moins 3 machines : en effet, il va y avoir une élection du master vers lequel seront faites toutes les écritures. ### En Version 3.2+ Si vos mongod ne sont pas sur un LAN il est recommandé de mettre en place du TLS avec Sinon on pourra utiliser un keyfile */!\ Le datadir doit être vierge.* #### Avec keyfile Créer le keyfile sur une machine et déployer sur les autres le même fichier. ~~~ # openssl rand -base64 755 > /etc/mongod.key # chmod 400 /etc/mongod.key # chown mongodb: /etc/mongod.key ~~~ Modifier la configuration : ~~~ security: keyFile: /etc/mongod.key replication: replSetName: rs0 ~~~ Redémarrer les mongod. ~~~ # systemctl restart mongod ~~~ Se connecter et initialiser le RS. ~~~ # mongo > rs.initiate( { _id : "rs0", members: [ { _id : 0, host : "mongo1.example.net:27017" }, { _id : 1, host : "mongo2.example.net:27017" }, { _id : 2, host : "mongo3.example.net:27017" } ] } ) ~~~ Se connecter au master (voir avec rs.Status()) et créer un utilisateur admin et clusterAdmin. ~~~ # mongo > use admin use admin db.createUser( { user: "myUserAdmin", pwd: "abc123", roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] } ) db.createUser( { "user" : "clusteradmin", "pwd" : "abc123", roles: [ { "role" : "clusterAdmin", "db" : "admin" } ] } ) ~~~ Le Replica Set est maintenant en place. #### Avec X.509 TODO ### En version 1.8 Soit trois machines de test avec MongoDB 1.8.2 : mongo1 (PRIMARY), mongo2 (SECONDARY), mongo3 (SECONDARY) Activer le paramètre suivant dans /etc/mongodb.conf : ~~~ # in replica set configuration, specify the name of the replica set replSet = foo # Enable journaling (recommended for replica set) journal = true ~~~ À ce stade, on ne peut rien écrire sur les serveurs : ~~~ > db.test.insert({"coin": "coin"}) not master > rs.status() { "startupStatus" : 3, "info" : "run rs.initiate(...) if not yet done for the set", "errmsg" : "can't get local.system.replset config from self or any seed (EMPTYCONFIG)", "ok" : 0 } ~~~ Réinitialiser les bases sur chaque machine (attention, opération destructrice !) : ~~~ /etc/init.d/mongodb stop && mv /var/lib/mongodb/* /tmp && /etc/init.d/mongodb start ~~~ ### Sur mongo1 (PRIMARY) Il faut ensuite s'assurer que : - les machines communiquent bien au niveau réseau en TCP/27017 - que les machines n'ont pas de NAT (ou alors il faudra utiliser des DNS) Puis on initialise la réplication via le mongo shell : ~~~ > config = {_id: 'foo' , members: [ {_id: 0, host: '1.2.3.4:27017'},{_id: 1, host: '1.2.3.5:27017'},{_id: 2, host: '1.2.3.6:27017'}]} > rs.initiate(config); { "info" : "Config now saved locally. Should come online in about a minute.", "ok" : 1 } > rs.help() ~~~ On peut aussi le faire étape par étape ~~~ > rs.initiate() { "info2" : "no configuration explicitly specified -- making one", "info" : "Config now saved locally. Should come online in about a minute.", "ok" : 1 } ~~~ Ajout des 2 SECONDARY : ~~~ setname:PRIMARY> rs.add("mongo2") { "ok" : 1 } setname:PRIMARY> rs.add("mongo3") { "ok" : 1 } ~~~ Consultation de l'état de la réplication sur le master : ~~~ setname:PRIMARY> rs.status() { "set" : "setname", "date" : ISODate("2011-08-09T15:42:54Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "mongo1", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "optime" : { "t" : 1312904495000, "i" : 1 }, "optimeDate" : ISODate("2011-08-09T15:41:35Z"), "self" : true }, { "_id" : 1, "name" : "mongo2", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 76, "optime" : { "t" : 1312904495000, "i" : 1 }, "optimeDate" : ISODate("2011-08-09T15:41:35Z"), "lastHeartbeat" : ISODate("2011-08-09T15:42:54Z") }, { "_id" : 2, "name" : "mongo3", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 70, "optime" : { "t" : 1312904495000, "i" : 1 }, "optimeDate" : ISODate("2011-08-09T15:41:35Z"), "lastHeartbeat" : ISODate("2011-08-09T15:42:54Z") } ], "ok" : 1 } ~~~ Sur un slave : ~~~ SECONDARY> db.printReplicationInfo() this is a slave, printing slave replication info. source: 92.243.5.219:27017 syncedTo: Sun Jan 29 2012 22:34:07 GMT+0100 (CET) = 5744 secs ago (1.6hrs) source: stampzz-prod01.evolix.net:27017 syncedTo: Mon Jan 30 2012 00:09:47 GMT+0100 (CET) = 4 secs ago (0hrs) SECONDARY> use local switched to db local SECONDARY> db.oplog.rs.stats() { "ns" : "local.oplog.rs", "count" : 9616448, "size" : 1166277368, "avgObjSize" : 121.27943373686418, "storageSize" : 1320140800, "numExtents" : 1, "nindexes" : 0, "lastExtentSize" : 1320140800, "paddingFactor" : 1, "flags" : 0, "totalIndexSize" : 0, "indexSizes" : { }, "capped" : 1, "max" : 2147483647, "ok" : 1 } ~~~ Création d'un enregistrement de test : ~~~ setname:PRIMARY> db.foo.save({a:1}) setname:PRIMARY> ~~~ ### Sur mongo2 ou mongo3 (SECONDARY) Autorise le SECONDARY à traiter des requêtes : ~~~ setname:SECONDARY> rs.slaveOk() ~~~ Vérification de la présence de l'enregistrement de test : ~~~ setname:SECONDARY> db.foo.find() { "_id" : ObjectId("4e41558da08ccc36090745be"), "a" : 1 } ~~~ ### Sortir un mongo de la réplication Voici les étapes pour sortir un mongo de la réplication : 1. Sauvegarder (mongodump) 1. Stopper MongoDB 1. Sauvegarder les datas 1. Supprimer les fichiers local.* 1. Désactiver les replica dans la configuration 1. Relancer MongoDB ### Resynchroniser un mongo slave En cas de soucis, il peut être nécessaire de resynchroniser complètement un serveur MongoDB par rapport à un master. Il suffit de supprimer complètement le _dbpath_ : ~~~ # /etc/init.d/monogdb stop # mv /var/lib/mongodb /var/lib/mongodb.old # mkdir /var/lib/mongodb # chown mongodb:mongodb /var/lib/mongodb # chmod 750 /var/lib/mongodb # /etc/init.d/monogdb start ~~~ Le serveur slave repassera en RECOVERING puis en SECONDARY : ~~~ RECOVERING> db.printReplicationInfo() this is a slave, printing slave replication info. source: master.example.com:27017 syncedTo: Thu Jan 01 1970 01:00:00 GMT+0100 (CET) = 1327878874 secs ago (368855.24hrs) source: otherslave.example.com:27017 syncedTo: Mon Jan 30 2012 00:14:09 GMT+0100 (CET) = 25 secs ago (0.01hrs) SECONDARY> db.printReplicationInfo() configured oplog size: 1025.1384765625MB log length start to end: 741secs (0.21hrs) oplog first event time: Mon Jan 30 2012 00:14:09 GMT+0100 (CET) oplog last event time: Mon Jan 30 2012 00:26:30 GMT+0100 (CET) now: Mon Jan 30 2012 00:27:26 GMT+0100 (CET) ~~~ ### Erreurs de synchronisation En cas d'erreur du type : ~~~ "optimeDate" : ISODate("2012-01-29T21:34:07Z"), "lastHeartbeat" : ISODate("2012-01-29T23:02:43Z"), "pingMs" : 11, "errmsg" : "syncTail: 0 assertion db/pdfile.cpp:1881, syncing: { ts: Timestamp 1327872847000|109, h: -1582883220170752094, op: \"i\", ns: \"DB_MONGODB.tmp.mr.COLL_MONGODB_396779\", o: { _id: \"#colorsplash\", value: 1.0 } }" ~~~ Côté slave, on a plus de détails : ~~~ [rsSync] replHandshake res not: 1 res: { ok: 1.0 } [rsSync] local.oplog.rs Assertion failure !loc.isNull() db/pdfile.cpp 1881 0x57eeb6 0x589d6b 0x8a2746 0x82f486 0x821d8d 0x8231d8 0x82439a 0x824820 0xaa4560 0x7f1a33ef08ba 0x7f1a334ac02d /usr/bin/mongod(_ZN5mongo12sayDbContextEPKc+0x96) [0x57eeb6] /usr/bin/mongod(_ZN5mongo8assertedEPKcS1_j+0xfb) [0x589d6b] /usr/bin/mongod() [0x8a2746] /usr/bin/mongod(_ZN5mongo11_logOpObjRSERKNS_7BSONObjE+0x236) [0x82f486] /usr/bin/mongod(_ZN5mongo11ReplSetImpl8syncTailEv+0xced) [0x821d8d] /usr/bin/mongod(_ZN5mongo11ReplSetImpl11_syncThreadEv+0xc8) [0x8231d8] /usr/bin/mongod(_ZN5mongo11ReplSetImpl10syncThreadEv+0x4a) [0x82439a] /usr/bin/mongod(_ZN5mongo15startSyncThreadEv+0xa0) [0x824820] /usr/bin/mongod(thread_proxy+0x80) [0xaa4560] /lib/libpthread.so.0(+0x68ba) [0x7f1a33ef08ba] /lib/libc.so.6(clone+0x6d) [0x7f1a334ac02d] [rsSync] replSet syncTail: 0 assertion db/pdfile.cpp:1881, syncing: { ts: Timestamp 1327872847000|109, h: -1582883220170752094, op: "i", ns: "DB_MONGODB.tmp.mr.COLL_MONGODB_396779", o: { _id: "#colorsplash", value: 1.0 } } ~~~ Cela semble être une corruption de la base côté slave... L'une des solutions consiste à resynchroniser complètement la base (voir plus haut). ### Forcer à changer de master ~~~ > rs.stepDown() ~~~ /!\ à ne faire que si les slaves sont synchros sous peine d'avoir un état rollback & ennuis... ### Etat ROLLBACK Master devient indispo alors que les slaves n'était pas 100% synchro ROLLBACK -> RECOVERY -> SECONDARY.. ou #FAIL avec Error RS102 ### replicaset lag ## Réparer la base de données en cas de crash Plusieurs méthodes selon cas. 1. Si la journalisation est activé, ce qui est le cas par défaut pour les version >1.9.2 et en 64 bits. MongoDB devrait automatiquement se servir des fichiers journaux, regardez si tout se passe bien dans les logs. Si malheureusement ce message apparaît : ~~~ old lock file: mongod.lock. probably means unclean shutdown, but there are no journal files to recover. ~~~ Il faut vérifier que le système de fichier est OK ! 1. Si la journalisation n'est pas activé. Supprimez le verrou et démarrer mongodb avec l'option pour lancer une réparation. ~~~ rm /var/lib/mongodb/mongod.lock mongod --dbpath /var/lib/mongodb/ --repairpath /tmp --repair ~~~ Vérifiez les droits du dbpath ! ~~~ chown -R mongodb:mongodb /var/lib/mongodb ~~~ Démarrez mongodb, lancez un mongo shell et lancer une réparation de toutes les base de données. ~~~ db.repairDatabase(); ~~~ ## Mise à jour ### 1.8 vers 2.0 Voici la procédure pour passer en Mongo 2.0 (version sortie en sept/oct 2011) : ~~~ # aptitude update # aptitude install mongodb-10gen ~~~ La version 2.0 active désormais par défaut la journalisation. Vous pouvez donc remplacer dans votre configuration : ~~~ journal = true ~~~ par : ~~~ # Disables write-ahead journaling # nojournal = true ~~~ Il faut également mettre-à-jour ses indexes ! On le fera via le mongo shell : ~~~ > use foo > db.bar.getIndexes() [ { "key" : { "_id" : 1 }, "ns" : "foo.bar", "name" : "_id_", "v" : 0 } ] ~~~ Le * "v" : 0 * signifie que l'index n'est pas à jour. ~~~ > db.runCommand({compact : 'bar'}) { "ok" : 1 } > db.bar.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "foo.bar", "name" : "_id_" } ] ~~~ Répéter l'opération pour toutes les collections ayant des indexes ! ## CAPPED ## Monitoring avec MMS MMS (MongoDB Monitoring Service) est une service fourni gratuitement par 10gen. *Déprécié, maintenant c'est payant et ça s'apelle MongoDB Cloud Manager* ### Installation Créer un compte sur mms.10gen.com, créer un groupe et télécharger l'archive (qui contient déjà la clé API du groupe). La décompresser dans un dossier (et donner les droits mongodb). ~~~ cd /opt tar zxvf 10gen*.tar.gz chown -R mongodb:mongodb mms-agent ~~~ Installer python-bson et python-pymongo (via backports). /etc/apt/preferences: ~~~ Package: python-pymongo Pin: release a=squeeze-backports Pin-Priority: 999 ~~~ Le lancer via le compte mongodb: sudo -u mongodb nohup python /opt/mms-agent/agent.py > /var/log/mongodb/agent.log 2>&1 & ## Monitoring avec Munin ### Créer un accès ~~~ use admin db.createUser( { user: "monitoring", pwd: "XXX", roles: [ "clusterMonitor" ] } ) ~~~ ### Plugin mongo-munin ~~~ # git clone /tmp/mongo-munin # mkdir -p /usr/local/share/munin/plugins # cp /tmp/mongo-munin/mongo_* /usr/local/share/munin/plugins # cd /etc/munin/plugins/ # ln -s /usr/local/share/munin/plugins/mongo_* # chmod -R u=rwX,g=rwX,o=rX /usr/local/share/munin/ ~~~ /etc/munin/plugin-conf.d/mongo ~~~ [mongo_*] env.MONGO_DB_URI mongodb://monitoring:XXX@localhost:27017/admin ~~~