Opublikowanie nowej odpowiedzi, aby to uporządkować. Przeprowadziłem testy i ponownie przeczytałem kod źródłowy i jestem pewien, że irytację bierze się z niefortunnego zdania w dokumentacji dotyczącej zapisu. Z włączonym dziennikiem i j:true
problem związany z zapisem, zapis jest trwały i nie ma tajemniczego okna utraty danych.
Nawet jeśli dziennik jest włączony, czy nadal istnieje szansa na utratę zapisów w MongoDB?
Tak, ponieważ trwałość zależy również od poszczególnych operacji napisz obawy.
„Domyślnie największy zakres utraconych zapisów, tj. tych, które nie zostały zapisane w dzienniku, to te, które powstały w ciągu ostatnich 100 milisekund”.
Pochodzi z Zarządzaj dziennikami, co oznacza, że możesz utracić zapisy dokonane od czasu ostatniego opróżnienia dziennika na dysk.
To jest poprawne. Dziennik jest opróżniany przez oddzielny wątek asynchronicznie, więc możesz stracić wszystko od ostatniego opróżnienia.
Jeśli chcę większej trwałości, „Aby zmusić mongoda do częstszego zatwierdzania dziennika, możesz określić j:true
. Gdy operacja zapisu z j:true
jest w toku, mongod zmniejszy journalCommitInterval
do jednej trzeciej ustawionej wartości."
Mnie też to irytowało. Oto, co to oznacza:
Kiedy wysyłasz operację zapisu z j:true
, nie powoduje natychmiastowego opróżnienia dysku, a nie w wątku sieciowym. Ma to sens, ponieważ mogą istnieć dziesiątki aplikacji komunikujących się z tą samą instancją mongod. Gdyby każda aplikacja często korzystała z kronikowania, baza danych byłaby bardzo wolna, ponieważ cały czas fsynchronizowałaby.
Zamiast tego dzieje się tak, że „wątek trwałości” zabierze wszystkie oczekujące zatwierdzenia dziennika i opróżni je na dysk. Wątek jest zaimplementowany w ten sposób (moje komentarze):
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();
Tak więc oczekujący j:true
operacja spowoduje, że wątek zatwierdzenia dziennika zostanie zatwierdzony wcześniej niż normalnie i zatwierdzi wszystkie oczekujące zapisy do dziennika, w tym te, które nie mają j:true
zestaw.
Nawet w tym przypadku wygląda na to, że opróżnianie dziennika na dysk jest asynchroniczne, więc nadal istnieje szansa na utratę zapisów. Czy brakuje mi czegoś o tym, jak zagwarantować, że zapisy nie zostaną utracone?
Write (lub getLastError
polecenie) z j:true
obawy dotyczące zapisu w dzienniku poczekają na zakończenie synchronizacji wątku trwałości , więc nie ma ryzyka utraty danych (o ile gwarantuje to system operacyjny i sprzęt).
Zdanie „Jednakże istnieje okno między zatwierdzeniami dziennika, gdy operacja zapisu nie jest w pełni trwała” prawdopodobnie odnosi się do mongoda działającego z włączonym dziennikiem, który akceptuje zapis, który NIE użyj j:true
napisz troskę. W takim przypadku istnieje szansa, że zapis zostanie utracony od czasu ostatniego zatwierdzenia dziennika.
Zgłosiłem w tym celu raport o błędzie w dokumentacji.