1、Journal?
????????Journal是 MongoDB 存儲(chǔ)引擎層的概念,目前 MongoDB主要支持 mmapv1袋马、wiredtiger、mongorocks 等存儲(chǔ)引擎秸应,都支持配置Journal虑凛。????????
????????MongoDB 所有的數(shù)據(jù)寫入、讀取最終都是調(diào)存儲(chǔ)引擎層的接口來存儲(chǔ)灸眼、讀取數(shù)據(jù)卧檐,journal 是存儲(chǔ)引擎存儲(chǔ)數(shù)據(jù)時(shí)的一種輔助機(jī)制。
Journal日志焰宣,是MongoDB的預(yù)寫日志W(wǎng)AL(類似Mysql的Redo log)霉囚。
默認(rèn)情況下mongodb每100毫秒往journal文件中flush一次數(shù)據(jù),不過這是在數(shù)據(jù)文件和journal文件處于同一磁盤卷上的情況匕积,而如果數(shù)據(jù)文件和journal文件不在同一磁盤卷上時(shí)盈罐,默認(rèn)刷新輸出時(shí)間是30毫秒。不過這個(gè)毫秒值是可以修改的闪唆,可修改范圍是2~300盅粪,值越低,刷新輸出頻率越高悄蕾,數(shù)據(jù)安全度也就越高票顾,但磁盤性能上的開銷也更高。
????????以wiredtiger 為例帆调,如果不配置 journal奠骄,寫入 wiredtiger 的數(shù)據(jù),并不會(huì)立即持久化存儲(chǔ)番刊;而是每分鐘(默認(rèn))或者待寫入的數(shù)據(jù)達(dá)到2G時(shí)含鳞,會(huì)做一次全量的checkpoint(storage.syncPeriodSecs配置項(xiàng),默認(rèn)為1分鐘)芹务,將所有的數(shù)據(jù)持久化蝉绷。如果中間出現(xiàn)宕機(jī),那么數(shù)據(jù)只能恢復(fù)到最近的一次checkpoint(檢測點(diǎn)枣抱,將內(nèi)存中的數(shù)據(jù)變更flush到磁盤中的數(shù)據(jù)文件中熔吗,并做一個(gè)標(biāo)記點(diǎn),表示此前的數(shù)據(jù)表示已經(jīng)持久存儲(chǔ)在了數(shù)據(jù)文件中佳晶,此后的數(shù)據(jù)變更存在于內(nèi)存和journal日志)磁滚,這樣最多可能丟掉1分鐘的數(shù)據(jù)。
????????所以建議「一定要開啟journal」,開啟 journal 后垂攘,每次寫入會(huì)記錄一條操作日志(通過journal可以重新構(gòu)造出寫入的數(shù)據(jù))。這樣即使出現(xiàn)宕機(jī)淤刃,啟動(dòng)時(shí) Wiredtiger 會(huì)先將數(shù)據(jù)恢復(fù)到最近的一次checkpoint的點(diǎn)晒他,然后重放后續(xù)的 journal 操作日志來恢復(fù)數(shù)據(jù)。
????????journal文件是以“j._”開頭命名的逸贾,且是append only的陨仅,如果1個(gè)journal文件滿了1G大小,mongodb就會(huì)新創(chuàng)建一個(gè)journal文件來使用铝侵,一旦某個(gè)journal文件所記載的寫操作都被使用過了灼伤,mongodb就會(huì)把這個(gè)journal文件刪除。通常在journal文件所在的文件夾下咪鲜,只會(huì)存在2~3個(gè)journal文件狐赡,除非你使用mongodb每秒都寫入大量的數(shù)據(jù)。而使用 smallfiles 這個(gè)運(yùn)行時(shí)選項(xiàng)可以將journal文件大小減至128M大小疟丙。
????????MongoDB 里的 journal 行為 主要由2個(gè)參數(shù)控制颖侄,storage.journal.enabled 決定是否開啟journal,storage.journal.commitInternalMs 決定 journal 刷盤的間隔享郊,默認(rèn)為100ms览祖,用戶也可以通過寫入時(shí)指定 writeConcern 為 {j: ture} 來每次寫入時(shí)都確保 journal 刷盤。
2炊琉、oplog
????????oplog 是 MongoDB 主從復(fù)制層面的一個(gè)概念展蒂,通過 oplog 來實(shí)現(xiàn)復(fù)制集節(jié)點(diǎn)間數(shù)據(jù)同步,客戶端將數(shù)據(jù)寫入到 Primary苔咪,Primary 寫入數(shù)據(jù)后會(huì)記錄一條 oplog锰悼,Secondary 從 Primary(或其他 Secondary )拉取 oplog 并重放,來確保復(fù)制集里每個(gè)節(jié)點(diǎn)存儲(chǔ)相同的數(shù)據(jù)悼泌。
????????oplog 在 MongoDB 里是一個(gè)普通的 capped collection(固定集合)松捉,對于存儲(chǔ)引擎來說,oplog只是一部分普通的數(shù)據(jù)而已馆里。
????????MongoDB 的一次寫入:
????????MongoDB 復(fù)制集里寫入一個(gè)文檔時(shí)隘世,需要修改如下數(shù)據(jù):
? ? ? ? 1)將文檔數(shù)據(jù)寫入對應(yīng)的集合;
? ? ? ? 2)更新集合的所有索引信息鸠踪;
? ? ? ? 3)寫入一條oplog用于同步丙者。
????????上面3個(gè)修改操作,需要確保要么都成功营密,要么都失敗械媒,不能出現(xiàn)部分成功的情況,否則:
? ? ? ? 1)如果數(shù)據(jù)寫入成功,但索引寫入失敗纷捞,那么會(huì)出現(xiàn)某個(gè)數(shù)據(jù)痢虹,通過全表掃描能讀取到,但通過索引就無法讀戎骼堋奖唯;
? ? ? ? 2)如果數(shù)據(jù)、索引都寫入成功糜值,但 oplog 寫入不成功丰捷,那么寫入操作就不能正常的同步到備節(jié)點(diǎn),出現(xiàn)主備數(shù)據(jù)不一致的情況寂汇。
????????MongoDB 在寫入數(shù)據(jù)時(shí)病往,會(huì)將上述3個(gè)操作放到一個(gè) wiredtiger 的事務(wù)里,確苯景辏「原子性」停巷。
wiredtiger 提交事務(wù)時(shí),會(huì)將所有修改操作應(yīng)用累贤,并將上述3個(gè)操作寫入到一條 journal 操作日志里叠穆;后臺(tái)會(huì)周期性的checkpoint,將修改持久化臼膏,并移除無用的journal硼被。
從數(shù)據(jù)布局看,oplog 與 journal 的關(guān)系如下圖:
????????oplog 與 journal?誰先寫入的問題:
? ? ? ? 1)oplog 與 journal 是 MongoDB 里不同層次的概念渗磅,放在一起比先后本身是不合理的嚷硫。
? ? ? ? 2)oplog 在 MongoDB 里是一個(gè)普通的集合,所以 oplog 的寫入與普通集合的寫入并無區(qū)別始鱼。
? ? ? ? 3)一次寫入仔掸,會(huì)對應(yīng)數(shù)據(jù)、索引医清,oplog的修改起暮,而這3個(gè)修改,會(huì)對應(yīng)一條journal操作日志会烙。