A continuación se describe el proceso para realizar una replicación de un servidor MongoDB, teniendo 2 equipos conectados en una red local, el maestro será Windows (192.168.1.70) y el esclavo Mac (192.168.1.68).
Cosas a tener en cuenta:
- Debe estar instalado MongoDB en ambos equipos
- Debe existir conexión entre el Maestro y el Esclavo (ping)
- Si están en una red no local, debe estár abierto el puerto 27017 en ambos equipos
En este ejemplo veremos como configurar un Master -> Windows Esclavo -> Mac
- Crear un archivo mongod.cfg en alguna ubicación, en este ejemplo estará en C:\\mongod.cfg y contendrá esta información:
storage:
dbPath: C:\\mongo_data\
net:
port: 27017
bindIp: 127.0.0.1,192.168.1.70
- Crear un archivo mongod.conf en alguna ubicación, en este ejemplo estará en /etc/mongod.conf y contendrá la siguiente información:
storage:
dbPath: /var/lib/mongo
net:
port: 27017
bindIp: 127.0.0.1,192.168.1.68
Ya que se tienen configurados ambos equipos, hay que ejecutar mongod para iniciar el servidor en ambos e indicarle que inicie con replicación:
MAC
mongod --replSet=rs0 --config=/etc/mongod.conf
Wndows
C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe --replSet=rs0 --config=/etc/mongod.conf
posteriormente, ya que se está ejecutando el servidor en ambos equipos, ejecutamos en la consola de cliente en el maestr (windows):
C:\Program Files\MongoDB\Server\3.4\bin\mongo.exe
y una vez dentro, lo siguiente:
conf = {
_id: "rs0",
members: [{
_id: 1,
host: 192.168.1.70
}]
}
rs.initiate(conf)
En caso de que ya se tenga una configucación anterior hay que sobreescribirla ejecutando:
rs.reconfig(conf, {force:true})
Una vez hecho esto hay que agregar a nuestros esclavos, en este caso solo hay uno:
rs.add("192.168.1.68:27017")
En este momento deberíamos ver mensajes en la terminal de ambos equipos, y si ejecutamos rs.status()
dentro de mongo/mongo.exe obtendremos algo así:
{
"set" : "rs0",
"date" : ISODate("2017-12-04T01:10:09.972Z"),
"myState" : 2,
"term" : NumberLong(3),
"syncingTo" : "192.168.1.70:27017",
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1512349810, 1),
"t" : NumberLong(3)
},
"appliedOpTime" : {
"ts" : Timestamp(1512349810, 1),
"t" : NumberLong(3)
},
"durableOpTime" : {
"ts" : Timestamp(1512349810, 1),
"t" : NumberLong(3)
}
},
"members" : [
{
"_id" : 1,
"name" : "192.168.1.70:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 162,
"optime" : {
"ts" : Timestamp(1512349810, 1),
"t" : NumberLong(3)
},
"optimeDurable" : {
"ts" : Timestamp(1512349810, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-12-04T01:10:10Z"),
"optimeDurableDate" : ISODate("2017-12-04T01:10:10Z"),
"lastHeartbeat" : ISODate("2017-12-04T01:10:08.995Z"),
"lastHeartbeatRecv" : ISODate("2017-12-04T01:10:08.994Z"),
"pingMs" : NumberLong(32),
"electionTime" : Timestamp(1512349659, 1),
"electionDate" : ISODate("2017-12-04T01:07:39Z"),
"configVersion" : 60147
},
{
"_id" : 2,
"name" : "192.168.1.67:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 164,
"optime" : {
"ts" : Timestamp(1512349810, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-12-04T01:10:10Z"),
"syncingTo" : "192.168.1.70:27017",
"configVersion" : 60147,
"self" : true
}
],
"ok" : 1
}
{
"set" : "rs0",
"date" : ISODate("2017-12-04T01:11:33.959Z"),
"myState" : 1,
"term" : NumberLong(3),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1512349890, 1),
"t" : NumberLong(3)
},
"appliedOpTime" : {
"ts" : Timestamp(1512349890, 1),
"t" : NumberLong(3)
},
"durableOpTime" : {
"ts" : Timestamp(1512349890, 1),
"t" : NumberLong(3)
}
},
"members" : [
{
"_id" : 1,
"name" : "192.168.1.70:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 305,
"optime" : {
"ts" : Timestamp(1512349890, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-12-04T01:11:30Z"),
"electionTime" : Timestamp(1512349659, 1),
"electionDate" : ISODate("2017-12-04T01:07:39Z"),
"configVersion" : 60147,
"self" : true
},
{
"_id" : 2,
"name" : "192.168.1.67:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 240,
"optime" : {
"ts" : Timestamp(1512349890, 1),
"t" : NumberLong(3)
},
"optimeDurable" : {
"ts" : Timestamp(1512349890, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-12-04T01:11:30Z"),
"optimeDurableDate" : ISODate("2017-12-04T01:11:30Z"),
"lastHeartbeat" : ISODate("2017-12-04T01:11:33.715Z"),
"lastHeartbeatRecv" : ISODate("2017-12-04T01:11:33.714Z"),
"pingMs" : NumberLong(56),
"syncingTo" : "192.168.1.70:27017",
"configVersion" : 60147
}
],
"ok" : 1
}
En el servidor maestro teniamos una base de datos llamada testrep para hacer pruebas, esta tiene una colección llamada col, si ejecutamos desde el servidor una prueba para ver los datos que se tienen veremos:
// dentro de mongo.exe
db = connect("localhost:27017/testrep")
db.getCollection("col").find({}) //buscar todos los documentos dentro de col
// Respuesta:
// { "_id" : ObjectId("5a248f5ee036aa8774c50160"), "asd" : 8 }
Si hacemos lo mismo en el esclavo (Mac):
// dentro de mongo
db = connect("localhost:27017/testrep")
db.getCollection("col").find({}) //buscar todos los documentos dentro de col
/* Respuesta:
Error: error: {
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk"
}
*
Para solucionar esto basta con ejecutar rs.slaveOk()
desde el esclavo, para hacerle saber a MongoDB que se permite hacer lecturas desde un esclavo
Intentando de nuevo despues de ejecutar este comando obtenemos:
db = connect("localhost:27017/testrep")
db.getCollection("col").find({})
{ "_id" : ObjectId("5a248f5ee036aa8774c50160"), "asd" : 8 }
Y Listo!, ahora ya tenemos replicado nuestro servidor de MongoDB, para agregar más esclavos basta con ejecutar rs.add() desde el servidor.
Información más detallada sobre las funciones usadas aquí: https://docs.mongodb.com/manual/replication/