Replikering i MongoDB involverer replikasæt af medlemmer med en arkitektur af primære og sekundære medlemmer, men til tider med et ikke-databærende medlem kaldet en arbiter. Replikeringsprocessen er, at når dataene er blevet skrevet til den primære node, registreres ændringerne på en oplog-fil, hvorfra de sekundære medlemmer anvender de samme ændringer. Læseoperationer kan udføres fra et hvilket som helst databærende medlem, hvilket skaber et scenario, almindeligvis kendt som High Availability.
I nogle tilfælde kan de sekundære medlemmer dog ikke indhente det primære ved at lave ændringer, og hvis den primære node fejler, før disse ændringer er blevet anvendt, vil man være tvunget til at synkronisere hele klyngen igen så de kan være i samme datatilstand.
Hvad er en tilbagerulning?
Dette er en automatisk failover-funktion i MongoDB, hvor den primære node i et replikasæt kan svigte, mens der foretages ændringer, som desværre ender med ikke at blive afspejlet til de sekundære medlemmer i tide fra oploggen, og derfor er det nødvendigt at vende tilbage tilstand af den primære til en, før ændringerne blev foretaget.
Rollbacks er derfor kun nødvendige, når den primære har accepteret at skrive de operationer, som ikke er blevet replikeret til de sekundære medlemmer før de primære trin ned på grund af en eller anden grund, såsom netværkspartition. Hvis i tilfælde af, at skriveoperationerne formår at blive replikeret i et af medlemmerne, som er tilgængeligt og tilgængeligt for et flertal af replikasættet, vil en tilbagerulning ikke ske.
Hovedårsagen bag tilbagerulninger i MongoDB er at holde datakonsistens for alle medlemmer, og derfor, når den primære genindtræder i replikasættet, hvis dens ændringer ikke er blevet anvendt på de sekundære medlemmer, vil den blive ført tilbage til staten før fiaskoen.
Tilbageføringer bør dog være sjældne eller snarere undgås i MongoDB, da de kan resultere i meget datatab og som følge heraf påvirke driften af tilsluttede applikationer til databasen.
MongoDB tilbagerulningsproces
Lad os overveje et replikasæt med tre medlemmer med A som det primære, B og C som de sekundære medlemmer. Vi vil udfylde data til A og samtidig udløse en vis netværkspartitionering til B og C. Vi vil bruge MongoDB version 4.2 og Atlas i denne test.
Først får vi status for replikasættet ved at køre kommandoen rs.status() på mongo-skallen
MongoDB Enterprise Cluster0-shard-0:PRIMARY> rs.status()
Når du ser på medlemsattributten, kan du se noget lignende
"members" : [
{
"_id" : 0,
"name" : "cluster0-shard-00-00-sc27x.mongodb.net:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1891079,
"optime" : {
"ts" : Timestamp(1594826711, 1),
"t" : NumberLong(27)
},
"optimeDurable" : {
"ts" : Timestamp(1594826711, 1),
"t" : NumberLong(27)
},
"optimeDate" : ISODate("2020-07-15T15:25:11Z"),
"optimeDurableDate" : ISODate("2020-07-15T15:25:11Z"),
"lastHeartbeat" : ISODate("2020-07-15T15:25:19.509Z"),
"lastHeartbeatRecv" : ISODate("2020-07-15T15:25:18.532Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "cluster0-shard-00-02-sc27x.mongodb.net:27017",
"syncSourceHost" : "cluster0-shard-00-02-sc27x.mongodb.net:27017",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 4
},
{
"_id" : 1,
"name" : "cluster0-shard-00-01-sc27x.mongodb.net:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1891055,
"optime" : {
"ts" : Timestamp(1594826711, 1),
"t" : NumberLong(27)
},
"optimeDurable" : {
"ts" : Timestamp(1594826711, 1),
"t" : NumberLong(27)
},
"optimeDate" : ISODate("2020-07-15T15:25:11Z"),
"optimeDurableDate" : ISODate("2020-07-15T15:25:11Z"),
"lastHeartbeat" : ISODate("2020-07-15T15:25:17.914Z"),
"lastHeartbeatRecv" : ISODate("2020-07-15T15:25:19.403Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "cluster0-shard-00-02-sc27x.mongodb.net:27017",
"syncSourceHost" : "cluster0-shard-00-02-sc27x.mongodb.net:27017",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 4
},
{
"_id" : 2,
"name" : "cluster0-shard-00-02-sc27x.mongodb.net:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1891089,
"optime" : {
"ts" : Timestamp(1594826711, 1),
"t" : NumberLong(27)
},
"optimeDate" : ISODate("2020-07-15T15:25:11Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1592935644, 1),
"electionDate" : ISODate("2020-06-23T18:07:24Z"),
"configVersion" : 4,
"self" : true,
"lastHeartbeatMessage" : ""
}
],
Dette vil vise dig status for hvert medlem af dit replikasæt. Nu åbnede vi en ny terminal for node A og udfyldte den med 20000 poster:
MongoDB Enterprise Cluster0-shard-0:PRIMARY> for (var y = 20000; y >= 0; y--) {
db.mytest.insert( { record : y } )
}
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.mytest 2020-07-15T21:28:40.436+2128 I NETWORK [thread1] trying reconnect to 127.0.0.1:3001 (127.0.0.1) failed
2020-07-15T21:28:41.436+2128 I
NETWORK [thread1] reconnect 127.0.0.1:3001 (127.0.0.1) ok
MongoDB Enterprise Cluster0-shard-0:SECONDARY> rs.slaveOk()
MongoDB Enterprise Cluster0-shard-0:SECONDARY> db.mytest.count()
20000
Under netværksopdelingen vil A være nede, hvilket gør den utilgængelig for B og C og dermed B valgt som den primære i vores tilfælde. Når A slutter sig til igen, vil den blive tilføjet som den sekundære, og du kan kontrollere det ved at bruge kommandoen rs.status(). Det lykkedes dog nogle poster at blive replikeret til medlem B før netværksopdelingen som vist nedenfor:(Husk i dette tilfælde er B den primære nu)
MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.mytest.find({}).count()
12480
Antallet er antallet af dokumenter, der var i stand til at blive replikeret til B, før A gik ned.
Hvis vi skriver nogle data til B og tillader A at tilslutte sig netværket, så kan vi bemærke nogle ændringer til A
connecting to: 127.0.0.1:3001/admin
MongoDB Enterprise Cluster0-shard-0:ROLLBACK>
MongoDB Enterprise Cluster0-shard-0:RECOVERING>
MongoDB Enterprise Cluster0-shard-0:SECONDARY>
MongoDB Enterprise Cluster0-shard-0:SECONDARY>
MongoDB Enterprise Cluster0-shard-0:PRIMARY>
Ved brug af en oplogFetcher synkroniserer sekundære medlemmer oplog-poster fra deres syncSource. oplogFetcher udløser en find-metode til kildeoploggen efterfulgt af en række getMores-markørserier. Når A genføjes som den sekundære, anvendes den samme tilgang, og et dokument, der er større end prædikattidsstemplet, returneres. Hvis det første dokument i B ikke matcher A's sidste oplog-indgang, vil A blive tvunget til en rollback.
Gendannelse af tilbagerulningsdata i MongoDB
Tilbageføring er ikke en dårlig ting i MongDB, men man bør prøve så meget som muligt for at sikre, at de ikke sker ret ofte. Det er en automatisk sikkerhedsforanstaltning til at sikre datakonsistens mellem medlemmer af et replikasæt. Hvis tilbagerulning sker, er her nogle trin til at løse situationen:
Rullback Data Collection
Du skal indsamle medlemsdata vedrørende rollback. Dette gøres ved at sikre, at rollback-filer oprettes (kun tilgængelig med MongoDB version 4.0) ved at aktivere createRollbackDataFiles. Som standard er denne indstilling sat til sand, så der vil altid blive oprettet rollback-filer.
Rulningsfilerne placeres i stien
Indlæsning af tilbagerulningsfilers data i en separat database eller server
Mongorestore er et vigtigt aspekt af MongoDB, der kan hjælpe med at aktivere gendannelse af tilbagerulningsdatafiler. Den første ting er at kopiere rollback-filer til en ny server og derefter indlæse filerne på din server ved hjælp af mongorestore. Mongorestore-kommandoen er vist nedenfor.
mongorestore -u <> -p <> -h 127.0.0.1 -d <rollbackrestoretestdb> -c <rollbackrestoretestc> <path to the .bson file> --authenticationDatabase=<database of user>
Rengøring af data, der ikke er nødvendige, og gennemsivning af data
Dette trin kræver, at man bruger skøn til at vælge mellem de data, der skal opbevares fra rollback-filer, og de data, der skal smides væk. Det er tilrådeligt at importere alle rollback-filernes data, dette beslutningspunkt gør dette trin til det sværeste trin i datagendannelse.
Brug af det primære som en klynge til at importere data
Start det sidste trin ved at downloade rensede data ved at bruge mongorestore og mongodump, følg dette ved at genimportere dataene til den originale produktionsklynge.
Forebyggelse af MongoDB-tilbageføringer
For at forhindre tilbagerulning af data, når du bruger MongoDB, kan man gøre følgende.
Køre alle stemmeberettigede medlemmer 'MAJORITY'
Dette kan gøres ved at bruge w:majoritetsskrivebekymring, som har magten til at vælge en anmodningsbekræftelse, der vil muliggøre skriveoperation til givne specifikke tags af Mongod-forekomster. Dette kan opnås ved at bruge w-indstillingen efterfulgt af
Brugerhandlinger
Opdateret version af MongoDB, dvs. version 4.2, har mulighed for at lukke ned for alle igangværende operationer i tilfælde af en tilbagerulning.
Indeksbuilds
Version 4.2 af MongoDB funktionskompatibilitetsversion (fcv) "4.2" er i stand til at vente på alle de igangværende indekser, der er ved at blive bygget og afsluttet, før en tilbagerulning tager placere. Version 4.0 venter dog på den fortsatte igangværende og opbygger baggrundsindeks, så muligheden for en tilbagerulning er høj.
Størrelse og begrænsninger
Version 4.0 af MongoDB har ingen listede grænser for givne data, der kan rulles tilbage, når igangværende baggrundsindeks opbygges.
Konklusion
MongoDB rollback er et almindeligt fænomen for dem, der bruger MongoDB uden at vide, hvordan man forhindrer det. Tilbageføringer kan forhindres, hvis man nøje følger og overholder nogle af sikre praksisser og måder at undgå tilbagerulninger i MongoDB. I det hele taget er det altid tilrådeligt at opgradere til den nyeste version af MongoDB for at undgå nogle hikke, der kan forhindres.