Diferència entre revisions de la pàgina «MongoDB: escalant»
(Hi ha 6 revisions intermèdies del mateix usuari que no es mostren) | |||
Línia 4: | Línia 4: | ||
Per entendre aquest article convé llegir [[MongoDB]] i potser [[Pymongo]] | Per entendre aquest article convé llegir [[MongoDB]] i potser [[Pymongo]] | ||
+ | <br> | ||
== Escalabilitat en BBDD == | == Escalabilitat en BBDD == | ||
+ | Tenim diverses tècniques per escalar la velocitat de les nostres aplicacions: | ||
+ | * Millorant la velocitat de les consultes/insercions amb indexes. | ||
+ | * Utilitzant els paràmetres d'escriptura convenientment. | ||
+ | * Replicant les instàncies de MongoDB (lectura). | ||
+ | * '''Sharding''': distribuïnt les dades en diversos ''shards'' (escriptura). | ||
+ | |||
+ | En les instal·lacions en producció es pot combinar replicació i sharding. | ||
+ | |||
+ | <br> | ||
+ | |||
+ | == Indexes == | ||
+ | Un índex: | ||
+ | * Accelera la velocitat de lectura (consultes) si l'utilitzem convenientment. | ||
+ | * Disminueix la velocitat d'escriptura sempre, ja que cada cop que fem un inserció/update cal actualitzar l'índex. | ||
+ | |||
+ | Per tant, '''convé crear els índexos justos i necessaris per les consultes que volem, ja que amb cadascun que fem ralentitzarà les escriptures'''. | ||
+ | |||
+ | <br> | ||
+ | |||
+ | == Paràmetres d'escriptura == | ||
+ | Quan realitzem una escriptures a la BBDD tenim dos paràmetres: | ||
+ | * '''w -> wait''' (esperem a que s'hagi escrit a memòria) | ||
+ | * '''j -> journal''' (efectiva persistència en disc) | ||
+ | Aquests paràmetres son importants a la nostra aplicació ja que ens determinen què fem quan escrivim a la BBDD. Podem esperar a què s'hagi actualitzat a la memòria, o al jornal (disc dur) i tenir en compte si s'ha enregistrat a les altres instàncies replicades. | ||
+ | |||
+ | <br> | ||
+ | |||
+ | == Sharding: dades distribuïdes == | ||
+ | * Per accelerar les escriptures podem distribuïr els documents en BBDD independents. | ||
+ | * '''Shard''': instància d'una DDBB distribuïda. | ||
+ | * No totes les aplicacions permeten distribuïr les dades. P.ex. una BBDD d'un servidor d'emails sí ho permet (distribuïnt els usuaris en diversos ''shards''). Una aplicació que necessiti extrema coherència, com un banc, no pot distribuïr les dades de la mateixa manera. | ||
+ | * Cada ''shard'' pot estar replicat internament. | ||
+ | * La '''shard key''' determinarà com repartim els documents als diversos ''shards''. Cal triar-la bé. | ||
+ | * Tots els índexes que creem han de tenir la ''shard key'' com a primer element de l'índex. Això vol dir que no podem fer índexes inter-shard. | ||
+ | |||
+ | Per exemple, en una base de dades d'una gran entitat mèdica, no podem incrustar les proves de cada pacient dins del document del pacient (sobrepassariem els 16MB del límit de documents de MongoDB). Cal tenir una col·lecció de documents de cada pacient (proves, anàlisis, visites, etc.). I caldrà distribuir-la per diversos nodes en base al id de pacient (''shard key''). D'aquesta manera distribuirem les lectures i escriptures de cada metge en diferents nodes. | ||
+ | |||
+ | Cal tenir en compte que ens poden interessar diferents estratègies de ''shard key'' segons quin tipus de consultes vulguem optimitzar. Per exemple, si volguéssim fer estudis (data mining) d'una malaltia ens convindria que la shard key fos la especialitat del metge que porta el cas, o una categoria de classificació del | ||
+ | |||
+ | <br> | ||
+ | |||
+ | == Replicant MongoDB == | ||
+ | Una rèplica és una còpia de totes les dades d'una BBDD. Un conjunt d'instàncies que repliquen en diem '''replica set'''. Ens és útil per accelerar les lectures ja que diversos clients poden treballar alhora llegint de diverses rèpliques simultàniament. | ||
+ | Consideracions: | ||
* Si son rèpliques/instàncies de lectura cap problema. Les d'escriptura tenen la problemàtica de la consistència. | * Si son rèpliques/instàncies de lectura cap problema. Les d'escriptura tenen la problemàtica de la consistència. | ||
* Solució típica: 1 instància primària (escriptura) i 2 (o més) de secundàries (lectura). | * Solució típica: 1 instància primària (escriptura) i 2 (o més) de secundàries (lectura). | ||
Línia 12: | Línia 57: | ||
* Si cau la primària cal unes eleccions per determinar quina farà de primària. | * Si cau la primària cal unes eleccions per determinar quina farà de primària. | ||
− | + | Per crear un '''''replica set''''' caldrà fer: | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
# Arrencar les diferents instàncies de mongod | # Arrencar les diferents instàncies de mongod | ||
# Configurar l'arbitratge (primari, secondaris, etc.) | # Configurar l'arbitratge (primari, secondaris, etc.) | ||
Amb aquest script podem crear diverses instàncies en diversos ports (normalment caldria crearles en diverses màquines): | Amb aquest script podem crear diverses instàncies en diversos ports (normalment caldria crearles en diverses màquines): | ||
+ | |||
+ | El port per defecte de MongoDB és el 27017, hem triat uns altres per no crear conflicte amb la instància del sistema. | ||
+ | |||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
#!/bin/bash | #!/bin/bash | ||
mkdir -p /data/rs1 /data/rs2 /data/rs3 | mkdir -p /data/rs1 /data/rs2 /data/rs3 | ||
− | mongod --replSet m101 --logpath "1.log" --dbpath /data/rs1 --port | + | mongod --replSet m101 --logpath "1.log" --dbpath /data/rs1 --port 27020 --smallfiles --fork |
− | mongod --replSet m101 --logpath "2.log" --dbpath /data/rs2 --port | + | mongod --replSet m101 --logpath "2.log" --dbpath /data/rs2 --port 27021 --smallfiles --fork |
− | mongod --replSet m101 --logpath "3.log" --dbpath /data/rs3 --port | + | mongod --replSet m101 --logpath "3.log" --dbpath /data/rs3 --port 27022 --smallfiles --fork |
</syntaxhighlight> | </syntaxhighlight> | ||
Línia 36: | Línia 76: | ||
De moment estan arrencades i son accessibles a través dels diferents ports amb: | De moment estan arrencades i son accessibles a través dels diferents ports amb: | ||
− | $ mongo --port | + | $ mongo --port 27020 |
I ara caldrà configurar el ''set'' perquè s'arbitri correctament. Ens caldrà aquesta configuració: | I ara caldrà configurar el ''set'' perquè s'arbitri correctament. Ens caldrà aquesta configuració: | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
config = { _id: "m101", members:[ | config = { _id: "m101", members:[ | ||
− | { _id : 0, host : "localhost: | + | { _id : 0, host : "localhost:27020"}, |
− | { _id : 1, host : "localhost: | + | { _id : 1, host : "localhost:27021"}, |
− | { _id : 2, host : "localhost: | + | { _id : 2, host : "localhost:27022"} ] |
}; | }; | ||
rs.initiate(config); | rs.initiate(config); | ||
rs.status(); | rs.status(); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | Ens ha de donar un missatge del tipus: | ||
+ | { | ||
+ | "info" : "Config now saved locally. Should come online in about a minute.", | ||
+ | "ok" : 1 | ||
+ | } | ||
+ | |||
+ | ... i més informació amb el rs.status() on ens dirà qui és el PRIMARY i quins SECONDARY | ||
+ | |||
+ | La instància sobre la que estem treballant se'ns indicarà al prompt: | ||
+ | m101:PRIMARY> | ||
+ | o bé | ||
+ | m101:SECONDARY> | ||
+ | |||
+ | Per poder escriure hem d'anar al primari (connectant-nos a la instància del port adient) i fer, per exemple: | ||
+ | PRIMARY> use test | ||
+ | PRIMARY> db.people.insert({"nom":"enric"}) | ||
+ | |||
+ | Amb el què haurem escrit un document. | ||
+ | |||
+ | Ara anem al secundari i, '''ULL, per poder fer lectures al secondari cal executar l'ordre''': | ||
+ | > rs.slaveOk() | ||
+ | |||
+ | ...i llavors ja podrem llegir les dades que hem entrat a l'altra instància: | ||
+ | SECONDARY> db.people.find() | ||
+ | { "_id" : ObjectId("52cde3219380fd09968b6cff"), "nom" : "enric" } |
Revisió de 12:50, 13 gen 2014
Escalabilitat: capacitat per augmentar el nombre de consultes per segon.
Estratègia típica: tenir diverses rèpliques en diferents instàncies de la BBDD on poder repartir les consultes (particularment les de lectura).
Per entendre aquest article convé llegir MongoDB i potser Pymongo
Contingut
Escalabilitat en BBDD[modifica]
Tenim diverses tècniques per escalar la velocitat de les nostres aplicacions:
- Millorant la velocitat de les consultes/insercions amb indexes.
- Utilitzant els paràmetres d'escriptura convenientment.
- Replicant les instàncies de MongoDB (lectura).
- Sharding: distribuïnt les dades en diversos shards (escriptura).
En les instal·lacions en producció es pot combinar replicació i sharding.
Indexes[modifica]
Un índex:
- Accelera la velocitat de lectura (consultes) si l'utilitzem convenientment.
- Disminueix la velocitat d'escriptura sempre, ja que cada cop que fem un inserció/update cal actualitzar l'índex.
Per tant, convé crear els índexos justos i necessaris per les consultes que volem, ja que amb cadascun que fem ralentitzarà les escriptures.
Paràmetres d'escriptura[modifica]
Quan realitzem una escriptures a la BBDD tenim dos paràmetres:
- w -> wait (esperem a que s'hagi escrit a memòria)
- j -> journal (efectiva persistència en disc)
Aquests paràmetres son importants a la nostra aplicació ja que ens determinen què fem quan escrivim a la BBDD. Podem esperar a què s'hagi actualitzat a la memòria, o al jornal (disc dur) i tenir en compte si s'ha enregistrat a les altres instàncies replicades.
Sharding: dades distribuïdes[modifica]
- Per accelerar les escriptures podem distribuïr els documents en BBDD independents.
- Shard: instància d'una DDBB distribuïda.
- No totes les aplicacions permeten distribuïr les dades. P.ex. una BBDD d'un servidor d'emails sí ho permet (distribuïnt els usuaris en diversos shards). Una aplicació que necessiti extrema coherència, com un banc, no pot distribuïr les dades de la mateixa manera.
- Cada shard pot estar replicat internament.
- La shard key determinarà com repartim els documents als diversos shards. Cal triar-la bé.
- Tots els índexes que creem han de tenir la shard key com a primer element de l'índex. Això vol dir que no podem fer índexes inter-shard.
Per exemple, en una base de dades d'una gran entitat mèdica, no podem incrustar les proves de cada pacient dins del document del pacient (sobrepassariem els 16MB del límit de documents de MongoDB). Cal tenir una col·lecció de documents de cada pacient (proves, anàlisis, visites, etc.). I caldrà distribuir-la per diversos nodes en base al id de pacient (shard key). D'aquesta manera distribuirem les lectures i escriptures de cada metge en diferents nodes.
Cal tenir en compte que ens poden interessar diferents estratègies de shard key segons quin tipus de consultes vulguem optimitzar. Per exemple, si volguéssim fer estudis (data mining) d'una malaltia ens convindria que la shard key fos la especialitat del metge que porta el cas, o una categoria de classificació del
Replicant MongoDB[modifica]
Una rèplica és una còpia de totes les dades d'una BBDD. Un conjunt d'instàncies que repliquen en diem replica set. Ens és útil per accelerar les lectures ja que diversos clients poden treballar alhora llegint de diverses rèpliques simultàniament. Consideracions:
- Si son rèpliques/instàncies de lectura cap problema. Les d'escriptura tenen la problemàtica de la consistència.
- Solució típica: 1 instància primària (escriptura) i 2 (o més) de secundàries (lectura).
- Les secundàries es sincronitzen a la primària regularment.
- La primària sempre serà consistent. Les secundàries poden tenir un retràs en l'actualització de les dades.
- Si cau la primària cal unes eleccions per determinar quina farà de primària.
Per crear un replica set caldrà fer:
- Arrencar les diferents instàncies de mongod
- Configurar l'arbitratge (primari, secondaris, etc.)
Amb aquest script podem crear diverses instàncies en diversos ports (normalment caldria crearles en diverses màquines):
El port per defecte de MongoDB és el 27017, hem triat uns altres per no crear conflicte amb la instància del sistema.
#!/bin/bash
mkdir -p /data/rs1 /data/rs2 /data/rs3
mongod --replSet m101 --logpath "1.log" --dbpath /data/rs1 --port 27020 --smallfiles --fork
mongod --replSet m101 --logpath "2.log" --dbpath /data/rs2 --port 27021 --smallfiles --fork
mongod --replSet m101 --logpath "3.log" --dbpath /data/rs3 --port 27022 --smallfiles --fork
Podem consultar què fa cadascuna de les instàncies mirant els logfiles (.log)
De moment estan arrencades i son accessibles a través dels diferents ports amb:
$ mongo --port 27020
I ara caldrà configurar el set perquè s'arbitri correctament. Ens caldrà aquesta configuració:
config = { _id: "m101", members:[
{ _id : 0, host : "localhost:27020"},
{ _id : 1, host : "localhost:27021"},
{ _id : 2, host : "localhost:27022"} ]
};
rs.initiate(config);
rs.status();
Ens ha de donar un missatge del tipus:
{ "info" : "Config now saved locally. Should come online in about a minute.", "ok" : 1 }
... i més informació amb el rs.status() on ens dirà qui és el PRIMARY i quins SECONDARY
La instància sobre la que estem treballant se'ns indicarà al prompt:
m101:PRIMARY>
o bé
m101:SECONDARY>
Per poder escriure hem d'anar al primari (connectant-nos a la instància del port adient) i fer, per exemple:
PRIMARY> use test PRIMARY> db.people.insert({"nom":"enric"})
Amb el què haurem escrit un document.
Ara anem al secundari i, ULL, per poder fer lectures al secondari cal executar l'ordre:
> rs.slaveOk()
...i llavors ja podrem llegir les dades que hem entrat a l'altra instància:
SECONDARY> db.people.find() { "_id" : ObjectId("52cde3219380fd09968b6cff"), "nom" : "enric" }