How To – ambiente di test per mongodb – uso Sharding

Vedremo qui alcune operazioni per la gestione dello sharding in mongodb. Utilizzeremo l’ambiente di test utilizzato nell’articolo precedente.

Vedremo come aggiungere e togliere nodi allo sharding e come attivare lo sharding ai db e alle collections.

Per prima cosa verifichiamo che tutti i demoni sono presenti;
ps aux|grep mongo
dovrebbe restituire tre config server, 1 control server e 6 data server.

Connettiamoci al control server e di li entriamo nel db admin per vedere gli elementi dello sharding

mongo --port 27021
use admin
db.runCommand( {listshards:1} )

Si otterrà qualche cosa come

mongos> db.runCommand( {listshards:1} )
{
"shards" : [
{
"_id" : "rs1",
"host" : "rs1/localhost:27101,localhost:27102"
},
{
"_id" : "rs2",
"host" : "rs2/localhost:27201,localhost:27202"
}
],
"ok" : 1
}

E’ possibile rimuovere un elemento dello sharding

db.runCommand( {removeShard: "rs1/localhost:27101,localhost:27102"} )

L’operazione richiede del tempo perché comporta la ridistribuzione dei dati sugli altri shards. Il comando

db.printShardingStatus()

o

sh.status()

mostra lo stato dello sharding e quindi il progresso di questa operazione.
Altre informazioni si possono avere ripetendo il comando di rimozione.

Per aggiungere un replicaset allo sharding

db.runCommand( {addShard: "rs1/localhost:27101"} )

E’ il caso di sottolineare che tutto questo prepara solamente l’infrastruttura dello sharding che, essendo intimamente legato alla struttura dei dati richiede per essere attivato realmente degli interventi a livello di collection e database.

Procediamo quindi con la creazione di un set minimale di dati.
Per prima cosa ci si connette al control server:

mongo --port 27021

Creiamo quindi il nuovo db e verifichiamo

use mydb
db

Creiamo due documenti

a = { name : "pippo", city : "topolinia" }
b = { name : "paperino", city : "paperinia" }

e, infine, inseriamoli in una collection

db.personaggi.insert( a )
db.personaggi.insert( b )

Verificiamo quindi quanto è stato fatto

show collections
db.personaggi.find()

Passiamo allo sharding vero e proprio. Abilitiamo lo sharding sul database

sh.enableSharding( "mydb" )

e sulla collection

db.personaggi.ensureIndex( { "city": 1 } )
sh.shardCollection("mydb.personaggi", { "city": 1 } )

Il primo comando crea un indice sul campo city. Questo indice è necessario per poter fare lo sharding.
Ora il comando sh.status() mostrerà la lista e la posizione dei chunk (partizioni) della collection di cui è stato effettuato lo sharding.
Essendo pochissimi i documenti si troveranno tutti sullo stesso nodo. Il chunk ha infatti di default una dimensione di 64MB riducibile fino a 1MB; possiamo però divertirci a spostare sull’altro shard il chunk contenente la city topolinia:

db.adminCommand( { moveChunk : "mydb.personaggi", find : {city : "topolinia"}, to : "rs2" } )

e verificare il risultato con

sh.status()

La scelta della chiave dello sharding e in misura minore della dimensione dei chunk sono essenziali per determinare le prestazioni del cluster ma è argomento che va oltre lo scopo di questo post.

How To – ambiente di test per mongodb – uso ReplicaSet

Vedremo qui alcune operazioni per la gestione del ReplicaSet. Utilizzeremo l’ambiente di test utilizzato nell’articolo precedente.

In particolare vedremo come effettuare il takeover di un ReplicaSet, e come aggiungere o togliere un nodo dal cluster.

Per prima cosa verifichiamo che tutti i demoni sono presenti;
ps aux|grep mongo
dovrebbe restituire qualche cosa come

mongodb 5570 0.4 1.2 261884 46924 ? Sl 09:48 0:14 /usr/bin/mongod --port 27001 --dbpath /var/lib/mongodb/cfg1 --configsvr --fork --rest --logpath /var/log/mongodb/cfg1.log
mongodb 5627 0.4 1.2 261884 46984 ? Sl 09:58 0:10 /usr/bin/mongod --port 27002 --dbpath /var/lib/mongodb/cfg2 --configsvr --fork --rest --logpath /var/log/mongodb/cfg2.log
mongodb 5642 0.4 1.2 261896 46964 ? Sl 09:58 0:10 /usr/bin/mongod --port 27003 --dbpath /var/lib/mongodb/cfg3 --configsvr --fork --rest --logpath /var/log/mongodb/cfg3.log
mongodb 5659 0.3 0.0 108680 3632 ? Sl 09:59 0:09 /usr/bin/mongos --port 27021 --configdb localhost:27001,localhost:27002,localhost:27003 --fork --logpath /var/log/mongodb/ctrl.log
mongodb 5696 0.4 0.7 2671608 31244 ? Sl 09:59 0:11 /usr/bin/mongod --port 27101 --dbpath /var/lib/mongodb/rs11 --replSet rs1 --shardsvr --rest --fork --logpath /var/log/mongodb/rs11.log
mongodb 5757 0.4 1.2 630700 47208 ? Sl 09:59 0:10 /usr/bin/mongod --port 27103 --dbpath /var/lib/mongodb/rs1a --replSet rs1 --rest --fork --logpath /var/log/mongodb/rs1a.log
mongodb 6645 0.5 0.8 3049440 32212 ? Sl 10:03 0:13 /usr/bin/mongod --port 27102 --dbpath /var/lib/mongodb/rs12 --replSet rs1 --shardsvr --rest --fork --logpath /var/log/mongodb/rs12.log
mongodb 7103 0.4 1.2 4783104 47512 ? Sl 10:08 0:09 /usr/bin/mongod --port 27201 --dbpath /var/lib/mongodb/rs21/ --replSet rs2 --shardsvr --rest --fork --logpath /var/log/mongodb/rs21.log
mongodb 7194 0.4 1.2 3016636 47316 ? Sl 10:08 0:08 /usr/bin/mongod --port 27202 --dbpath /var/lib/mongodb/rs22/ --replSet rs2 --shardsvr --rest --fork --logpath /var/log/mongodb/rs22.log
mongodb 7399 0.4 1.2 5093292 47060 ? Sl 10:09 0:08 /usr/bin/mongod --port 27203 --dbpath /var/lib/mongodb/rs2a --replSet rs2 --rest --fork --logpath /var/log/mongodb/rs2a.log

ovvero tre config server, 1 control server e 6 data server.

Come passo successivo verifichiamo lo stato dei ReplicaSet. Per farlo ci connettiamo al nodo primary di ogni replicaset, eventualmendo provando i vari nodi fino a trovare quello che si presenta come primary al prompt. Una volta dentro si richiede la configurazione attuale e lo stato della replica. In comandi

mongo --port 27101
rs.config()
rs.status()

I risultati di questi comandi sono abbastanza parlanti.

E’ possibile cambiare il nodo primario. Se tutti i nodi sono presenti si può dire al sistema di farlo, se il nodo primario dovesse morire invece il processo sarebbe automatico.
Trattandosi di un’ambiente di test simuliamo la morte del nodo primario con un kill e osserviamo il takeover del cluster. Utilizzando nel kill il PID ricavato in precedenza:

kill

non essendoci attività in corso nel cluster il takeover sarà quasi immediato; attenzione che in un sistema di produzione sotto carico può essere necessario del tempo.
Se ci si connette quindi al nuovo Primary e si osserva lo stato del cluster:

mongo --port 27102
rs.status()

si vedrà che il vecchio nodo primary risulta ora non raggiungibile.
Se lo riavviamo

sudo -u mongodb /usr/bin/mongod --port 27101 --dbpath /var/lib/mongodb/rs11 --replSet rs1 --shardsvr --rest --fork --logpath /var/log/mongodb/rs11.log

il nodo rientrerà come secondary. Se nel frattempo fossero intervenute modifiche ai dati il nodo appena reinserito riallineerebbe i propri dati prima di rientrare realmente in gioco. Nel caso fosse passato troppo tempo e non fossero più presenti i passi incrementali tutti i dati verrebberio ritrasferiti al secondary.
Vediamo ora come Spostare il primario su di un’altro nodo. Per farlo bisogna, lavorando sul nodo primary, recuperare la configurazione attuale.

mongo --port 27102

da prompt

cfg = rs.config()

assegnare diverse priorità ai nodi

cfg.members[0].priority = 1
cfg.members[1].priority = 0.5

attivare la nuova configurazione

rs.reconfig(cfg)

Dopo qualche secondo il nodo a cui si è connessi diventerà secondario e l’altro primario.

E’ infine possibile togliere e aggiungere nodi da un replicaset. E’ sempre preferibile effettuare queste operazioni con i nodi coinvolti attivi.
Iniziamo rimuovendo il nodo secondary.
Entriamo nel nodo primary e rimuoviamo il nodo secondary:
mongo --port 27101
rs.remove("localhost:27102")

la configurazione riporterà le modifiche e se ci si connette al nodo rimosso non risulterà più secondary al prompt.
Ripristiniamo ora il nodo
mongo --port 27101
rs.add("localhost:27102")

Non essendoci molti dati da aggiornare il nodo risulterà presto come secondary.