前言
本文重點(diǎn)敘述下mongodb存儲(chǔ)特性和內(nèi)部原理,
下一篇文章咱們一起來(lái)搭建下Replica?Sets+Sharded?Cluster的集群存儲(chǔ)引擎
wiredTiger引擎
1、3.0新增引擎 推薦使用 2、可以支撐更高的讀寫(xiě)負(fù)載和并發(fā)量
所有的write請(qǐng)求都基于“文檔級(jí)別”的lock,
因此多個(gè)客戶端可以同時(shí)更新一個(gè)colleciton中的不同文檔,
這種更細(xì)顆粒度的lock,可以支撐更高的讀寫(xiě)負(fù)載和并發(fā)量。
因?yàn)閷?duì)于production環(huán)境,更多的CPU可以有效提升wireTiger的性能,
因?yàn)樗堑腎O是多線程的3、配置緩存
可以通過(guò)在配置文件中指定“cacheSizeGB”參數(shù)設(shè)定引擎使用的內(nèi)存量,
此內(nèi)存用于緩存工作集數(shù)據(jù)(索引、namespace,未提交的write,query緩沖等)4、journal即預(yù)寫(xiě)事務(wù)日志
a、journal就是一個(gè)預(yù)寫(xiě)事務(wù)日志,來(lái)確保數(shù)據(jù)的持久性
b、wiredTiger每隔60秒(默認(rèn))或者待寫(xiě)入的數(shù)據(jù)達(dá)到2G時(shí),mongodb將對(duì)journal文件提交一個(gè)checkpoint(檢測(cè)點(diǎn),將內(nèi)存中的數(shù)據(jù)變更flush到磁盤(pán)中的數(shù)據(jù)文件中,并做一個(gè)標(biāo)記點(diǎn),表示此前的數(shù)據(jù)表示已經(jīng)持久存儲(chǔ)在了數(shù)據(jù)文件中,此后的數(shù)據(jù)變更存在于內(nèi)存和journal日志)
c、對(duì)于write操作,首先被持久寫(xiě)入journal,然后在內(nèi)存中保存變更數(shù)據(jù),條件滿足后提交一個(gè)新的檢測(cè)點(diǎn),即檢測(cè)點(diǎn)之前的數(shù)據(jù)只是在journal中持久存儲(chǔ),但并沒(méi)有在mongodb的數(shù)據(jù)文件中持久化,延遲持久化可以提升磁盤(pán)效率,如果在提交checkpoint之前,mongodb異常退出,此后再次啟動(dòng)可以根據(jù)journal日志恢復(fù)數(shù)據(jù)
d、journal日志默認(rèn)每個(gè)100毫秒同步磁盤(pán)一次,每100M數(shù)據(jù)生成一個(gè)新的journal文件,journal默認(rèn)使用了snappy壓縮,檢測(cè)點(diǎn)創(chuàng)建后,此前的journal日志即可清除。
e、mongod可以禁用journal,這在一定程度上可以降低它帶來(lái)的開(kāi)支;對(duì)于單點(diǎn)mongod,關(guān)閉journal可能會(huì)在異常關(guān)閉時(shí)丟失checkpoint之間的數(shù)據(jù)(那些尚未提交到磁盤(pán)數(shù)據(jù)文件的數(shù)據(jù));對(duì)于replica set架構(gòu),持久性的保證稍高,但仍然不能保證絕對(duì)的安全(比如replica set中所有節(jié)點(diǎn)幾乎同時(shí)退出時(shí))
MMAPv1引擎
1、原生的存儲(chǔ)引擎 直接使用系統(tǒng)級(jí)的內(nèi)存映射文件機(jī)制(memory mapped files)
2、對(duì)于insert、read和in-place update(update不導(dǎo)致文檔的size變大)性能較高
3、不過(guò)MMAPV1在lock的并發(fā)級(jí)別上,支持到collection級(jí)別 所以對(duì)于同一個(gè)collection同時(shí)只能有一個(gè)write操作執(zhí)行 這一點(diǎn)相對(duì)于wiredTiger而言,在write并發(fā)性上就稍弱一些
4、對(duì)于production環(huán)境而言,較大的內(nèi)存可以使此引擎更加高效,有效減少“page fault”頻率
5、但是因?yàn)槠洳l(fā)級(jí)別的限制,多核CPU并不能使其受益
6、此引擎將不會(huì)使用到swap空間,但是對(duì)于wiredTiger而言需要一定的swap空間
7、對(duì)于大文件MAP操作,比較忌諱的就是在文件的中間修改數(shù)據(jù),而且導(dǎo)致文件長(zhǎng)度增長(zhǎng),這會(huì)涉及到索引引用的大面積調(diào)整
8、所有的記錄在磁盤(pán)上連續(xù)存儲(chǔ),當(dāng)一個(gè)document尺寸變大時(shí),mongodb需要重新分配一個(gè)新的記錄(舊的record標(biāo)記刪除,新的記record在文件尾部重新分配空間)
9、這意味著mongodb同時(shí)還需要更新此文檔的索引(指向新的record的offset),與in-place update相比,將消耗更多的時(shí)間和存儲(chǔ)開(kāi)支。
10、由此可見(jiàn),如果你的mongodb的使用場(chǎng)景中有大量的這種update,那么或許MMAPv1引擎并不太適合
11、同時(shí)也反映出如果document沒(méi)有索引,是無(wú)法保證document在read中的順序(即自然順序)
12、3.0之后,mongodb默認(rèn)采用“Power of 2 Sized Allocations”,所以每個(gè)document對(duì)應(yīng)的record將有實(shí)際數(shù)據(jù)和一些padding組成,這padding可以允許document的尺寸在update時(shí)適度的增長(zhǎng),以最小化重新分配record的可能性。此外重新分配空間,也會(huì)導(dǎo)致磁盤(pán)碎片(舊的record空間)
Power of 2 Sized Allocations
1、默認(rèn)情況下,MMAPv1中空間分配使用此策略,每個(gè)document的size是2的次冪,比如32、64、128、256...2MB,如果文檔尺寸大于2MB,則空間為2MB的倍數(shù)(2M,4M,6M等)
2、2種優(yōu)勢(shì)
-
那些刪除或者update變大而產(chǎn)生的磁盤(pán)碎片空間(尺寸變大,意味著開(kāi)辟新空間存儲(chǔ)此document,舊的空間被mark為deleted)可以被其他insert重用
-
再者padding可以允許文檔尺寸有限度的增長(zhǎng),而無(wú)需每次update變大都重新分配空間。
3、mongodb還提供了一個(gè)可選的“No padding Allocation”策略(即按照實(shí)際數(shù)據(jù)尺寸分配空間),如果你確信數(shù)據(jù)絕大多數(shù)情況下都是insert、in-place update,極少的delete,此策略將可以有效的節(jié)約磁盤(pán)空間,看起來(lái)數(shù)據(jù)更加緊湊,磁盤(pán)利用率也更高
備注:mongodb 3.2+之后,默認(rèn)的存儲(chǔ)引擎為“wiredTiger”,大量?jī)?yōu)化了存儲(chǔ)性能,建議升級(jí)到3.2+版本
Capped Collections
1、尺寸大小是固定值 類似于一個(gè)可循環(huán)使用的buffer
如果空間被填滿之后,新的插入將會(huì)覆蓋最舊的文檔,通常不會(huì)對(duì)Capped進(jìn)行刪除或者update操作,所以這種類型的collection能夠支撐較高的write和read
2、不需要對(duì)這種collection構(gòu)建索引,因?yàn)閕nsert是append(insert的數(shù)據(jù)保存是嚴(yán)格有序的)、read是iterator方式,幾乎沒(méi)有隨機(jī)讀
3、在replica set模式下,其oplog就是使用這種colleciton實(shí)現(xiàn)的
4、Capped Collection的設(shè)計(jì)目的就是用來(lái)保存“最近的”一定尺寸的document
db.createCollection("capped_collections",
new?CreateCollectionOptions()??
.capped(true)??
.maxDocuments(6552350)??
.usePowerOf2Sizes(false).autoIndex(true));//不會(huì)涉及到更新,所以可以不用power?of?2??5、類似于“FIFO”隊(duì)列,而且是有界隊(duì)列 適用于數(shù)據(jù)緩存,消息類型的存儲(chǔ)
6、Capped支持update,但是我們通常不建議,如果更新導(dǎo)致document的尺寸變大,操作將會(huì)失敗,只能使用in-place update,而且還需要建立合適的索引
7、在capped中使用remove操作是允許的
8、autoIndex屬性表示默認(rèn)對(duì)_id字段建立索引
數(shù)據(jù)模型(Data Model)
1、mongodb支持內(nèi)嵌document 即document中一個(gè)字段的值也是一個(gè)document
2、如果內(nèi)嵌文檔(即reference文檔)尺寸是動(dòng)態(tài)的,比如一個(gè)user可以有多個(gè)card,因?yàn)閏ard數(shù)量無(wú)法預(yù)估,這就會(huì)導(dǎo)致document的尺寸可能不斷增加以至于超過(guò)“Power of 2 Allocate”,從而觸發(fā)空間重新分配,帶來(lái)性能開(kāi)銷
3、這種情況下,我們需要將內(nèi)嵌文檔單獨(dú)保存到一個(gè)額外的collection中,作為一個(gè)或者多個(gè)document存儲(chǔ),比如把card列表保存在card collection中
4、如果reference文檔尺寸較小,可以內(nèi)嵌,如果尺寸較大,建議單獨(dú)存儲(chǔ)。此外內(nèi)嵌文檔還有個(gè)優(yōu)點(diǎn)就是write的原子性
索引
1、提高查詢性能,默認(rèn)情況下_id字段會(huì)被創(chuàng)建唯一索引;
2、因?yàn)樗饕粌H需要占用大量?jī)?nèi)存而且也會(huì)占用磁盤(pán),所以我們需要建立有限個(gè)索引,而且最好不要建立重復(fù)索引;
3、每個(gè)索引需要8KB的空間,同時(shí)update、insert操作會(huì)導(dǎo)致索引的調(diào)整,
會(huì)稍微影響write的性能,索引只能使read操作收益,
所以讀寫(xiě)比高的應(yīng)用可以考慮建立索引
大集合拆分
比如一個(gè)用于存儲(chǔ)log的collection,
log分為有兩種“dev”、“debug”,結(jié)果大致為
{"log":"dev","content":"...."},{"log":"debug","content":"....."}。
這兩種日志的document個(gè)數(shù)比較接近,
對(duì)于查詢時(shí),即使給log字段建立索引,這個(gè)索引也不是高效的,
所以可以考慮將它們分別放在2個(gè)Collection中,比如:log_dev和log_debug。數(shù)據(jù)生命周期管理
mongodb提供了expire機(jī)制,
即可以指定文檔保存的時(shí)長(zhǎng),過(guò)期后自動(dòng)刪除,即TTL特性,
這個(gè)特性在很多場(chǎng)合將是非常有用的,
比如“驗(yàn)證碼保留15分鐘有效期”、“消息保存7天”等等,
mongodb會(huì)啟動(dòng)一個(gè)后臺(tái)線程來(lái)刪除那些過(guò)期的document
需要對(duì)一個(gè)日期字段創(chuàng)建“TTL索引”,
比如插入一個(gè)文檔:{"check_code":"101010",$currentDate:{"created":true}}},
其中created字段默認(rèn)值為系統(tǒng)時(shí)間Date;然后我們對(duì)created字段建立TTL索引:
collection.createIndex(new?Document("created",1),new?IndexOptions().expireAfter(15L,TimeUnit.MILLISECONDS));//15分鐘??
向collection中insert文檔時(shí),created的時(shí)間為系統(tǒng)當(dāng)前時(shí)間,
其中在creatd字段上建立了“TTL”索引,索引TTL為15分鐘,
mongodb后臺(tái)線程將會(huì)掃描并檢測(cè)每條document的(created時(shí)間?+?15分鐘)與當(dāng)前時(shí)間比較,
如果發(fā)現(xiàn)過(guò)期,則刪除索引條目(連帶刪除document)。
某些情況下,可能需要實(shí)現(xiàn)“在某個(gè)指定的時(shí)刻過(guò)期”,
只需要將上述文檔和索引變通改造即可,
即created指定為“目標(biāo)時(shí)間”,expiredAfter指定為0。?架構(gòu)模式
Replica set 復(fù)制集
通常是三個(gè)對(duì)等的節(jié)點(diǎn)構(gòu)成一個(gè)“復(fù)制集”集群,
有“primary”和secondary等多種角色
其中primary負(fù)責(zé)讀寫(xiě)請(qǐng)求,secondary可以負(fù)責(zé)讀請(qǐng)求,這又配置決定,
其中secondary緊跟primary并應(yīng)用write操作;
如果primay失效,則集群進(jìn)行“多數(shù)派”選舉,選舉出新的primary,即failover機(jī)制,即HA架構(gòu)。
復(fù)制集解決了單點(diǎn)故障問(wèn)題,也是mongodb垂直擴(kuò)展的最小部署單位,
當(dāng)然sharding?cluster中每個(gè)shard節(jié)點(diǎn)也可以使用Replica?set提高數(shù)據(jù)可用性。Sharding cluster 分片集群
數(shù)據(jù)水平擴(kuò)展的手段之一;
replica?set這種架構(gòu)的缺點(diǎn)就是“集群數(shù)據(jù)容量”受限于單個(gè)節(jié)點(diǎn)的磁盤(pán)大小,
如果數(shù)據(jù)量不斷增加,對(duì)它進(jìn)行擴(kuò)容將時(shí)非??嚯y的事情,所以我們需要采用Sharding模式來(lái)解決這個(gè)問(wèn)題。
將整個(gè)collection的數(shù)據(jù)將根據(jù)sharding?key被sharding到多個(gè)mongod節(jié)點(diǎn)上,
即每個(gè)節(jié)點(diǎn)持有collection的一部分?jǐn)?shù)據(jù),這個(gè)集群持有全部數(shù)據(jù),
原則上sharding可以支撐數(shù)TB的數(shù)據(jù)。系統(tǒng)配置
-
建議mongodb部署在linux系統(tǒng)上,較高版本,選擇合適的底層文件系統(tǒng)(ext4),開(kāi)啟合適的swap空間
-
無(wú)論是MMAPV1或者wiredTiger引擎,較大的內(nèi)存總能帶來(lái)直接收益
-
對(duì)數(shù)據(jù)存儲(chǔ)文件關(guān)閉“atime”(文件每次access都會(huì)更改這個(gè)時(shí)間值,表示文件最近被訪問(wèn)的時(shí)間),可以提升文件訪問(wèn)效率
-
ulimit參數(shù)調(diào)整,這個(gè)在基于網(wǎng)絡(luò)IO或者磁盤(pán)IO操作的應(yīng)用中,通常都會(huì)調(diào)整,上調(diào)系統(tǒng)允許打開(kāi)的文件個(gè)數(shù)(ulimit -n 65535)。
數(shù)據(jù)文件存儲(chǔ)原理(Data Files storage,MMAPV1引擎)
?mongodb的數(shù)據(jù)將會(huì)保存在底層文件系統(tǒng)中,
?比如我們dbpath設(shè)定為“/data/db”目錄,
?我們創(chuàng)建一個(gè)database為“test”,collection為“sample”,
?然后在此collection中插入數(shù)條documents。我們查看dbpath下生成的文件列表:
可以看到test這個(gè)數(shù)據(jù)庫(kù)目前已經(jīng)有6個(gè)數(shù)據(jù)文件(data?files),
每個(gè)文件以“database”的名字?+?序列數(shù)字組成,
序列號(hào)從0開(kāi)始,逐個(gè)遞增,數(shù)據(jù)文件從16M開(kāi)始,每次擴(kuò)張一倍(16M、32M、64M、128M...),
在默認(rèn)情況下單個(gè)data?file的最大尺寸為2G,
如果設(shè)置了smallFiles屬性(配置文件中)則最大限定為512M;
mongodb中每個(gè)database最多支持16000個(gè)數(shù)據(jù)文件,即約32T,
如果設(shè)置了smallFiles則單個(gè)database的最大數(shù)據(jù)量為8T。
如果你的database中的數(shù)據(jù)文件很多,
可以使用directoryPerDB配置項(xiàng)將每個(gè)db的數(shù)據(jù)文件放置在各自的目錄中。
當(dāng)最后一個(gè)data?file有數(shù)據(jù)寫(xiě)入后,
mongodb將會(huì)立即預(yù)分配下一個(gè)data?file,
可以通過(guò)“--nopreallocate”啟動(dòng)命令參數(shù)來(lái)關(guān)閉此選項(xiàng)參考文檔
https://blog.csdn.net/quanmaoluo5461/article/details/85164588