MongoDB Sharding: Ghid practic pas cu pas

Sharding-ul este un proces de împărțire a marii seturi de date într-o bucată de seturi de date mai mici în mai multe instanțe MongoDB într-un mediu distribuit.

Ce este Sharding?

MongoDB sharding ne oferă o soluție scalabilă pentru a stoca o cantitate mare de date între numărul de servere, mai degrabă decât stocarea pe un singur server.

În termeni practici, nu este fezabil să stocați date în creștere exponențială pe o singură mașină. Interogarea unei cantități uriașe de date stocate pe un singur server poate duce la o utilizare ridicată a resurselor și poate să nu ofere un debit satisfăcător de citire și scriere.

Practic, există două tipuri de metode de scalare care există pentru a realiza creșterea datelor cu sistemul:

Scalare verticală funcționează cu îmbunătățirea performanței unui singur server prin adăugarea de procesoare mai puternice, modernizarea memoriei RAM sau adăugarea de mai mult spațiu pe disc la sistem. Există însă posibilele implicații ale aplicării scalării verticale în cazuri practice de utilizare cu tehnologia și configurațiile hardware existente.

Horizontal Scaling funcționează cu adăugarea mai multor servere și distribuirea sarcinii pe mai multe servere. Deoarece fiecare mașină se va ocupa de subsetul întregului set de date, oferă o eficiență mai bună și o soluție rentabilă, mai degrabă decât să implementeze hardware-ul de ultimă generație. Dar necesită întreținere suplimentară a infrastructurii complexe cu un număr mare de servere.

Mongo DB sharding funcționează pe tehnica de scalare orizontală.

Componente de fragmentare

Pentru a realiza sharding în MongoDB, sunt necesare următoarele componente:

Shard este o instanță Mongo pentru a gestiona un subset de date originale. Este necesar ca fragmentele să fie implementate în setul de replici.

Mongos este o instanță Mongo și acționează ca o interfață între o aplicație client și un cluster fragmentat. Funcționează ca un router de interogare către fragmente.

Config Server este o instanță Mongo care stochează informații despre metadate și detalii de configurare ale clusterului. MongoDB necesită ca serverul de configurare să fie implementat ca un set de replică.

Sharding Architecture

Clusterul MongoDB este format dintr-un număr de seturi de replici.

Fiecare set de replică constă din minimum 3 sau mai multe instanțe mongo. Un cluster fragmentat poate consta din mai multe instanțe de fragmente mongo, iar fiecare instanță de fragmente funcționează într-un set de replică de fragmente. Aplicația interacționează cu Mongos, care la rândul său comunică cu cioburi. Prin urmare, în Sharding, aplicațiile nu interacționează niciodată direct cu nodurile shard. Routerul de interogare distribuie subseturile de date între nodurile shard-urilor pe baza cheii shard-ului.

Implementarea fragmentării

Urmați pașii de mai jos pentru fragmentare

Pasul 1

  • Porniți serverul de configurare în setul de replici și activați replicarea între ele.

mongod –configsvr –port 27019 –replSet rs0 –dbpath C:datadata1 –bind_ip localhost

mongod –configsvr –port 27018 –replSet rs0 –dbpath C:datadata2 –bind_ip localhost

mongod –configsvr –port 27017 –replSet rs0 –dbpath C:datadata3 –bind_ip localhost

Pasul 2

  • Inițializați setul de replică pe unul dintre serverele de configurare.

rs.initiate( { _id: „rs0”, configsvr: true, membrii: [   { _id: 0, host: “IP:27017” },   { _id: 1, host: “IP:27018” },   { _id: 2, host: “IP:27019” }    ] })

rs.initiate( { _id : "rs0",  configsvr: true,  members: [   { _id: 0, host: "IP:27017" },   { _id: 1, host: "IP:27018" },   { _id: 2, host: "IP:27019" }    ] })
{
        "ok" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(1593569257, 1),
                "electionId" : ObjectId("000000000000000000000000")
        },
        "lastCommittedOpTime" : Timestamp(0, 0),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593569257, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1593569257, 1)
}

Pasul 3

  • Începeți să împărțiți serverele din setul de replici și activați replicarea între ele.
  Ce este No Code AI și de ce este important pentru companii?

mongod –shardsvr –port 27020 –replSet rs1 –dbpath C:datadata4 –bind_ip localhost

mongod –shardsvr –port 27021 –replSet rs1 –dbpath C:datadata5 –bind_ip localhost

mongod –shardsvr –port 27022 –replSet rs1 –dbpath C:datadata6 –bind_ip localhost

MongoDB inițializează primul server de sharding ca Primar, pentru a muta utilizarea serverului de sharding primar mutarePrimar metodă.

Pasul 4

  • Inițializați setul de replică pe unul dintre serverele fragmentate.

rs.initiate( { _id: „rs0”, membri: [   { _id: 0, host: “IP:27020” },   { _id: 1, host: “IP:27021” },   { _id: 2, host: “IP:27022” }    ] })

rs.initiate( { _id : "rs0",  members: [   { _id: 0, host: "IP:27020" },   { _id: 1, host: "IP:27021" },   { _id: 2, host: "IP:27022" }    ] })
{
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593569748, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1593569748, 1)
}

Pasul 5

  • Începeți mango pentru clusterul fragmentat

mongos –port 40000 –configdb rs0/localhost:27019,localhost:27018, localhost:27017

Pasul 6

  • Conectați serverul de ruta mongo

mongo –port 40000

  • Acum, adăugați servere de sharding.

sh.addShard( „rs1/localhost:27020,localhost:27021,localhost:27022”)

sh.addShard( "rs1/localhost:27020,localhost:27021,localhost:27022")
{
        "shardAdded" : "rs1",
        "ok" : 1,
        "operationTime" : Timestamp(1593570212, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570212, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Pasul 7

  • Pe mongo shell, activați sharding-ul pe DB și colecții.
  • Activați sharding pe DB

sh.enableSharding(„geekFlareDB”)

sh.enableSharding("geekFlareDB")
{
        "ok" : 1,
        "operationTime" : Timestamp(1591630612, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1591630612, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Pasul 8

  • Pentru a fragmenta cheia fragmentului de colecție (descrisă mai târziu în acest articol) este necesară.

Sintaxă: sh.shardCollection(„dbName.collectionName”, { „key” : 1 } )

sh.shardCollection("geekFlareDB.geekFlareCollection", { "key" : 1 } )
{
        "collectionsharded" : "geekFlareDB.geekFlareCollection",
        "collectionUUID" : UUID("0d024925-e46c-472a-bf1a-13a8967e97c1"),
        "ok" : 1,
        "operationTime" : Timestamp(1593570389, 3),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570389, 3),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Rețineți dacă colecția nu există, creați după cum urmează.

db.createCollection("geekFlareCollection")
{
        "ok" : 1,
        "operationTime" : Timestamp(1593570344, 4),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570344, 5),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Pasul 9

Introduceți date în colecție. Jurnalele Mongo vor începe să crească și indică faptul că un echilibrator este în acțiune și încearcă să echilibreze datele între fragmente.

Pasul 10

Ultimul pas este verificarea stării sharding-ului. Starea poate fi verificată rulând comanda de mai jos pe nodul de rută Mongos.

Starea de fragmentare

Verificați starea sharding rulând sub comanda pe nodul rutei mongo.

sh.status()

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5ede66c22c3262378c706d21")
  }
  shards:
        {  "_id" : "rs1",  "host" : "rs1/localhost:27020,localhost:27021,localhost:27022",  "state" : 1 }
  active mongoses:
        "4.2.7" : 1
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  5
        Last reported error:  Could not find host matching read preference { mode: "primary" } for set rs1
        Time of Reported error:  Tue Jun 09 2020 15:25:03 GMT+0530 (India Standard Time)
        Migration Results for the last 24 hours:
                No recent migrations
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1024
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "geekFlareDB",  "primary" : "rs1",  "partitioned" : true,  "version" : {  "uuid" : UUID("a770da01-1900-401e-9f34-35ce595a5d54"),  "lastMod" : 1 } }
                geekFlareDB.geekFlareCol
                        shard key: { "key" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1
                        { "key" : { "$minKey" : 1 } } -->> { "key" : { "$maxKey" : 1 } } on : rs1 Timestamp(1, 0)
                geekFlareDB.geekFlareCollection
                        shard key: { "product" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1
                        { "product" : { "$minKey" : 1 } } -->> { "product" : { "$maxKey" : 1 } } on : rs1 Timestamp(1, 0)
        {  "_id" : "test",  "primary" : "rs1",  "partitioned" : false,  "version" : {  "uuid" : UUID("fbc00f03-b5b5-4d13-9d09-259d7fdb7289"),  "lastMod" : 1 } }

mongos>

Distribuția datelor

Routerul Mongos distribuie sarcina între fragmente pe baza cheii fragmentului și pentru a distribui în mod uniform datele; echilibrantul intră în acțiune.

  Ce înseamnă „AMA” și cum îl folosești?

Componenta cheie pentru distribuirea datelor între fragmente sunt

  • Un echilibrator joacă un rol în echilibrarea subsetului de date între nodurile fragmentate. Balancer rulează când serverul Mongos începe să distribuie încărcăturile între fragmente. Odată pornit, Balancer a distribuit datele mai uniform. Pentru a verifica starea echilibrului, rulați sh.status() sau sh.getBalancerState() saush.isBalancerRunning().
mongos> sh.isBalancerRunning()
true
mongos>

SAU

mongos> sh.getBalancerState()
true
mongos>

După inserarea datelor, am putut observa o activitate în demonul Mongos care afirmă că mută unele bucăți pentru fragmentele specifice și așa mai departe, adică echilibratorul va fi în acțiune încercând să echilibreze datele între fragmente. Rularea echilibrului ar putea duce la probleme de performanță; prin urmare, se sugerează să rulați echilibrul într-un anumit interval fereastra de echilibrare.

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5efbeff98a8bbb2d27231674")
  }
  shards:
        {  "_id" : "rs1",  "host" : "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022",  "state" : 1 }
        {  "_id" : "rs2",  "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",  "state" : 1 }
  active mongoses:
        "4.2.7" : 1
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  yes
        Failed balancer rounds in last 5 attempts:  5
        Last reported error:  Could not find host matching read preference { mode: "primary" } for set rs2
        Time of Reported error:  Wed Jul 01 2020 14:39:59 GMT+0530 (India Standard Time)
        Migration Results for the last 24 hours:
                1024 : Success
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs2     1024
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "geekFlareDB",  "primary" : "rs2",  "partitioned" : true,  "version" : {  "uuid" : UUID("a8b8dc5c-85b0-4481-bda1-00e53f6f35cd"),  "lastMod" : 1 } }
                geekFlareDB.geekFlareCollection
                        shard key: { "key" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs2     1
                        { "key" : { "$minKey" : 1 } } -->> { "key" : { "$maxKey" : 1 } } on : rs2 Timestamp(1, 0)
        {  "_id" : "test",  "primary" : "rs2",  "partitioned" : false,  "version" : {  "uuid" : UUID("a28d7504-1596-460e-9e09-0bdc6450028f"),  "lastMod" : 1 } }

mongos>
  • Shard Key determină logica de distribuire a documentelor de colecție fragmentată între fragmente. Cheia Shard poate fi un câmp indexat sau un câmp compus indexat care trebuie să fie prezent în toate documentele colecției care urmează să fie introduse. Datele vor fi împărțite în bucăți și fiecare bucată va fi asociată cu cheia shard bazată pe interval. Pe baza interogării intervalului, routerul va decide ce fragment va stoca fragmentul.

Shard Key poate fi selectată luând în considerare cinci proprietăți:

  • Cardinalitatea
  • Distribuție de scriere
  • Citiți distribuția
  • Citiți direcționarea
  • Citiți localitatea

O cheie shard ideală face ca MongoDB să distribuie uniform sarcina între toate shard-urile. Alegerea unei chei shard bune este extrem de importantă.

Imagine: MongoDB

Eliminarea nodului shard

Înainte de a elimina fragmentele din cluster, utilizatorul trebuie să asigure migrarea în siguranță a datelor către fragmentele rămase. MongoDB se ocupă de drenarea în siguranță a datelor către alte noduri shard-uri înainte de eliminarea nodului shard-ului necesar.

Rulați comanda de mai jos pentru a elimina fragmentul necesar.

Pasul 1

În primul rând, trebuie să determinăm numele de gazdă al fragmentului care urmează să fie eliminat. Comanda de mai jos va lista toate fragmentele prezente în cluster împreună cu starea fragmentului.

db.adminCommand( { listShards: 1 } )

mongos> db.adminCommand( { listShards: 1 } )
{
        "shards" : [
                {
                        "_id" : "rs1",
                        "host" : "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022",
                        "state" : 1
                },
                {
                        "_id" : "rs2",
                        "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",
                        "state" : 1
                }
        ],
        "ok" : 1,
        "operationTime" : Timestamp(1593572866, 15),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593572866, 15),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Pasul 2

Lansați comanda de mai jos pentru a elimina fragmentul necesar din cluster. Odată emis, echilibrerul se ocupă de eliminarea bucăților din nodul shard care se scurge și apoi echilibrează distribuția bucăților rămase între nodurile shard-urilor rămase.

db.adminCommand( { removeShard: „shardedReplicaNodes” } )

mongos> db.adminCommand( { removeShard: "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022" } )
{
        "msg" : "draining started successfully",
        "state" : "started",
        "shard" : "rs1",
        "note" : "you need to drop or movePrimary these databases",
        "dbsToMove" : [ ],
        "ok" : 1,
        "operationTime" : Timestamp(1593572385, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593572385, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Pasul 3

Pentru a verifica starea ciobului de scurgere, lansați din nou aceeași comandă.

db.adminCommand( { removeShard: „rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022” } )

Trebuie să așteptăm până când scurgerea datelor este finalizată. Câmpurile msg și state vor arăta dacă scurgerea datelor a fost finalizată sau nu, după cum urmează

"msg" : "draining ongoing",
"state" : "ongoing",

Putem verifica starea și cu comanda sh.status(). Odată eliminat, nodul fragmentat nu va fi reflectat în rezultat. Dar dacă drenarea va fi în curs de desfășurare, nodul fragmentat va avea statutul de drenaj adevărat.

Pasul 4

Continuați să verificați starea drenării cu aceeași comandă de mai sus, până când ciobul necesar este îndepărtat complet.
Odată finalizată, rezultatul comenzii va reflecta mesajul și starea ca finalizată.

"msg" : "removeshard completed successfully",
"state" : "completed",
"shard" : "rs1",
"ok" : 1,

Pasul 5

În cele din urmă, trebuie să verificăm fragmentele rămase în cluster. Pentru a verifica starea, introduceți sh.status() sau db.adminCommand( { listShards: 1 } )

mongos> db.adminCommand( { listShards: 1 } )
{
        "shards" : [
                {
                        "_id" : "rs2",
                        "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",
                        "state" : 1
                }
        ],
        "ok" : 1,
        "operationTime" : Timestamp(1593575215, 3),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593575215, 3),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Aici, putem vedea că fragmentul eliminat nu mai este prezent în lista de fragmente.

Beneficiile fragmentării față de replicare

  • În replicare, nodul primar se ocupă de toate operațiunile de scriere, în timp ce serverele secundare trebuie să mențină copii de rezervă sau să servească operațiuni numai pentru citire. Dar în sharding împreună cu seturile de replici, încărcarea este distribuită între un număr de servere.
  • Un singur set de replică este limitat la 12 noduri, dar nu există nicio restricție privind numărul de fragmente.
  • Replicarea necesită hardware de vârf sau scalare verticală pentru a gestiona seturi mari de date, ceea ce este prea costisitor în comparație cu adăugarea de servere suplimentare în sharding.
  • În replicare, performanța de citire poate fi îmbunătățită prin adăugarea mai multor servere slave/secundar, în timp ce, în sharding, atât performanța de citire, cât și cea de scriere vor fi îmbunătățite prin adăugarea mai multor noduri shards.

Limitarea fragmentării

  • Clusterul Sharded nu acceptă indexarea unică între shard-uri până când indexul unic este prefixat cu cheia shard completă.
  • Toate operațiunile de actualizare pentru colectarea sharded fie pe unul sau mai multe documente trebuie să conțină cheia sharded sau câmpul _id din interogare.
  • Colecțiile pot fi fragmentate dacă dimensiunea lor nu depășește pragul specificat. Acest prag poate fi estimat pe baza dimensiunii medii a tuturor cheilor shard și a dimensiunii configurate a bucăților.
  • Partajarea cuprinde limite operaționale privind dimensiunea maximă a colecției sau numărul de împărțiri.
  • Alegerea cheilor shard greșite pentru a duce la implicații de performanță.

Concluzie

MongoDB oferă sharding încorporat pentru a implementa o bază de date mare fără a compromite performanța. Sper că cele de mai sus vă ajută să configurați fragmentarea MongoDB. În continuare, poate doriți să vă familiarizați cu unele dintre comenzile MongoDB utilizate în mod obișnuit.