Mongodb存儲特性與內部原理

前言

本文重點敘述下mongodb存儲特性和內部原理,
下一篇文章我們一塊兒來搭建下Replica Sets+Sharded Cluster的集羣
複製代碼

存儲引擎

wiredTiger引擎

一、3.0新增引擎 推薦使用 二、能夠支撐更高的讀寫負載和併發量linux

全部的write請求都基於「文檔級別」的lock,
所以多個客戶端能夠同時更新一個colleciton中的不一樣文檔,
這種更細顆粒度的lock,能夠支撐更高的讀寫負載和併發量。
由於對於production環境,更多的CPU能夠有效提高wireTiger的性能,
由於它是的IO是多線程的
複製代碼

三、配置緩存web

能夠經過在配置文件中指定「cacheSizeGB」參數設定引擎使用的內存量,
此內存用於緩存工做集數據(索引、namespace,未提交的write,query緩衝等)
複製代碼

四、journal即預寫事務日誌mongodb

a、journal就是一個預寫事務日誌,來確保數據的持久性數據庫

b、wiredTiger每隔60秒(默認)或者待寫入的數據達到2G時,mongodb將對journal文件提交一個checkpoint(檢測點,將內存中的數據變動flush到磁盤中的數據文件中,並作一個標記點,表示此前的數據表示已經持久存儲在了數據文件中,此後的數據變動存在於內存和journal日誌)緩存

c、對於write操做,首先被持久寫入journal,而後在內存中保存變動數據,條件知足後提交一個新的檢測點,即檢測點以前的數據只是在journal中持久存儲,但並無在mongodb的數據文件中持久化,延遲持久化能夠提高磁盤效率,若是在提交checkpoint以前,mongodb異常退出,此後再次啓動能夠根據journal日誌恢復數據安全

d、journal日誌默認每一個100毫秒同步磁盤一次,每100M數據生成一個新的journal文件,journal默認使用了snappy壓縮,檢測點建立後,此前的journal日誌便可清除。網絡

e、mongod能夠禁用journal,這在必定程度上能夠下降它帶來的開支;對於單點mongod,關閉journal可能會在異常關閉時丟失checkpoint之間的數據(那些還沒有提交到磁盤數據文件的數據);對於replica set架構,持久性的保證稍高,但仍然不能保證絕對的安全(好比replica set中全部節點幾乎同時退出時)多線程

MMAPv1引擎

一、原生的存儲引擎 直接使用系統級的內存映射文件機制(memory mapped files)架構

二、對於insert、read和in-place update(update不致使文檔的size變大)性能較高併發

三、不過MMAPV1在lock的併發級別上,支持到collection級別 因此對於同一個collection同時只能有一個write操做執行 這一點相對於wiredTiger而言,在write併發性上就稍弱一些

四、對於production環境而言,較大的內存可使此引擎更加高效,有效減小「page fault」頻率

五、可是由於其併發級別的限制,多核CPU並不能使其受益

六、此引擎將不會使用到swap空間,可是對於wiredTiger而言須要必定的swap空間

七、對於大文件MAP操做,比較忌諱的就是在文件的中間修改數據,並且致使文件長度增加,這會涉及到索引引用的大面積調整

八、全部的記錄在磁盤上連續存儲,當一個document尺寸變大時,mongodb須要從新分配一個新的記錄(舊的record標記刪除,新的記record在文件尾部從新分配空間)

九、這意味着mongodb同時還須要更新此文檔的索引(指向新的record的offset),與in-place update相比,將消耗更多的時間和存儲開支。

十、因而可知,若是你的mongodb的使用場景中有大量的這種update,那麼或許MMAPv1引擎並不太適合

十一、同時也反映出若是document沒有索引,是沒法保證document在read中的順序(即天然順序)

十二、3.0以後,mongodb默認採用「Power of 2 Sized Allocations」,因此每一個document對應的record將有實際數據和一些padding組成,這padding能夠容許document的尺寸在update時適度的增加,以最小化從新分配record的可能性。此外從新分配空間,也會致使磁盤碎片(舊的record空間)

Power of 2 Sized Allocations

一、默認狀況下,MMAPv1中空間分配使用此策略,每一個document的size是2的次冪,好比3二、6四、12八、256...2MB,若是文檔尺寸大於2MB,則空間爲2MB的倍數(2M,4M,6M等)

二、2種優點

  • 那些刪除或者update變大而產生的磁盤碎片空間(尺寸變大,意味着開闢新空間存儲此document,舊的空間被mark爲deleted)能夠被其餘insert重用

  • 再者padding能夠容許文檔尺寸有限度的增加,而無需每次update變大都從新分配空間。

三、mongodb還提供了一個可選的「No padding Allocation」策略(即按照實際數據尺寸分配空間),若是你確信數據絕大多數狀況下都是insert、in-place update,極少的delete,此策略將能夠有效的節約磁盤空間,看起來數據更加緊湊,磁盤利用率也更高

備註:mongodb 3.2+以後,默認的存儲引擎爲「wiredTiger」,大量優化了存儲性能,建議升級到3.2+版本

Capped Collections

一、尺寸大小是固定值 相似於一個可循環使用的buffer

若是空間被填滿以後,新的插入將會覆蓋最舊的文檔,一般不會對Capped進行刪除或者update操做,因此這種類型的collection可以支撐較高的write和read

二、不須要對這種collection構建索引,由於insert是append(insert的數據保存是嚴格有序的)、read是iterator方式,幾乎沒有隨機讀

三、在replica set模式下,其oplog就是使用這種colleciton實現的

四、Capped Collection的設計目的就是用來保存「最近的」必定尺寸的document

db.createCollection("capped_collections",
new CreateCollectionOptions()  
.capped(true)  
.maxDocuments(6552350)  
.usePowerOf2Sizes(false).autoIndex(true));//不會涉及到更新,因此能夠不用power of 2  
複製代碼

五、相似於「FIFO」隊列,並且是有界隊列 適用於數據緩存,消息類型的存儲

六、Capped支持update,可是咱們一般不建議,若是更新致使document的尺寸變大,操做將會失敗,只能使用in-place update,並且還須要創建合適的索引

七、在capped中使用remove操做是容許的

八、autoIndex屬性表示默認對_id字段創建索引

數據模型(Data Model)

一、mongodb支持內嵌document 即document中一個字段的值也是一個document

二、若是內嵌文檔(即reference文檔)尺寸是動態的,好比一個user能夠有多個card,由於card數量沒法預估,這就會致使document的尺寸可能不斷增長以致於超過「Power of 2 Allocate」,從而觸發空間從新分配,帶來性能開銷

三、這種狀況下,咱們須要將內嵌文檔單獨保存到一個額外的collection中,做爲一個或者多個document存儲,好比把card列表保存在card collection中

四、若是reference文檔尺寸較小,能夠內嵌,若是尺寸較大,建議單獨存儲。此外內嵌文檔還有個優勢就是write的原子性

索引

一、提升查詢性能,默認狀況下_id字段會被建立惟一索引;

二、由於索引不只須要佔用大量內存並且也會佔用磁盤,因此咱們須要創建有限個索引,並且最好不要創建重複索引;

三、每一個索引須要8KB的空間,同時update、insert操做會致使索引的調整,
會稍微影響write的性能,索引只能使read操做收益,
因此讀寫比高的應用能夠考慮創建索引

複製代碼

大集合拆分

好比一個用於存儲log的collection,
log分爲有兩種「dev」、「debug」,結果大體爲
{"log":"dev","content":"...."},{"log":"debug","content":"....."}。
這兩種日誌的document個數比較接近,
對於查詢時,即便給log字段創建索引,這個索引也不是高效的,
因此能夠考慮將它們分別放在2個Collection中,好比:log_dev和log_debug。
複製代碼

數據生命週期管理

mongodb提供了expire機制,
便可以指定文檔保存的時長,過時後自動刪除,即TTL特性,
這個特性在不少場合將是很是有用的,
好比「驗證碼保留15分鐘有效期」、「消息保存7天」等等,
mongodb會啓動一個後臺線程來刪除那些過時的document

須要對一個日期字段建立「TTL索引」,
好比插入一個文檔:{"check_code":"101010",$currentDate:{"created":true}}},
其中created字段默認值爲系統時間Date;而後咱們對created字段創建TTL索引:

collection.createIndex(new Document("created",1),new IndexOptions().expireAfter(15L,TimeUnit.MILLISECONDS));//15分鐘  

向collection中insert文檔時,created的時間爲系統當前時間,
其中在creatd字段上創建了「TTL」索引,索引TTL爲15分鐘,
mongodb後臺線程將會掃描並檢測每條document的(created時間 + 15分鐘)與當前時間比較,
若是發現過時,則刪除索引條目(連帶刪除document)。

某些狀況下,可能須要實現「在某個指定的時刻過時」,
只須要將上述文檔和索引變通改造便可,
即created指定爲「目標時間」,expiredAfter指定爲0。 
複製代碼

架構模式

Replica set 複製集

一般是三個對等的節點構成一個「複製集」集羣,
有「primary」和secondary等多種角色
其中primary負責讀寫請求,secondary能夠負責讀請求,這又配置決定,
其中secondary緊跟primary並應用write操做;
若是primay失效,則集羣進行「多數派」選舉,選舉出新的primary,即failover機制,即HA架構。
複製集解決了單點故障問題,也是mongodb垂直擴展的最小部署單位,
固然sharding cluster中每一個shard節點也可使用Replica set提升數據可用性。
複製代碼

Sharding cluster 分片集羣

數據水平擴展的手段之一;
replica set這種架構的缺點就是「集羣數據容量」受限於單個節點的磁盤大小,
若是數據量不斷增長,對它進行擴容將時很是苦難的事情,因此咱們須要採用Sharding模式來解決這個問題。
將整個collection的數據將根據sharding key被sharding到多個mongod節點上,
即每一個節點持有collection的一部分數據,這個集羣持有所有數據,
原則上sharding能夠支撐數TB的數據。
複製代碼

系統配置

  • 建議mongodb部署在linux系統上,較高版本,選擇合適的底層文件系統(ext4),開啓合適的swap空間

  • 不管是MMAPV1或者wiredTiger引擎,較大的內存總能帶來直接收益

  • 對數據存儲文件關閉「atime」(文件每次access都會更改這個時間值,表示文件最近被訪問的時間),能夠提高文件訪問效率

  • ulimit參數調整,這個在基於網絡IO或者磁盤IO操做的應用中,一般都會調整,上調系統容許打開的文件個數(ulimit -n 65535)。

數據文件存儲原理(Data Files storage,MMAPV1引擎)

 mongodb的數據將會保存在底層文件系統中,
 好比咱們dbpath設定爲「/data/db」目錄,
 咱們建立一個database爲「test」,collection爲「sample」,
 而後在此collection中插入數條documents。咱們查看dbpath下生成的文件列表:
複製代碼

能夠看到test這個數據庫目前已經有6個數據文件(data files),
每一個文件以「database」的名字 + 序列數字組成,
序列號從0開始,逐個遞增,數據文件從16M開始,每次擴張一倍(16M、32M、64M、128M...),
在默認狀況下單個data file的最大尺寸爲2G,
若是設置了smallFiles屬性(配置文件中)則最大限定爲512M;
mongodb中每一個database最多支持16000個數據文件,即約32T,
若是設置了smallFiles則單個database的最大數據量爲8T。
若是你的database中的數據文件不少,
可使用directoryPerDB配置項將每一個db的數據文件放置在各自的目錄中。
當最後一個data file有數據寫入後,
mongodb將會當即預分配下一個data file,
能夠經過「--nopreallocate」啓動命令參數來關閉此選項
複製代碼

參考文檔

https://blog.csdn.net/quanmaoluo5461/article/details/85164588
複製代碼
相關文章
相關標籤/搜索