Vamos a ver cómo configurar nuestros servicios mongod para disponer de una Replica Set y poder así disfrutar en nuestro sistema de alta disponibilidad y de replicación automática de datos.
Lo primero ha de ser tener instalado MongoDB en nuestro sistema. Si no sabéis cómo hacerlo podéis consultar estos artículos:
- http://www.mongodbspain.com/en/2014/11/06/install-mongodb-on-mac-os-x-yosemite/
- http://www.mongodbspain.com/en/2014/08/30/install-mongodb-on-ubuntu-14-04/
Configuración típica
La configuración típica está compuesta de tres nodos. Uno de ellos actuará como primario y los otros dos como secundarios. Como sabéis, la réplica de datos se hace siempre desde el primario hacia los secundarios.
Creación de directorios
Antes de levantar los servicios tenemos que crear los directorios donde vamos a guardar nuestros datos. En mi caso serán los directorios a0, a1 y a2:
1 2 3 4 5 6 7 8 |
juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ ll -rt total 40 drwxr-xr-x 11 mongodb mongodb 4096 dic 9 16:48 ../ drwxr-xr-x 2 root root 4096 dic 15 10:54 a0/ drwxr-xr-x 2 root root 4096 dic 15 10:54 a1/ drwxr-xr-x 2 root root 4096 dic 15 10:54 a2/ drwxr-xr-x 10 root root 4096 dic 15 10:54 ./ juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ |
Primer nodo
De la siguiente manera levantamos el servicio correspondiente al primer nodo:
1 2 3 4 5 |
juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ mongod --replSet a --dbpath /var/lib/mongodb/replicaset/a0 --logpath /var/lib/mongodb/replicaset/log.a0 --port 27000 --fork --logappend --smallfiles --oplogSize 50 about to fork child process, waiting until server is ready for connections. forked process: 4549 child process started successfully, parent exiting juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ |
Antes de hacer lo mismo con los dos nodos restantes voy a comentar el significado de cada opción utilizada (en la documentación oficial podemos consultar todas ellas):
- replSet Indicamos el nombre de la Replica Set a la que va a pertenecer nuestro servicio.
- dbpath Será el directorio donde se guardan nuestros datos.
- logpath <ruta/fichero> Fichero donde se guardará el log de todo lo que ocurra en el servicio.
- port Puerto a utilizar. MongoDB utilizar el puerto 27017 si no especificamos ninguno.
- fork Para que el servicio corra en background. Opcional.
- logappend Sirve para no vaciar el fichero de log en caso de que ya exista. Opcional.
- smallfiles Utilizado en entornos de desarrollo cuando no tenemos necesidad de grandes cantidades de datos.
- oplogSize <tamaño> Utilizado en entornos de desarrollo para limitar el tamaño del fichero de operaciones log. Este fichero es usado para poder llevar a cabo la replicación.
Nodos restantes
Ahora que ya hemos comprendido lo que estamos haciendo, levantamos los dos nodos restantes:
1 2 3 4 5 6 7 8 9 |
juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ mongod --replSet a --dbpath /var/lib/mongodb/replicaset/a1 --logpath /var/lib/mongodb/replicaset/log.a1 --port 27001 --fork --logappend --smallfiles --oplogSize 50 about to fork child process, waiting until server is ready for connections. forked process: 4670 child process started successfully, parent exiting juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ mongod --replSet a --dbpath /var/lib/mongodb/replicaset/a2 --logpath /var/lib/mongodb/replicaset/log.a2 --port 27002 --fork --logappend --smallfiles --oplogSize 50 about to fork child process, waiting until server is ready for connections. forked process: 4717 child process started successfully, parent exiting juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ |
En caso de tener los nodos en máquinas distintas no es necesario que especifiquemos ningún puerto. De esta forma, todos ellos escucharán en el 27017, cada uno de su máquina.
Comprobamos que los tres servicios están corriendo:
1 2 3 4 5 6 |
juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ ps -ef | grep mongo root 4549 2561 0 15:02 ? 00:00:07 mongod --replSet a --dbpath /var/lib/mongodb/replicaset/a0 --logpath /var/lib/mongodb/replicaset/log.a0 --port 27000 --fork --logappend --smallfiles --oplogSize 50 root 4670 2561 0 15:18 ? 00:00:02 mongod --replSet a --dbpath /var/lib/mongodb/replicaset/a1 --logpath /var/lib/mongodb/replicaset/log.a1 --port 27001 --fork --logappend --smallfiles --oplogSize 50 root 4717 2561 0 15:19 ? 00:00:01 mongod --replSet a --dbpath /var/lib/mongodb/replicaset/a2 --logpath /var/lib/mongodb/replicaset/log.a2 --port 27002 --fork --logappend --smallfiles --oplogSize 50 juan 4771 4456 0 15:23 pts/1 00:00:00 grep --color=auto mongo juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ |
Configuración de la Replica Set
En este momento nuestros servicios están activos, pero de manera individual porque aún no hemos configurado la Replica Set. Eso es lo que vamos a hacer ahora.
Nos conectamos al primero de los nodos:
1 2 3 4 5 |
juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ mongo --port 27000 MongoDB shell version: 2.6.6 connecting to: 127.0.0.1:27000/test Hello Juan. Have a good day! > |
Si consultamos el estado de la Replica Set, o su configuración , vemos que aún está sin definir:
1 2 3 4 5 6 7 8 9 10 |
> rs.conf() null > rs.status() { "startupStatus" : 3, "info" : "run rs.initiate(...) if not yet done for the set", "ok" : 0, "errmsg" : "can't get local.system.replset config from self or any seed (EMPTYCONFIG)" } > |
Ejecutamos el siguiente comando para que MongoDB configure la Replica Set con el nodo al que estamos conectados y con la configuración mínima por defecto:
1 2 3 4 5 6 7 8 |
> rs.initiate() { "info2" : "no configuration explicitly specified -- making one", "me" : "juan-mongodbspain:27000", "info" : "Config now saved locally. Should come online in about a minute.", "ok" : 1 } > |
Y consultamos para ver que se ha incluido en la Replica Set:
1 2 3 4 5 6 7 8 9 10 11 12 |
> rs.conf() { "_id" : "a", "version" : 1, "members" : [ { "_id" : 0, "host" : "juan-mongodbspain:27000" } ] } a:PRIMARY> |
Si nos fijamos en el prompt devuelto podemos ver que está formado por el nombre de la Replica Set (a), seguido por dos puntos y por el tipo de nodo. En este caso y, al ser todavía el único, nuestro nodo es el primario.
Sólo nos falta añadir a nuestra Replica Set los dos nodos restantes:
1 2 3 4 5 |
a:PRIMARY> rs.add("juan-mongodbspain:27001") { "ok" : 1 } a:PRIMARY> rs.add("juan-mongodbspain:27002") { "ok" : 1 } a:PRIMARY> |
Vemos que la configuración de la Replica Set es correcta:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
a:PRIMARY> rs.conf() { "_id" : "a", "version" : 3, "members" : [ { "_id" : 0, "host" : "juan-mongodbspain:27000" }, { "_id" : 1, "host" : "juan-mongodbspain:27001" }, { "_id" : 2, "host" : "juan-mongodbspain:27002" } ] } a:PRIMARY> |
Y, por último, comprobamos que los tres nodos están funcionando correctamente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
a:PRIMARY> rs.status() { "set" : "a", "date" : ISODate("2014-12-15T14:50:03Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "juan-mongodbspain:27000", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2877, "optime" : Timestamp(1418654251, 1), "optimeDate" : ISODate("2014-12-15T14:37:31Z"), "electionTime" : Timestamp(1418653975, 2), "electionDate" : ISODate("2014-12-15T14:32:55Z"), "self" : true }, { "_id" : 1, "name" : "juan-mongodbspain:27001", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 755, "optime" : Timestamp(1418654251, 1), "optimeDate" : ISODate("2014-12-15T14:37:31Z"), "lastHeartbeat" : ISODate("2014-12-15T14:50:03Z"), "lastHeartbeatRecv" : ISODate("2014-12-15T14:50:02Z"), "pingMs" : 0, "syncingTo" : "juan-mongodbspain:27000" }, { "_id" : 2, "name" : "juan-mongodbspain:27002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 752, "optime" : Timestamp(1418654251, 1), "optimeDate" : ISODate("2014-12-15T14:37:31Z"), "lastHeartbeat" : ISODate("2014-12-15T14:50:01Z"), "lastHeartbeatRecv" : ISODate("2014-12-15T14:50:02Z"), "pingMs" : 0, "syncingTo" : "juan-mongodbspain:27000" } ], "ok" : 1 } a:PRIMARY> |
Podemos ver cómo los dos secundarios se sincronizan con el primario.
Lectura de un nodo secundario
¿Qué tenemos que hacer para leer de los secundarios? Lo primero sería conectarnos a ese secundario:
1 2 3 4 5 |
juan@juan-mongodbspain:/var/lib/mongodb/replicaset$ mongo --port 27001 MongoDB shell version: 2.6.6 connecting to: 127.0.0.1:27001/test Hello Juan. Have a good day! a:SECONDARY> |
Si intentamos leer ahora comprobamos que no podemos:
1 2 3 |
a:SECONDARY> db.name.find() error: { "$err" : "not master and slaveOk=false", "code" : 13435 } a:SECONDARY> |
Tenemos que ejecutar antes el siguiente comando:
1 |
a:SECONDARY> rs.slaveOk() |
Y ya podremos leer:
1 2 3 |
a:SECONDARY> db.name.find() { "_id" : ObjectId("548f041c4428b0b75a8ddca5"), "name" : "juan" } a:SECONDARY> |
En un próximo artículo hablaremos sobre cómo configurar un Sharded Cluster.