淺談MongoDB內(nèi)部的存儲原理
存儲引擎
本文介紹默認存儲引擎WiredTiger
WiredTiger架構
WiredTiger的寫操作會先寫入Cache,并持久化到WAL(Write ahead log),每60s會做一次Checkpoint,將當前的數(shù)據(jù)持久化,每,產(chǎn)生一個新的快照。Wiredtiger連接初始化時,首先將數(shù)據(jù)恢復至最新的快照狀態(tài),然后根據(jù)Checkpoint恢復數(shù)據(jù),以保證存儲可靠性
btree與b+tree
雖然遍歷數(shù)據(jù)的查詢是相對常見的,但是 MongoDB 認為查詢單個數(shù)據(jù)記錄遠比遍歷數(shù)據(jù)更加常見,由于 B 樹的非葉結(jié)點也可以存儲數(shù)據(jù),所以 查詢一條數(shù)據(jù)所需要的平均隨機 IO 次數(shù)會比 B+ 樹少,使用 B 樹的 MongoDB 在類似場景中的查詢速度就會比 MySQL 快。
這里并不是說 MongoDB 并不能對數(shù)據(jù)進行遍歷,我們在 MongoDB 中也可以使用范圍來查詢一批滿足對應條件的記錄,只是需要的時間會比 MySQL 長一些。MySQL 認為遍歷數(shù)據(jù)的查詢是常見的,所以它選擇 B+ 樹作為底層數(shù)據(jù)結(jié)構
cache
內(nèi)部緩存和文件系統(tǒng)緩存,默認情況下內(nèi)部緩存取50%(RAM-1 GB)或256M較大者,文件系統(tǒng)緩存使用所有當前可用的RAM。
Wiredtiger的Cache采用Btree的方式組織,每個Btree節(jié)點為一個page,root page是btree的根節(jié)點,internal page是btree的中間索引節(jié)點,leaf page是真正存儲數(shù)據(jù)的葉子節(jié)點;btree的數(shù)據(jù)以page為單位按需從磁盤加載或?qū)懭氪疟P,btree的每個page以文件里的extent形式(由文件offset + size標識)存儲
page
ROW_ARRAY: 每個數(shù)組單元(wt_row)存儲的是這個 kv row 在存儲在磁盤上的 page kv cell 行集合數(shù)據(jù)緩沖區(qū)偏移的位置和編碼方式(這個位置和編碼方式在 WT 上定義成一個 wt_cell 對象),通過這個信息偏移位置信息就可以訪問到這一樣在緩沖區(qū)中的 K/V 內(nèi)容值 ROW_UPDATE_ARRAY: 一個 mvcc list 對象,mvcc_list 與 wt_row 是一一對應的,mvcc list 當中存儲對 wt_row 修改的值,修改的值包括值更新和值刪除,是一個無鎖單向鏈表
寫操作 遍歷btree,找到需要更新的page如果cache中沒有對應的page,會從磁盤中加載page,鍵值對存入WT_ROW如果是insert操作,更新WT_INSERT,如果是update/delete操作,更新WT_UPDATE如果需要,將操作記錄寫入journal
我們通過一個實例來說明: 假如一個 page 存儲了一個 [0,100] 的 key 范圍,磁盤上原來存儲的行 key=2, 10 ,20, 30 , 50, 80, 90,他們的值分別是value = 102, 110, 120, 130, 150, 180, 190。 在 page 數(shù)據(jù)從磁盤讀到內(nèi)存后,分別對 key=2 的 value 進行了兩次修改,兩次修改的值是分別 402,502。對 key = 20 ,50 的 value 做了一次修改,修改后的 value = 122, 155,后有分配 insert 了新的 key = 3,5, 41, 99,value = 203,205,241,299。 那么在內(nèi)存中的 page 就是如下圖組織數(shù)據(jù)的:
相鄰的兩 wt_row 之間可能不是連續(xù)的,他們之間可以插入新的單元,例如 row1(key = 2) 和 row2(key=10) 可以插入 3 和 5,這兩個 row 之間需要有一個排序的數(shù)據(jù)結(jié)構(WT用 skiplist 數(shù)據(jù)結(jié)構)來存儲插入的 K/V,就需要一個 skiplist 對象數(shù)組 page_insert_array與row array對應。這里需要說明的是 圖6 當中紅色框當中的 skiplist8,它是用于存儲 row1(key=2) 范圍之前的 insert 數(shù)據(jù),圖中如果有 key =1 的數(shù)據(jù) insert,那么這個數(shù)據(jù)會新增到 skiplist8 當中。
那么圖中row與 insert skiplist 的對應關系就是:
row1 之前的范圍對應 insert 是 skiplist8row1 和 row2之間對應的 insert 是 skiplist1row2 和 row3之間對應的 insert 是 skiplist3…row7 之后的范圍對應的 insert 是 skiplist7 checkpoint
一個Checkpoit包含如下元數(shù)據(jù): root page地址,地址由文件offset,size及內(nèi)容的checksum組成 alloc extent list地址,存儲從上次checkpoint起新分配的extent列表 discard extent list地址,存儲從上次checkpoint起丟棄的extent列表 available extent list地址,存儲可分配的extent列表,只有最新的checkpoint包含該列表 file size 如需恢復到該checkpoint的狀態(tài),將文件truncate到file size即可
WAL(journal)
日志文件記錄的是從上一個checkpoint之后的實際操作,該文件每100ms或文件大小到達100M就從緩存同步到磁盤
整體關系
分布式存儲
架構
架構圖:
寫數(shù)據(jù)流程:
讀數(shù)據(jù)流程:
到此這篇關于淺談MongoDB內(nèi)部的存儲原理的文章就介紹到這了,更多相關MongoDB存儲原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MongoDB的$sample、aggregate和$rand實現(xiàn)隨機選取數(shù)據(jù)
在MongoDB中,我們可以使用內(nèi)置的$sample聚合操作符來隨機生成數(shù)據(jù),$sample可以從集合文檔中隨機選擇指定數(shù)量的文檔,但由于其查詢整個集合的性能問題,應該慎用,aggregate方法以及$rand函數(shù)的結(jié)合使用可以實現(xiàn)更加靈活的查詢操作,并且可以對查詢結(jié)果進行精細篩選2024-01-01MongoDB實現(xiàn)查詢、分頁和排序操作以及游標的使用
本文詳細講解了MongoDB實現(xiàn)查詢、分頁和排序操作以及游標的使用方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07python實現(xiàn)爬蟲數(shù)據(jù)存到 MongoDB
本文給大家分享的是使用python實現(xiàn)將爬蟲爬到的數(shù)據(jù)存儲到mongoDB數(shù)據(jù)庫中的實例代碼,有需要的小伙伴可以參考下2016-09-09