Lägger upp ett nytt svar för att rensa upp detta. Jag utförde tester och läste källkoden igen och jag är säker på att irritationen kommer från en olycklig mening i skrivbekymmersdokumentationen. Med journalföring aktiverad och j:true
skrivproblem, skrivningen är hållbar och det finns inget mystiskt fönster för dataförlust.
Även om journalföring är på, finns det fortfarande en chans att förlora skrivningar i MongoDB?
Ja, eftersom hållbarheten också beror på de enskilda operationerna skriver oro.
"Som standard är den största omfattningen av förlorade skrivningar, det vill säga de som inte har gjorts till journalen, de som gjorts under de senaste 100 millisekunderna."
Detta är från Manage Journaling, vilket indikerar att du kan förlora skrivningar som gjorts sedan senaste gången journalen rensades till disken.
Det är korrekt. Journalen spolas av en separat tråd asynkront, så du kan förlora allt sedan den senaste spolningen.
Om jag vill ha mer hållbarhet, "För att tvinga mongod att engagera sig i tidskriften oftare kan du ange
j:true
. När en skrivoperation medj:true
väntar kommer mongod att minskajournalCommitInterval
till en tredjedel av det inställda värdet."
Detta irriterade mig också. Så här betyder det:
När du skickar en skrivoperation med j:true
, det utlöser inte diskspolningen omedelbart, och inte på nätverkstråden. Det är vettigt, eftersom det kan finnas dussintals applikationer som talar till samma mongod-instans. Om varje applikation skulle använda journalföring mycket, skulle db vara väldigt långsam eftersom den fsynkroniserar hela tiden.
Istället, vad som händer är att "hållbarhetstråden" kommer att ta alla pågående journalbekräftelser och spola dem till disk. Tråden är implementerad så här (kommentarer mina):
sleepmillis(oneThird); //dur.cpp, line 801
for( unsigned i = 1; i <= 2; i++ ) {
// break, if any j:true write is pending
if( commitJob._notify.nWaiting() )
break;
// or the number of bytes is greater than some threshold
if( commitJob.bytes() > UncommittedBytesLimit / 2 )
break;
// otherwise, sleep another third
sleepmillis(oneThird);
}
// fsync all pending writes
durThreadGroupCommit();
Så en väntande j:true
operationen kommer att göra att journalcommit-tråden commit tidigare än den normalt skulle göra, och den kommer att commitera alla väntande skrivningar till journalen, inklusive de som inte har j:true
ställ in.
Även i det här fallet ser det ut som att spola journalen till disken är asynkron så det finns fortfarande en chans att förlora skrivningar. Saknar jag något om hur man kan garantera att skrivningar inte går förlorade?
Skriven (eller getLastError
kommando) med en j:true
journalad skrivproblem kommer att vänta tills hållbarhetstråden slutför synkroniseringen , så det finns ingen risk för dataförlust (så långt som OS och hårdvara garanterar det).
Meningen "Men det finns ett fönster mellan journalbekräftelser när skrivoperationen inte är helt hållbar" syftar förmodligen på en mongod som körs med journalföring aktiverad som accepterar en skrivning som gör INTE använd j:true
skriva oro. I så fall finns det en chans att skrivandet försvinner sedan den senaste journalen.
Jag lämnade in en felrapport för detta dokument.