MongoDB: escalant

De Cacauet Wiki
Salta a la navegació Salta a la cerca

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

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.


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.


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.


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.


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.
  • 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:

  1. Arrencar les diferents instàncies de mongod
  2. 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" }