venerdì 14 ottobre 2011

MongoDB and Java - Checking cluster status

Java Example for monitoring MongoDB Cluster.

package freedbtoMongoDb;

import com.mongodb.DB;
import com.mongodb.Mongo;
import java.util.ArrayList;
import java.util.List;

public class CheckCluster {

    static String host = "192.168.0.72";
    static int[] ports = {
        //replica1
        20001, 20002, 20003, 20005,
        //replica11
        20011, 20012, 20013,
        //configsvr1
        20050,
        //configsvr2
        20060,
        //configdb1
        20100,
        //configdb2
        20101
    };

    public static void main(String[] args) {

        try {

            while (true) {
                Thread.sleep(10000);

                for (int port : ports) {

                    try {
                        Mongo m = new Mongo(host, port);
                        List add_l = m.getAllAddress();
                        System.out.println("address:" + add_l);
                        System.out.println("Version: " + m.getVersion());

                        if (m.getReplicaSetStatus() != null) {
                            System.out.println("Replica Name: " + m.getReplicaSetStatus().getName());
                        }

                        ArrayList db_ll = (ArrayList) m.getDatabaseNames();
                        System.out.println("db_list:" + db_ll);
                        for (String db_name : db_ll) {
                            DB d = m.getDB(db_name);
                            System.out.println(db_name + ": " + d.getStats().get("ok") + " - fileSize: " + Double.parseDouble(d.getStats().get("fileSize").toString()) / 1024 + "MB");
                        }

                        m.close();

                        System.out.println();
                    } catch (Exception e) {
                        System.out.println("Problemi sul db: " + port + "\n" + e.getMessage());
                        //send Mail
                    }
                }

            }
        } catch (Throwable t) {
                   //send Mail
        }
    }
}

[download source]

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.

--------









martedì 4 ottobre 2011

MongoDB query e qualche test con indici

Utilizzando il db precedentemente creato eseguo qualche query per verificare la velocità:

db.freedb.disk.find({"artist":"Porcupine Tree"}).skip(0).limit(0)

324 risultati
92,81 secondi

Eseguo nuovamente la query precedente ed ottengo gli stessi tempi, quindi non si è creato una cache per la query.

Eseguo la stessa operazione dal codice java:



package freedbtoMongoDb;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.Mongo;

public class Queries {

    static String host = "mongodb1";
    static int port = 27017;
    static String db_name = "freedb";

    public static void main(String[] args) {

        try {

            Mongo m = new Mongo(host, port);

            DB db = m.getDB(db_name);
            DBCollection coll = db.getCollection("disk");

            BasicDBObject query = new BasicDBObject();
            long t1 = System.currentTimeMillis();
            query.put("artist", "Porcupine Tree");


            DBCursor cur = coll.find(query).limit(0).skip(0);
            long t2 = System.currentTimeMillis();
            System.out.println("Tot time Find: " + (t2 - t1));

            while (cur.hasNext()) {
                System.out.println(cur.next());
            }
            long t3 = System.currentTimeMillis();
            System.out.println("Tot time cursor: " + (t3 - t2));

            m.close();

        } catch (Exception e) {

            System.out.println("Exception :" + e.getMessage());
        }
    }
}


Ottengo i seguenti risultati suddivisi per farte di find e retrive dei dati, da quello che si nota la lentezza è nel periodo di retrive dei dati.





Tot time Find: 2
{ "_id" : { "$oid" : "4e846f2330042d8d3130aad3"} , "id" : "blues_480f5d06" , "filename" : "blues/480f5d06" , "revision" : "7" , "title" : "The Sky Moves Sideways" , "genre" : "Rock" , "artist" : "Porcupine Tree" , "length" : "3935" , "year" : "1995" , "extd" : "YEAR: 1995 ID3G: 17" , "tracks" : { "3" : { "title" : "Prepare Yourself"} , "2" : { "title" : "The Moon Touches Your Shoulder"} , "1" : { "title" : "Dislocated Day"} , "0" : { "title" : "The Sky Moves Sideways (phase one)"} , "5" : { "title" : "The Sky Moves Sideways (phase two)"} , "4" : { "title" : "Moonloop"}}}}
etc..
etc..

Tot time cursor: 61270 (1 minuto abbondante)
BUILD SUCCESSFUL (total time: 1 minute 2 seconds)

adesso provo a restringere la query su determinati campi, ad esempio sul nome dell'album (field title).

db.freedb.disk.find({"artist":"Porcupine Tree"}, {title:1}).skip(0).limit(0)

con il terminale stesso risultato precedente:


324 risultati
92,81 secondi
con il seguente codice java:


package freedbtoMongoDb;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.Mongo;

public class Queries {

    static String host = "mongodb1";
    static int port = 27017;
    static String db_name = "freedb";

    public static void main(String[] args) {

        try {

            Mongo m = new Mongo(host, port);

            DB db = m.getDB(db_name);
            DBCollection coll = db.getCollection("disk");

            BasicDBObject query = new BasicDBObject();


            query.put("artist", "Porcupine Tree");

            BasicDBObject field = new BasicDBObject();
            field.put("title", "1");

            long t1 = System.currentTimeMillis();
            DBCursor cur = coll.find(query, field).limit(0).skip(0);
            long t2 = System.currentTimeMillis();
            System.out.println("Tot time Find: " + (t2 - t1));

            while (cur.hasNext()) {
                System.out.println(cur.next());
            }
            long t3 = System.currentTimeMillis();
            System.out.println("Tot time cursor: " + (t3 - t2));

            m.close();

        } catch (Exception e) {

            System.out.println("Exception :" + e.getMessage());
        }
    }
}





Risultato:

Tot time Find: 1
{ "_id" : { "$oid" : "4e846f2330042d8d3130aad3"} , "title" : "The Sky Moves Sideways"}
{ "_id" : { "$oid" : "4e846f2330042d8d3130add5"} , "title" : "The Sky Moves Sideways"}
{ "_id" : { "$oid" : "4e846f2330042d8d3130bb1a"} , "title" : "The Sky Moves Sideways"}
{ "_id" : { "$oid" : "4e846f5830042d8d3134caaa"} , "title" : "BBC Sessions 1993 & 1995"}
{ "_id" : { "$oid" : "4e846faa30042d8d31379b9d"} , "title" : "XM ReTracked"}
{ "_id" : { "$oid" : "4e846fba30042d8d3138cc14"} , "title" : "Lightbulb Sun"}
etc.
etc.
etc.
Tot time cursor: 73556
BUILD SUCCESSFUL (total time: 1 minute 14 seconds)



Le tempistiche si mantengono molto vicine al precedente test anche con l'estrazione di un singolo campo.

A questo punto creo un indice semplice sul campo artist.

Eseguo nuovamente i test precedenti.

il primo:


console:
db.freedb.disk.find({"artist":"Porcupine Tree"}).skip(0).limit(0)

324 risultati tempo 0,01 s

in java:


Tot time cursor: 557

il secondo:


console:
db.freedb.disk.find({"artist":"Porcupine Tree"}, {title:1}).skip(0).limit(0)



324 risultati tempo 0,00 s

in java:

Tot time cursor: 63

diciamo che gli indici aiutano parecchio....



[sorgenti in NetBeans]



sabato 1 ottobre 2011

MongoTorino - 1st Ottobre 2011 - appunti sparsi



Appunti sparsi della giornata

Politecnico di Torino 1 ottobre 2011 aula 10d.

----------------------------
@FlaPer87

- memory mapped files : alloca memoria (usare free)
- lock gloabal : molti possono leggere ma uno solo lo può scrivere.
- scritture asincrone in coda di scrittura.
- usare il lock per collection (prossima release).
- indici: non possono essere cambiati solo b-tree, possono essere interpretate in modo diverso (es index di geoloc). MongoDB elabora solo un indice per volta.
- cpu: la scrittura usa un core solo, in lettura usa più core, Spidermonkey in javascript è single core mono thred.
- map reduce non disponibile fino alla v8, locks in lettura,locks sulla map, lock sulla reduce, lock sulla write, (lock di scrittura su tutta l'istanza del db).
Usare mapreduce non su strutture principali.
- Scripting usa Spidermonkey, v8 multithreading.
- java jpa si può implementare uno scripting in jvm.
- mongodb mapreduce single core causato dalla limitante dell'engine javascript.
- mongodb è un document store, molto vicino a json e python utile e vicino al linguaggio di programmazione.
- mongoodb spedisce molte info in parallelo, no join e le transaction.
- sharding: molto complesso sulla concororrenza e consistenza del dato.

che db usare:
- che tipo di gestione del dato devo fare?
- che tipo di interazione del dato?
- che modelli devo disegnare? ( oppure ristrutturare i modelli)
- adattare i modelli al db che si usa.
- se estraggo un doc e mi serve sempre un doc correlato uso un embedding altrimenti una reference.
- In memoria (cache) rimane il documento e non la query (uso degli indici sul b-tree), cache a lista.
- sharding degli indici (vedi Kristina della 10gen), esiste un master punti a mongoS che conosce dove viene posizionati gli indici, quindi gli indici sono distribuiti.
- limiti del doc in collection di 16 MB.
- Foursquare tutti i check-in sono in mongodb.

update degli appunti direttamente da @FlaPer nei commenti.


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

Diego Guenzi - CSP (centro ricerca)

Web scalabile con Nginx e MongoDB
- test su Nginx - php - mongodb
- scalabilità verticale (comprare hardware della macchina più costi) /orizzontale (più server meno costi)
- rdmbs poca scalabilità orizzontale.
- nosql molta scalabilità orizzontale.
- teorema CAP (Partition Tolerance,Availability,Consistency).
- teorema CAP - C.A. per rdbms
- teorema CAP - P.A. per nosql
- teorema CAP - C.P. per nosql
- bisogna decidere da che tipologia di prestazioni si vogliono avere.
- rdbma modello ACID
- dbms modello BASE (dato non consistente in maniera completa)
- Replica distibuisco su più nodi le stesse info nel caso di network partitionig il db replica i dati e aggiorna successivamente (eventuali conflitti).
- sharding: le info sono distribuite su più server.
- si può mischiare sharding e replica per ottenere buone performance.
- test specifici con ycsb di yahoo.
- mongos per sharding, l'ottimale è sharding+repliche (le repliche devono essere dispari).
- client nginx.
- oracle Exadata (si può clonare con mongo).
- nosql senza standard.
- server web scalabili: tornado,lighttpd, cherokee (sfida delle 10000 connessioni).
- nginx - veloce e low balancing compreso.
- nginx - php - mongodb - aggiungo una macchina clono il tutto ed ogni macchina ha tutto.
- altra soluzione nginx davanti, cluster di nginx e php con solo il driver e una macchina per lo storage.
- altra nginx sul load balancer, macchine con php e macchine sotto con storage.

------------------------------------------------
ore 14:00 - Brendan McAdams 10gen, inc.

mongodb and the jvm
- java driver 2.6.5
- vari esempi di codice basilari...
- scala...
- object -> document
- ODMS in java Morphia (JPA inspired,Annotation driven) e Spring-DataDocument (data-system,Spring paradigms,mutiple datastorage)
- Hadoop + Mongo
- no-web app : logging (graylog2,flume sink)
- WTF:
- le dimensioni collection sono disegnate oer la Replica.
- i documenti sono mantenuti in ordine di inserimento
- cursore di tipo Tailable. (molto efficiente per le query senza indici)
- Messaggistica veloce sul broadcast.

-----------------------------------------------
ore 14:30 - Realtime Analytics using mongodb, phyton source forge.

- couchdb no performance
- new platfom with mongodb
- zarkov (async tpc server,inc validate).
- Bson - ZeroMQ - journal - write log - commit greenlet - Mongo Cronjob.
- mongorestore is fast, but locks a lot.
- indexing is nice, but slows use _id when you can.
- use databases to partition really big data, not collections.

------------------------------------------------
15:14 - new fetured v 2.0 Brendan McAdams 10gen

- journaling compressed
- command compact (old repair)
- old repair (double space on database on disk)
- command compat (defrag individual collections,more fash and light)
- replica sets (priorirties (node with highest prioirty become primary), reconf,tags,majority write concerns)
- indici pù leggeri
- stack defaul 1mb
- geospatial indexing

------------------------------------------------
15:40 - GridFS - Mitch Pirtle

- i metadata sono separati e possono comodamente stare in un array di metadata
- add attribute to store file
- Replica set - ridondare
- master-slave - performance
- sharding - scalare
- i file vengono splittati a blocchi


----

Questi sono solo appunti, che dovrò approfondire, presi durante l'ottima giornata.