I min tidigare blogg, How to use MongoDB Data Modeling to Improve Throughput Operations, diskuterade vi de två stora tillvägagångssätten för datamodellering, det vill säga inbäddning och referens. Skalbarheten av MongoDB är ganska beroende av dess arkitektur och för att vara specifik, datamodellering. När du designar en NoSQL DBM är huvudpunkten att överväga att säkerställa schemalösa dokument förutom ett litet antal samlingar i syfte att enkelt underhålla. God dataintegritet, antagande av datavalidering genom vissa definierade regler före lagring uppmuntras. En databasarkitektur och design bör normaliseras och delas upp i flera små samlingar som ett sätt att undvika dataupprepning, förbättra dataintegriteten och göra det enkelt med hämtningsmönster. Med detta på plats kan du förbättra datakonsistensen, atomiciteten, hållbarheten och integriteten för din databas.
Datamodellering är inte ett eftertanke i en applikationsutvecklingsfas utan ett första övervägande eftersom många applikationsaspekter faktiskt realiseras under datamodelleringsstadiet. I den här artikeln kommer vi att diskutera vilka faktorer som måste beaktas vid datamodellering och se hur de påverkar prestandan hos en databas i allmänhet.
Många gånger kommer du att behöva distribuera ett kluster av din databas som ett sätt att öka datatillgängligheten. Med en väldesignad datamodell kan du distribuera aktiviteter till ett fragmenterat kluster mer effektivt och därmed minska genomströmningsoperationerna riktade mot en enda mongod-instans. De viktigaste faktorerna att ta hänsyn till vid datamodellering inkluderar:
- Skalbarhet
- Atomicitet
- Prestanda och dataanvändning
- Skärning
- Indexering
- Lagringsoptimering
- Dokumentstruktur och tillväxt
- Datalivscykel
1. Skalbarhet
Detta är en ökning av arbetsbelastningen för en applikation som drivs av ökad trafik. Många applikationer har alltid en förväntning på att antalet användare ökar. När det finns så många användare som betjänas av en enda databasinstans, motsvarar inte prestandan alltid förväntningarna. Som databashanterare har du alltså mandat att designa denna DBM så att samlingar och dataenheter modelleras utifrån applikationens nuvarande och framtida krav. Databasstrukturen bör i allmänhet vara presentabel för att underlätta processen för replikering och skärning. När du har fler skärvor fördelas skrivoperationerna mellan dessa skärvor så att för alla datauppdateringar görs det inom skärvan som innehåller dessa data snarare än att slå upp i en enda stor uppsättning data för att göra en uppdatering.
2. Atomicitet
Detta syftar på att en operation lyckas eller misslyckas som en enhet. Till exempel kan du ha en läsoperation som involverar en sorteringsoperation efter att ha hämtat resultatet. Om sorteringsoperationen inte hanteras korrekt kommer hela operationen därför inte att gå vidare till nästa steg.
Atomtransaktioner är serier av operationer som varken är delbara eller reducerbara och därför uppträder som enstaka enheter eller misslyckas som en enda operation. MongoDB-versioner före 4.0 stöder skrivoperationer som atomära processer på en enda dokumentnivå. Med version 4.0 kan man nu implementera multidokumenttransaktioner. En datamodell som förbättrar atomoperationer tenderar att ha en bra prestanda när det gäller latens. Latency är helt enkelt den varaktighet inom vilken en operationsbegäran skickas och när ett svar returneras från databasen. För att vara seccant är det lätt att uppdatera data som är inbäddade i ett enda dokument snarare än ett som det refereras till.
Låt oss till exempel överväga datamängden nedan
{
childId : "535523",
studentName : "James Karanja",
parentPhone : 704251068,
age : 12,
settings : {
location : "Embassy",
address : "420 01",
bus : "KAZ 450G",
distance : "4"
}
}
Om vi vill uppdatera åldern genom att öka den med 1 och ändra platsen till London kan vi göra:
db.getCollection(‘students’).update({childId: 535523},{$set:{'settings.location':'London'}, $inc:{age:1}}).
Om till exempel $set-operationen misslyckas, kommer $inc-operationen automatiskt inte att implementeras och i allmänhet misslyckas hela operationen.
Å andra sidan, låt oss överväga refererade data så att det finns två samlingar, en för studenter och den andra för inställningar.
Studentsamling
{
childId : "535523",
studentName : "James Karanja",
parentPhone : 704251068,
age : 12
}
Inställningssamling
{
childId : "535523",
location : "Embassy",
address : "420 01",
bus : "KAZ 450G",
distance : "4"
}
I det här fallet kan du uppdatera ålders- och platsvärdena med separata skrivoperationer .i.e
db.getCollection(‘students’).update({childId: 535523},{$inc:{age:1}})
db.getCollection('settings’).update({childId: 535523 } , {$set: { 'settings.location':'London'}})
Om en av operationerna misslyckas, påverkar det inte nödvändigtvis den andra eftersom de utförs som olika enheter.
Transaktioner för flera dokument
Med MongoDB version 4.0 kan du nu utföra flera dokumenttransaktioner för replikuppsättningar. Detta förbättrar prestandan eftersom operationerna skickas till ett antal samlingar, databaser och dokument för snabb hantering. När en transaktion har genomförts sparas data medan om något går fel och en transaktion misslyckas, kasseras de ändringar som gjorts och transaktionen avbryts i allmänhet. Det kommer ingen uppdatering av replikuppsättningarna under transaktionen eftersom operationen endast är synlig utanför när transaktionen är helt genomförd.
Så mycket som du kan uppdatera flera dokument i flera transaktioner, kommer det med ett bakslag av minskad prestanda jämfört med att skriva enstaka dokument. Dessutom stöds detta tillvägagångssätt endast för WiredTiger-lagringsmotorn och är därför en nackdel för lagringsmotorerna In-Memory och MMAPv1.
3. Prestanda och dataanvändning
Applikationer är utformade på olika sätt för att möta olika syften. Det finns några som endast tjänar för aktuella data som vädernyhetsapplikationer. Beroende på strukturen av en applikation, bör man kunna designa en korrespondent optimal databas för att servera det nödvändiga användningsfallet. Till exempel, om man utvecklar en applikation som hämtar de senaste uppgifterna från databasen, kommer användning av en begränsad samling vara det bästa alternativet. En begränsad samling förbättrar driften med hög genomströmning precis som en buffert så att när det tilldelade utrymmet utnyttjas skrivs de äldsta dokumenten över och dokumenten kan hämtas i den ordning de infogades. Med tanke på hämtning av infogningsorder kommer det inte att finnas något behov av att använda indexering och frånvaron av indexoverhead kommer likaså att förbättra skrivgenomströmningen. Med en begränsad samling är associerade data ganska små genom att de kan bibehållas i RAM-minnet under en tid. Tidsdata i detta fall lagras i cachen som är ganska läst än att skrivas in i vilket gör läsoperationen ganska snabb. Den begränsade samlingen har dock vissa nackdelar som att du inte kan ta bort ett dokument om du inte släpper hela samlingen, varje förändring av storleken på ett dokument kommer att misslyckas med operationen och slutligen är det inte möjligt att skära en begränsad samling.
Olika aspekter är integrerade i datamodelleringen av en databas beroende på användningsbehov. Som sett kommer rapportapplikationer att tendera att vara mer läsintensiva och därför bör designen vara på ett sätt som förbättrar läskapaciteten.
4. Sharding
Prestanda genom horisontell skalning kan förbättras genom skärning eftersom läs- och skrivbelastningen är fördelad mellan klustermedlemmarna. Att distribuera ett kluster av shards tenderar att partitionera databasen i flera små samlingar med distribuerade dokument beroende på någon shard-nyckel. Du bör välja en lämplig shard-nyckel som kan förhindra frågeisolering förutom att öka skrivkapaciteten. Ett bättre urval innebär i allmänhet ett fält som finns i alla dokument inom den riktade samlingen. Med sharding blir det ökad lagring eftersom allt eftersom data växer etableras fler shards för att hålla en delmängd av detta kluster.
5. Indexering
Indexering är en av de bästa metoderna för att förbättra skrivbelastningen, särskilt där fälten förekommer i alla dokument. När man gör indexering bör man tänka på att varje index kommer att kräva 8KB datautrymme. När indexet är aktivt kommer det dessutom att förbruka lite diskutrymme och minne bör därför spåras för kapacitetsplanering.
Severalnines Become a MongoDB DBA - Bringing MongoDB to ProductionLäs om vad du behöver veta för att distribuera, övervaka, hantera och skala MongoDBDownload gratis6. Lagringsoptimering
Många små dokument inom en samling tenderar att ta mer plats än när du har några dokument med inbäddade dokument. Vid modellering bör man därför gruppera relaterade data före lagring. Med ett fåtal dokument kan en databasoperation utföras med få frågor och därmed minskad slumpmässig diskåtkomst och det kommer att finnas färre associerade nyckelposter i motsvarande index. Överväganden i det här fallet kommer därför att vara:använd inbäddning för att ha färre dokument vilket i sin tur minskar omkostnaden per dokument. Använd kortare fältnamn om färre fält är involverade i en samling för att inte göra dokumentoverhead betydande. Kortare fältnamn minskar uttrycksförmågan, dvs.
{ Lname : "Briston", score : 5.9 }
kommer att spara 9 byte per dokument istället för att använda
{ last_name : "Briston", high_score: 5.9 }
Använd explicit fältet _id. Som standard lägger MongoDB-klienter till ett _id-fält till varje dokument genom att tilldela ett unikt 12-byte ObjectId för detta fält. Dessutom kommer _id-fältet att indexeras. Om dokumenten är ganska små kommer detta scenario att stå för en betydande mängd utrymme i det totala dokumentnumret. För lagringsoptimering får du ange värdet för fältet _id uttryckligen när du infogar dokument i en samling. Se dock till att värdet är unikt identifierat eftersom det fungerar som en primärnyckel för dokument i samlingen.
7. Dokumentstruktur och tillväxt
Detta sker som ett resultat av push-operationen där underdokument skjuts in i ett matrisfält eller när nya fält läggs till i ett befintligt dokument. Dokumenttillväxt har vissa bakslag, dvs för en begränsad samling, om storleken ändras kommer operationen automatiskt att misslyckas. För en MMAPv1-lagringsmotor kommer versioner före 3.0 att flytta dokumentet till disken om dokumentstorleken överskrids. Men senare versioner från och med 3.0, finns det ett koncept med Power of 2 Sized Allocations som minskar chanserna för sådana omallokeringar och möjliggör effektiv återanvändning av det frigjorda postutrymmet. Om du förväntar dig att din data kommer att växa, kanske du vill omfaktorisera din datamodell för att använda referenser mellan data i distinkta dokument istället för att använda en denormaliserad datamodell. För att undvika dokumenttillväxt kan du också överväga att använda en förallokeringsstrategi.
8. Datalivscykel
För ett program som endast använder de nyligen infogade dokumenten, överväg att använda en begränsad samling vars funktioner har diskuterats ovan.
Du kan också ställa in Time to Live-funktionen för din samling. Detta är ganska tillämpligt för åtkomsttokens i lösenordsåterställningsfunktionen för en applikation.
Time To Live (TTL)
Detta är en insamlingsinställning som gör det möjligt för mongod att automatiskt ta bort data efter en angiven varaktighet. Som standard används detta koncept för maskingenererade händelsedata, loggar och sessionsinformation som måste finnas kvar under en begränsad tid.
Exempel:
db.log_events.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )
Vi har skapat ett index skapat vid och specificerat ett expireAfterSeconds-värde på 3600 vilket är 1 timme efter skapandet. Om vi nu infogar ett dokument som:
db.log_events.insert( {
"createdAt": new Date(),
"logEvent": 2,
"logMessage": "This message was recorded."
} )
Detta dokument kommer att raderas efter 1 timme från tidpunkten för insättningen.
Du kan också ställa in en klockspecifik tid när du vill att dokumentet ska raderas. För att göra det, skapa först ett index, dvs:
db.log_events.createIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )
Nu kan vi infoga ett dokument och ange när det ska raderas.
db.log_events.insert( {
"expireAt": new Date(December 12, 2018 18:00:00'),
"logEvent": 2,
"logMessage": "Success!"
} )
Detta dokument kommer att raderas automatiskt när expireAt-värdet är äldre än det antal sekunder som anges i expireAfterSeconds, dvs 0 i detta fall.
Slutsats
Datamodellering är ett rymligt företag för alla applikationsdesigner för att förbättra dess databasprestanda. Innan du infogar data i din db, överväg applikationsbehoven och vilka som är de bästa datamodellmönstren du bör implementera. Dessutom kan viktiga aspekter av applikationer inte realiseras förrän implementeringen av en riktig datamodell.