Un replicaset es un grupo de instancias de Mongo que mantienen el mismo dataset o conjunto de datos, de este modo los datos estarán replicados en diferentes servidores consiguiendo alta disponibilidad de nuestras bases de datos. En cuanto a nuestra aplicación tan solo debemos pasarle la lista de servidores al driver de conexión que utilicemos y este transparentemente se conectará al servidor correcto.
La topologÃa de un replicaset(RS) de Mongo define tres figuras:
- Primary: Servidor primario del RS, los clientes se conectan a este por defecto para ejecutar las querys, tanto lecturas como escrituras.
- Secondary: Servidor con los datos del Primary server replicados.
- Arbiter: Servidor sin datos, tan solo vota a la hora de elegir un nuevo Primary server.
NOTA: Las votaciones para elegir un Primary server se realizan cuando hay algún cambio de topologÃa. Mongo no recomienda el uso de RS con Arbitros, vale la pena montar un nodo mas con el dataset replicado.
En este artÃculo se irá indicando en mayúsculas donde se deben ejecutar ciertos comandos, si es en el Primary en el Secondary o en Todos los servidores.
TODOS
Compilamos e instalamos MongoDb:
Bindeamos el servicio a todas las ips:
bind_ip = 0.0.0.0
PRIMARY
Accedemos a la CLI de MongoDb:
Creamos el usuario admin:
use admin
db.createUser(
{
user: "admin",
pwd: "PASSWORD",
roles: [ "root" ]
}
)
Creamos el usuario de admin del RS:
db.createUser(
{
user: "clusterAdmin",
pwd: "PASSWORDRS",
roles: [ "root" ]
}
)
TODOS
Habilitamos la autenticación:
security:
authorization: enabled
Reiniciamos el servicio:
PRIMARY
Los nodos de un RS de Mongo se comunican de forma segura entres ellos ya sea por certificados SSL que deberán ser renovados cada X tiempo o por ficheros de keys.
Generamos los ficheros de keys:
chmod 400 /etc/mongodb.key
chown mongodb:mongodb /etc/mongodb.key
Copiamos la key a todos los servers del RS y le asignamos los mismos permisos que antes.
TODOS
security:
keyFile: /etc/mongodb.key
replication:
replSetName: rs0
Reiniciamos el servicio:
PRIMARY
rs.initiate(
{
_id : 'rs0',
members: [
{ _id : 0, host : "kr0mtest:27017" },
{ _id : 1, host : "kr0mtest2:27017" },
{ _id : 2, host : "kr0mtest3:27017" }
]
}
)
rs0:SECONDARY>
Al rato se elegirá un PRIMARY:
rs0:PRIMARY> rs.status()
{
"set" : "rs0",
"date" : ISODate("2020-04-17T10:38:46.841Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1587119903, 1),
"members" : [
{
"_id" : 0,
"name" : "kr0mtest:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 265286,
"optime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-04-17T10:38:43Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1586854672, 1),
"electionDate" : ISODate("2020-04-14T08:57:52Z"),
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "kr0mtest2:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 84614,
"optime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-04-17T10:38:43Z"),
"optimeDurableDate" : ISODate("2020-04-17T10:38:43Z"),
"lastHeartbeat" : ISODate("2020-04-17T10:38:44.999Z"),
"lastHeartbeatRecv" : ISODate("2020-04-17T10:38:44.998Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "kr0mtest3:27017",
"syncSourceHost" : "kr0mtest3:27017",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "kr0mtest3:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 265265,
"optime" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1587119923, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2020-04-17T10:38:43Z"),
"optimeDurableDate" : ISODate("2020-04-17T10:38:43Z"),
"lastHeartbeat" : ISODate("2020-04-17T10:38:45.870Z"),
"lastHeartbeatRecv" : ISODate("2020-04-17T10:38:45.888Z"),
"pingMs" : NumberLong(1),
"lastHeartbeatMessage" : "",
"syncingTo" : "kr0mtest:27017",
"syncSourceHost" : "kr0mtest:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1587119923, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1587119923, 1),
"signature" : {
"hash" : BinData(0,"xSsKDy+0YUJcBM4vpFN0VaJa+rg="),
"keyId" : NumberLong("6815488928334741505")
}
}
}