前言
本文重點叙述下mongodb存儲特性和内部原理,下一篇文章咱們一起來搭建下Replica Sets+Sharded Cluster的叢集
存儲引擎
wiredTiger引擎
1、3.0新增引擎 推薦使用 2、可以支撐更高的讀寫負載和并發量
所有的write請求都基于“文檔級别”的lock,是以多個用戶端可以同時更新一個colleciton中的不同文檔,這種更細顆粒度的lock,可以支撐更高的讀寫負載和并發量。因為對于production環境,更多的CPU可以有效提升wireTiger的性能,因為它是的IO是多線程的
3、配置緩存
可以通過在配置檔案中指定“cacheSizeGB”參數設定引擎使用的記憶體量,此記憶體用于緩存工作集資料(索引、namespace,未送出的write,query緩沖等)
4、journal即預寫事務日志
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引擎
1、原生的存儲引擎 直接使用系統級的記憶體映射檔案機制(memory mapped files)
2、對于insert、read和in-place update(update不導緻文檔的size變大)性能較高
3、不過MMAPV1在lock的并發級别上,支援到collection級别 是以對于同一個collection同時隻能有一個write操作執行 這一點相對于wiredTiger而言,在write并發性上就稍弱一些
4、對于production環境而言,較大的記憶體可以使此引擎更加高效,有效減少“page fault”頻率
5、但是因為其并發級别的限制,多核CPU并不能使其受益
6、此引擎将不會使用到swap空間,但是對于wiredTiger而言需要一定的swap空間
7、對于大檔案MAP操作,比較忌諱的就是在檔案的中間修改資料,而且導緻檔案長度增長,這會涉及到索引引用的大面積調整
8、所有的記錄在磁盤上連續存儲,當一個document尺寸變大時,mongodb需要重新配置設定一個新的記錄(舊的record标記删除,新的記record在檔案尾部重新配置設定空間)
9、這意味着mongodb同時還需要更新此文檔的索引(指向新的record的offset),與in-place update相比,将消耗更多的時間和存儲開支。
10、由此可見,如果你的mongodb的使用場景中有大量的這種update,那麼或許MMAPv1引擎并不太适合
11、同時也反映出如果document沒有索引,是無法保證document在read中的順序(即自然順序)
12、3.0之後,mongodb預設采用“Power of 2 Sized Allocations”,是以每個document對應的record将有實際資料和一些padding組成,這padding可以允許document的尺寸在update時适度的增長,以最小化重新配置設定record的可能性。此外重新配置設定空間,也會導緻磁盤碎片(舊的record空間)
Power of 2 Sized Allocations
1、預設情況下,MMAPv1中空間配置設定使用此政策,每個document的size是2的次幂,比如32、64、128、256...2MB,如果文檔尺寸大于2MB,則空間為2MB的倍數(2M,4M,6M等)
2、2種優勢
- 那些删除或者update變大而産生的磁盤碎片空間(尺寸變大,意味着開辟新空間存儲此document,舊的空間被mark為deleted)可以被其他insert重用
- 再者padding可以允許文檔尺寸有限度的增長,而無需每次update變大都重新配置設定空間。
3、mongodb還提供了一個可選的“No padding Allocation”政策(即按照實際資料尺寸配置設定空間),如果你确信資料絕大多數情況下都是insert、in-place update,極少的delete,此政策将可以有效的節約磁盤空間,看起來資料更加緊湊,磁盤使用率也更高
備注:mongodb 3.2+之後,預設的存儲引擎為“wiredTiger”,大量優化了存儲性能,建議更新到3.2+版本
Capped Collections
1、尺寸大小是固定值 類似于一個可循環使用的buffer
如果空間被填滿之後,新的插入将會覆寫最舊的文檔,通常不會對Capped進行删除或者update操作,是以這種類型的collection能夠支撐較高的write和read
2、不需要對這種collection建構索引,因為insert是append(insert的資料儲存是嚴格有序的)、read是iterator方式,幾乎沒有随機讀
3、在replica set模式下,其oplog就是使用這種colleciton實作的
4、Capped Collection的設計目的就是用來儲存“最近的”一定尺寸的document
db.createCollection("capped_collections",new CreateCollectionOptions() .capped(true) .maxDocuments(6552350) .usePowerOf2Sizes(false).autoIndex(true));//不會涉及到更新,是以可以不用power of 2
5、類似于“FIFO”隊列,而且是有界隊列 适用于資料緩存,消息類型的存儲
6、Capped支援update,但是我們通常不建議,如果更新導緻document的尺寸變大,操作将會失敗,隻能使用in-place update,而且還需要建立合适的索引
7、在capped中使用remove操作是允許的
8、autoIndex屬性表示預設對_id字段建立索引
資料模型(Data Model)
1、mongodb支援内嵌document 即document中一個字段的值也是一個document
2、如果内嵌文檔(即reference文檔)尺寸是動态的,比如一個user可以有多個card,因為card數量無法預估,這就會導緻document的尺寸可能不斷增加以至于超過“Power of 2 Allocate”,進而觸發空間重新配置設定,帶來性能開銷
3、這種情況下,我們需要将内嵌文檔單獨儲存到一個額外的collection中,作為一個或者多個document存儲,比如把card清單儲存在card collection中
4、如果reference文檔尺寸較小,可以内嵌,如果尺寸較大,建議單獨存儲。此外内嵌文檔還有個優點就是write的原子性
索引
1、提高查詢性能,預設情況下_id字段會被建立唯一索引;2、因為索引不僅需要占用大量記憶體而且也會占用磁盤,是以我們需要建立有限個索引,而且最好不要建立重複索引;3、每個索引需要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