MongoDB Sharding: Komplett Guide for Skalerbar Databasen

Sharding er en metode for å oppdele en stor mengde data i mindre delmengder, fordelt over flere MongoDB-instanser i et distribuert system.

Hva innebærer Sharding?

MongoDB-sharding gir en skalerbar løsning for å lagre omfattende data over et nettverk av servere, i stedet for å begrense seg til en enkelt server.

Det er praktisk umulig å lagre eksponentielt voksende data på én enkelt maskin. Forespørsler mot en enorm datamengde lagret på en enkelt server kan føre til høyt ressursforbruk og utilfredsstillende lese- og skrivehastigheter.

I hovedsak finnes det to metoder for skalering for å håndtere økende datamengder i systemet:

Vertikal skalering forbedrer ytelsen til én server ved å oppgradere prosessorer, øke RAM-kapasiteten eller legge til mer diskplass. Imidlertid kan det være begrensninger ved bruk av vertikal skalering i praktiske tilfeller med dagens teknologi og maskinvarekonfigurasjoner.

Horisontal skalering, derimot, involverer å legge til flere servere og fordele arbeidsbelastningen. Siden hver maskin håndterer en delmengde av det totale datasettet, gir dette bedre effektivitet og en mer kostnadseffektiv løsning enn å oppgradere maskinvaren. Det krever likevel mer vedlikehold av en kompleks infrastruktur med mange servere.

MongoDB-sharding benytter seg av horisontal skaleringsmetode.

Komponenter i Sharding

For å implementere sharding i MongoDB, kreves følgende komponenter:

En shard er en MongoDB-instans som håndterer en del av den totale datamengden. Shards må distribueres som et replikasett.

Mongos er en MongoDB-instans som fungerer som et mellomledd mellom klientapplikasjonen og den sharded klyngen. Den fungerer som en spørringsruter for shards.

En Config Server er en MongoDB-instans som lagrer metadata og konfigurasjonsdetaljer for klyngen. MongoDB krever at config server distribueres som et replikasett.

Sharding Arkitektur

En MongoDB-klynge består av flere replikasett.

Hvert replikasett består av minst tre eller flere MongoDB-instanser. En shard-klynge kan bestå av flere mongo shard-instanser, og hver shard-instans opererer innenfor et shard-replikasett. Applikasjonen kommuniserer med Mongos, som igjen samhandler med shards. Dermed samhandler applikasjoner aldri direkte med shard-noder i Sharding. Spørringsruteren fordeler delsett av data mellom shard-noder basert på shard-nøkkelen.

Implementering av Sharding

Følg disse stegene for sharding:

Trinn 1

  • Start konfigurasjonsserveren i replikasettet og aktiver replikering mellom dem.

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

Steg 2

  • Initialiser replikasettet på en av konfigurasjonsserverne.

rs.initiate( { _id : «rs0», configsvr: true, medlemmer: [   { _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)
}

Trinn 3

  • Start deling av servere i replikasettet og aktiver replikering mellom dem.

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 initialiserer den første sharding-serveren som primær. For å flytte den primære sharding-serveren, bruk flyttePrimær-metoden.

Trinn 4

  • Initialiser replikasettet på en av de sønderdelte serverne.

rs.initiate( { _id : «rs0», medlemmer: [   { _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)
}

Trinn 5

  • Start mongoene for den oppdelte klyngen.

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

Trinn 6

  • Koble til mongo-ruteserveren.

mongo –port 40000

  • Legg nå til sharding-servere.

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)
                }
        }
}

Trinn 7

  • I mongo shell, aktiver sharding på databasen og samlingene.
  • Aktiver sharding på databasen.

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)
                }
        }
}

Trinn 8

  • For å shard, kreves en samlingsshard-nøkkel (beskrevet senere i denne artikkelen).

Syntaks: 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)
                }
        }
}

Merk: Hvis samlingen ikke eksisterer, opprett den som følger:

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

Trinn 9

Sett inn data i samlingen. Mongo-logger vil begynne å vokse, noe som indikerer at en balanser er i aktivitet og forsøker å balansere dataene mellom shards.

Trinn 10

Det siste trinnet er å sjekke statusen til sharding. Status kan kontrolleres ved å kjøre kommandoen nedenfor på Mongos-rutenoden.

Sharding Status

Sjekk status for sharding ved å kjøre kommandoen nedenfor på mongo-rutenoden.

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>

Datadistribusjon

Mongos-ruteren fordeler arbeidsmengden mellom shards basert på shard-nøkkelen, og sørger for jevn datadistribusjon; balanseren trer i kraft.

De viktigste komponentene for datadistribusjon mellom shards er:

  • En balanser spiller en rolle i å fordele delmengden av data jevnt mellom de sharded nodene. Balanceren kjøres når Mongos-serveren starter for å distribuere belastningen mellom shards. Etter oppstart fordeler balanceren data jevnere. For å sjekke statusen til balanceren, kjør sh.status(), sh.getBalancerState() eller sh.isBalancerRunning().
mongos> sh.isBalancerRunning()
true
mongos>

ELLER

mongos> sh.getBalancerState()
true
mongos>

Etter å ha satt inn dataene, kan vi merke oss aktivitet i Mongos-demonen, som indikerer at den flytter biter for de spesifikke shardene og så videre. Balanceren vil være aktiv og forsøke å balansere dataene over shardene. Å kjøre balanceren kan føre til ytelsesproblemer; derfor anbefales det å kjøre balanceren innenfor et visst balanservindu.

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-nøkkelen bestemmer logikken for å distribuere dokumenter i en sharded samling mellom shards. En shard-nøkkel kan være et indeksert felt eller et indeksert sammensatt felt som må være til stede i alle dokumenter i samlingen som skal settes inn. Data vil bli delt inn i biter, og hver bit vil være knyttet til en rekkeviddebasert shard-nøkkel. Basert på rekkeviddespørringen vil ruteren bestemme hvilken shard som skal lagre biten.

En shard-nøkkel kan velges ved å vurdere fem egenskaper:

  • Kardinalitet
  • Skrivefordeling
  • Lesefordeling
  • Lesemålretting
  • Leselokalitet

En ideell shard-nøkkel sikrer at MongoDB fordeler belastningen jevnt mellom alle shards. Å velge en god shard-nøkkel er svært viktig.

Bilde: MongoDB

Fjerning av Shard-noder

Før du fjerner shards fra klyngen, må brukeren sørge for sikker overføring av data til de gjenværende shardene. MongoDB sørger for sikker tømming av data til andre shard-noder før den nødvendige shard-noden fjernes.

Kjør kommandoen nedenfor for å fjerne den nødvendige sharden.

Trinn 1

Først må vi bestemme vertsnavnet til sharden som skal fjernes. Kommandoen nedenfor vil liste alle shards som er til stede i klyngen, sammen med deres status.

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)
                }
        }
}

Steg 2

Utfør kommandoen nedenfor for å fjerne den nødvendige sharden fra klyngen. Når kommandoen er gitt, vil balanceren håndtere fjerning av biter fra shard-noden som tømmes, og deretter balansere fordelingen av de resterende shardene mellom de resterende shard-nodene.

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)
                }
        }
}

Trinn 3

For å sjekke statusen til tømmings-sharden, gi den samme kommandoen på nytt.

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

Vi må vente til tømmingen av dataene er fullført. Feltene «melding» og «tilstand» vil vise om tømmingen av dataene er fullført eller ikke, som følger:

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

Vi kan også sjekke statusen med kommandoen sh.status(). Når den er fjernet, vil ikke shard-noden vises i utdataene. Men hvis tømmingen pågår, vil den sharded noden komme med statusen «draining» som «true».

Trinn 4

Fortsett å sjekke statusen for tømming med den samme kommandoen ovenfor, til den nødvendige sharden er fjernet fullstendig.
Når prosessen er fullført, vil utdataene fra kommandoen vise meldingen og tilstanden som «completed».

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

Trinn 5

Til slutt må vi sjekke de gjenværende shardene i klyngen. For å sjekke statusen, skriv inn sh.status() eller 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)
                }
        }
}

Her ser vi at den fjernede sharden ikke lenger er til stede i listen over shards.

Fordeler med Sharding fremfor Replikering

  • I replikering håndterer primærnoden alle skriveoperasjoner, mens sekundære servere vedlikeholder sikkerhetskopier eller betjener leseoperasjoner. Ved sharding, sammen med replikasett, blir belastningen fordelt på flere servere.
  • Et enkelt replikasett er begrenset til 12 noder, men det er ingen begrensning på antall shards.
  • Replikering krever avansert maskinvare eller vertikal skalering for å håndtere store datamengder, noe som er dyrere enn å legge til flere servere i sharding.
  • I replikering kan lese-ytelsen forbedres ved å legge til flere slave-/sekundære servere. I sharding vil både lese- og skrive-ytelsen forbedres ved å legge til flere shard-noder.

Begrensninger ved Sharding

  • En sharded klynge støtter ikke unik indeksering på tvers av shards før den unike indeksen er prefikset med full shard-nøkkel.
  • Alle oppdateringsoperasjoner for en sharded samling, enten det gjelder ett eller flere dokumenter, må inkludere shard-nøkkelen eller _id-feltet i spørringen.
  • Samlinger kan deles hvis størrelsen ikke overstiger en spesifisert terskel. Denne terskelen kan estimeres basert på gjennomsnittsstørrelsen på alle shard-nøkler og den konfigurerte størrelsen på biter.
  • Sharding har driftsmessige begrensninger for maksimal samlingsstørrelse eller antall biter.
  • Feil valg av shard-nøkler kan føre til ytelsesproblemer.

Konklusjon

MongoDB tilbyr innebygd sharding for å implementere en stor database uten å kompromittere ytelsen. Jeg håper ovenstående hjelper deg med å sette opp MongoDB-sharding. Deretter kan du gjerne bli kjent med noen av de vanligste MongoDB-kommandoene.