mercoledì 12 ottobre 2011

MongoDB - Cluster - Sharding and Replica Set


Questa è una configurazione di prova per eseguire dei test sulle possibilità di Cluster con Treplica Set e e bilanciamento del carico con MongoDB (Sharding), il test viene eseguito su una macchina sola, in realtà ogni server mongo deve essere residente su una macchina separata

  •  creo le cartelle per i vari db


/data/r1
/data/r2
/data/r3

/data/r11
/data/r12
/data/r13

/data/cfg1
/data/cfg2

  • configuro ed eseguo i due blocchi di replica (2 blocchi da 3 server)


./mongod --replSet replica1 --dbpath /data/r1 --port 20001 --rest 
./mongod --replSet replica1 --dbpath /data/r2 --port 20002 --rest
./mongod --replSet replica1 --dbpath /data/r3 --port 20003 --rest

./mongod --replSet replica11 --dbpath /data/r11 --port 20011 --rest 
./mongod --replSet replica11 --dbpath /data/r12 --port 20012 --rest
./mongod --replSet replica11 --dbpath /data/r13 --port 20013 --rest

nota: per ogni server è possibile avere l'esecuzione in background e il logging su file aggiungendo --fork --logpath /mongodb/log/<nome_del_file>.log --logappend 
  • eseguo la configurazione per agganciare i server replica.
./mongo localhost:20001

config = {
"_id" : "replica1",
"members" : [
{
"_id" : 1,
"host" : "localhost:20001"
},
{
"_id" : 2,
"host" : "localhost:20002"
},
{
"_id" : 3,
"host" : "localhost:20003"
}
]
}

rs.initiate(config);

----

./mongo localhost:20011

config = {
"_id" : "replica11",
"members" : [
{
"_id" : 1,
"host" : "localhost:20011"
},
{
"_id" : 2,
"host" : "localhost:20012"
},
{
"_id" : 3,
"host" : "localhost:20013"
}
]
}

rs.initiate(config);

----


è possibile accedere alla parte di info via web (opzione --rest) su http://192.168.0.75:21001/ e http://192.168.0.75:21011/

  •  server cfg

./mongod --configsvr --dbpath /data/cfg1 --port 20050 --rest

da qui l'interfaccia web:

http://192.168.0.75:21050/


./mongod --configsvr --dbpath /data/cfg2 --port 20060 --rest

  • Mongo finali

 due mongod per accedere con i client

 ./mongos --configdb localhost:20060 --port 20100 
 ./mongos --configdb localhost:20050 --port 20101 

  • Configurazione Sharding

Collego al mogos finale (che rappresentano la punta del mio sistema)

./mongo localhost:20100
use admin
db.runCommand( { addshard : "replica1/localhost:20001,localhost:20002,localhost:20003" } );
db.runCommand( { addshard : "replica11/localhost:20011,localhost:20012,localhost:20013" } );
  
db.runCommand( { listshards : 1 } );

 a questo punto lo shard su replica è configurato

Primo test, se mi collego al ./mongo localhost:20100 ed eseguo db.runCommand( { listshards : 1 } ); ottengo le configurazioni uguali quindi le info sono propagate a tutto il cluster

------

- a questo punto il client a cui devo accedere sono localhost:20100 e localhost:20101 che sono due erogazioni che dovrebbero essere gestite automaticamente dal driver della mia app.

- il parametro --rest serve ad abilitare l'interfaccia rest del browser. Ogni server è raggiungibile da ip:<porta+1000> es se il server è su localhost:20003 la sua parte web è su http://localhost:21003
  • Test di propagazione
- Collego con una piccola app in java al mongos 20100.
- Carico su un db qualche milione di riga, il cluster propaga e sparpaglia i db interi creati su un ramo di replica e l'altro (replica1 e replica11).
  •  Shard del singolo db: 
./mongo localhost:20100
use admin
db.runCommand( { enablesharding : "freedb" } );
  • Shard di una collection
eseguo uno shard della collection

db.runCommand( { shardcollection : "freedb.disc" , key : { filename : 1 } } );


Dopo diversi db creati e milioni di righe inserite trovo con un ramo di shard corposo e uno quasi libero con soli con 2 db, questo è il risultato dell' autobalancer che appunto bilancia il carico.

  • Consistenza

Caduta di una macchina di replica:

ecco che mi cade un mongo del ramo  localhost:20002 (2), le repliche tengono senza problemi, 
la macchina si è demolita... (elimino il contenuto della cartella /data/r2).
dall'interfaccia web vedo che il server va in recovery: 
localhost:20002 2 RECOVERING initial sync need a member to be primary or secondary to do our initial sync 0:0
poi 
localhost:20002 2 RECOVERING initial sync cloning db: freedb21
etc.

Caduta di due macchina di replica:
butto giù le macchine localhost:20001 e localhost:20002
lancio la mia app, mentre sta girando la app si blocca (forse messa in attesa da driver), il ramo di replica localhost:20003 sembra bloccato, fermo la app.. nulla da fare.
rifaccio ripartire il server 20001, finalmente il 20003 si elegge primary e la app riprende le sue insert, quindi se cadono due macchine sul ramo è possibile che tutto si blocchi e rappresenta la criticità del cluster.

soluzione: creare un server arbiter che aiuti la elezione del master: 
http://tebros.com/2010/11/mongodb-arbiters-with-only-two-replicas/
http://www.mongodb.org/display/DOCS/Upgrading+to+Replica+Sets#UpgradingtoReplicaSets-AddingAnArbiter

mkdir /data/arb1
./mongod --rest --replSet replica1 --dbpath /data/arb1 --port 20005

poi.. cerco chi è il primary all'interno della replica1 dall'interfaccia web http://192.168.0.73:21001/_replSet è il localhost:20003

mongo localhost:20003
use admin
rs.addArb("localhost:20005");
rs.status();

a questo punto dall'interfaccia web http://192.168.0.73:21001/_replSet il server arbitrario è online.

..... il server localhost:20002 va in errore..... :  RECOVERING error RS102 too stale to catch up

http://www.mongodb.org/display/DOCS/Resyncing+a+Very+Stale+Replica+Set+Member

Elimino tutto il contenuto della cartella del cluster 20002  - rm -rf /data/r2/* rifaccio ripartire il server 20002 e riparte di resync

ok, a questo punto le conf sono le seguenti:

localhost:20001 - PRIMARY
localhost:20002 - SECONDARY
localhost:20003 - SECONDARY
localhost:20005 - ARBITER

proseguo con il test per verificare il funzionamento dell'ARBITER.
interrompo i server 20002 e 20001.
..no nulla da fare il server 20003 non viene eletto PRIMARY.. 
..neanche tentando di forzare il server 20003  a PRIMARY la cosa non funziona. 
...quindi per avere una replica consistente è necessario avere almeno 3 server in replica oppure 2 in replica e 1 con arbiter.

-------------

- elimino il contenuto della cartella /data/r2
- inserisco dei dati nel db

./mongo localhost:20100
mongos> use freedb21
switched to db freedb21
mongos> for(i=0;i<100000;i++) db.pippo.insert({"test":"prova","c":i});
mongos> db.pippo.count();
100001
......
......
mongos> db.pippo.count();
5418885

-- db sharding

 ./mongo localhost:20101
MongoDB shell version: 2.0.0
connecting to: localhost:20101/test
mongos> use admin
switched to db admin
mongos> db.runCommand( { enablesharding : "freedb21" } );
{ "ok" : 1 }

- il ramo /data/r2 non ricrea i vari file, devo fermare e far ripartire il server r2, a questo punto il server si sincronizza con tutti i rami della sua replica.

--------









2 commenti:

Unknown ha detto...

Ottimo articolo ma essendo nuovo su MongoDB ho poco chiare le conclusioni dell'esperimento.

Marco Berri ha detto...

Era per testare le casistiche di funzionamento e prestazioni.