百度新疆網(wǎng)站建設(shè)西安網(wǎng)
前言
MongoDB是非關(guān)系型數(shù)據(jù)庫(kù)的典型代表,DB-Engines Ranking 數(shù)據(jù)顯示,近年來(lái),MongoDB在 NoSQL領(lǐng)域一直獨(dú)占鰲頭。MongoDB是為快速開發(fā)互聯(lián)網(wǎng)應(yīng)用 而設(shè)計(jì)的數(shù)據(jù)庫(kù)系統(tǒng),其數(shù)據(jù)模型和持 久化策略就是為了構(gòu)建高讀/寫的性能,并且可以方面的彈性拓展。隨著MongoDB的普及和使用量的快 速增長(zhǎng),為了規(guī)范使用,便于管理和獲取更高的性能,整理此文檔。我們從 數(shù)據(jù)庫(kù)設(shè)計(jì)規(guī)范、集合設(shè)計(jì) 規(guī)范、索引設(shè)計(jì)規(guī)范、文檔設(shè)計(jì)規(guī)范、API使用規(guī)范、連接規(guī)范等方面進(jìn)行闡述和要求。
存儲(chǔ)選型
-
主要解決大量數(shù)據(jù)的訪問(wèn)效率問(wèn)題, 減少mysql 壓力。MongoDB內(nèi)建了多種數(shù)據(jù)分片的特性,可 以很好的適應(yīng)大數(shù)據(jù)量的需求。內(nèi)建的Sharding分片特性避免系統(tǒng)在數(shù)據(jù)增長(zhǎng)的過(guò)程中遇到性能瓶頸。
-
復(fù)雜數(shù)據(jù)結(jié)構(gòu),以多種不同查詢條件去查詢同一份數(shù)據(jù)。MongoDB的BSON數(shù)據(jù)格式非常適合文 檔化格式的存儲(chǔ)及查詢;支持豐富的查詢表達(dá)式,可輕易查詢文檔中內(nèi)嵌的對(duì)象和數(shù)組及子文檔。
-
非事務(wù)并且關(guān)聯(lián)性集合不強(qiáng)的都可以使用(MongoDB4.0+支持跨Collection事務(wù),MongoDB4.2+支持跨Shard事務(wù))。
-
無(wú)多文檔事務(wù)性需求及復(fù)雜關(guān)聯(lián)檢索。
-
業(yè)務(wù)快速迭代,需求頻繁變動(dòng)業(yè)務(wù)。
-
數(shù)據(jù)模型不固定,存儲(chǔ)格式靈活場(chǎng)景。
-
單集群讀寫并發(fā)過(guò)大無(wú)法支撐業(yè)務(wù)增長(zhǎng)。
-
期望 5 個(gè) 9 的數(shù)據(jù)庫(kù)高可用場(chǎng)景。
一、庫(kù)設(shè)計(jì)規(guī)范
-
【強(qiáng)制】數(shù)據(jù)庫(kù)命名規(guī)范:db_xxxx
-
【強(qiáng)制】庫(kù)名全部小寫,禁止使用任何_以外的特殊字符,禁止使用數(shù)字打頭的庫(kù)名,如:123_abc;
說(shuō)明:庫(kù)以文件夾的形式存在,使用特殊字符或其它不規(guī)范的命名方式會(huì)導(dǎo)致命名混亂
3. 【強(qiáng)制】數(shù)據(jù)庫(kù)名稱最多為 64 個(gè)字符。
- 【強(qiáng)制】在創(chuàng)建新的庫(kù)前應(yīng)盡量評(píng)估該庫(kù)的體積、QPS等,提前與DBA討論是應(yīng)該新建一個(gè)庫(kù)還是專門為該庫(kù)創(chuàng)建一個(gè)新的集群。
二、集合設(shè)計(jì)規(guī)范
1.【強(qiáng)制】集合名全部小寫,禁止使用任何_以外的特殊字符,禁止使用數(shù)字打頭的集合名,如:123_abc,禁止system打頭; system是系統(tǒng)集合前綴;
2.【強(qiáng)制】集合名稱最多為64字符;
3.【建議】一個(gè)庫(kù)中寫入較大的集合會(huì)影響其它集合的讀寫性能,如果業(yè)務(wù)比較繁忙的集合在一個(gè)DB中,建議最多80個(gè)集合,同時(shí)也要考慮磁盤I/O的性能;
4.【建議】如果評(píng)估單集合數(shù)據(jù)量較大,可以將一個(gè)大表拆分為多個(gè)小表,然后將每一個(gè)小表存放在獨(dú)立的庫(kù)中或者sharding分表;
5.【建議】MongoDB的集合擁有”自動(dòng)清理過(guò)期數(shù)據(jù)”的功能,只需在該集合中文檔的時(shí)間字段增加一個(gè)TTL索引即可實(shí)現(xiàn)該功能,但需要注意的是該字段的類型則必須是mongoDate(),一定要結(jié)合實(shí)際業(yè)務(wù)設(shè)計(jì)是否需要;
6.【建議】設(shè)計(jì)輪詢集合—集合是否設(shè)計(jì)為Capped限制集,一定要結(jié)合實(shí)際業(yè)務(wù)設(shè)計(jì)是否需要。
創(chuàng)建集合規(guī)則
不同的業(yè)務(wù)場(chǎng)景是可以使用不同的配置;
db.createCollection(“l(fā)ogs”,
{ “storageEngine”: { “wiredTiger”:
{ “configString”: “internal_page_max=16KB,
leaf_page_max=16KB,leaf_value_max=8KB,os_cache_max=1GB”} }
})
a. 如果是讀多寫少的表在創(chuàng)建時(shí)我們可以盡量將 page size 設(shè)置的比較小 ,比如 16KB,如果表數(shù)據(jù)量不大 (“internal_page_max=16KB,leaf_page_max=16KB,leaf_value_max=8KB,os_cache_max=1GB”)
b. 如果這個(gè)讀多寫少的表數(shù)據(jù)量比較大,可以為其設(shè)置一個(gè)壓縮算法,例如:”block_compressor=zlib, internal_page_max=16KB,leaf_page_max=16KB,leaf_value_max=8KB”
c. 注意:該zlib壓縮算法不要使用,對(duì)cpu消耗特別大,如果使用snapp消耗20% cpu,而且使用zlib能消耗90%cpu,甚至100%
d. 如果是寫多讀少的表,可以將 leaf_page_max 設(shè)置到 1MB,并開啟壓縮算法,也可以為其制定操作系統(tǒng)層面 page cache 大小的 os_cache_max 值,讓它不會(huì)占用太多的 page cache 內(nèi)存,防止影響讀操作
讀多寫少的表 internal_page_max=16KB 默認(rèn)為4KB leaf_page_max=16KB 默認(rèn)為32KB leaf_value_max=8KB 默認(rèn)為64MB os_cache_max=1GB 默認(rèn)為0 讀多寫少的表 而且數(shù)據(jù)量比較大 block_compressor=zlib 默認(rèn)為snappy internal_page_max=16KB 默認(rèn)為4KB leaf_page_max=16KB 默認(rèn)為32KB leaf_value_max=8KB 默認(rèn)為64M
三、文檔設(shè)計(jì)規(guī)范
1.【強(qiáng)制】集合中的 key 禁止使用任何 “_”(下劃線)以外的特殊字符。
2.【強(qiáng)制】盡量將同樣類型的文檔存放在一個(gè)集合中,將不同類型的文檔分散在不同的集合中;相同類型的文檔能夠大幅度提高索引利用率,如果文檔混雜存放則可能會(huì)出現(xiàn)查詢經(jīng)常需要全表掃描的情況;
3.【建議】禁止使用_id,如:向_id中寫入自定義內(nèi)容;
說(shuō)明:MongoDB的表與InnoDB相似,都是索引組織表,數(shù)據(jù)內(nèi)容跟在主鍵后,而_id是MongoDB中的默認(rèn)主鍵,一旦_id的值為非自增,當(dāng)數(shù)據(jù)量達(dá)到一定程度之后,每一次寫入都可能導(dǎo)致主鍵的二叉樹大幅度調(diào)整,這將是一個(gè)代價(jià)極大的寫入, 所以寫入就會(huì)隨著數(shù)據(jù)量的增大而下降,所以一定不要在_id中寫入自定義的內(nèi)容。
4.【建議】盡量不要讓數(shù)組字段成為查詢條件;
5.【建議】如果字段較大,應(yīng)盡量壓縮存放;
不要存放太長(zhǎng)的字符串,如果這個(gè)字段為查詢條件,那么確保該字段的值不超過(guò)1KB;MongoDB的索引僅支持1K以內(nèi)的字段,如果你存入的數(shù)據(jù)長(zhǎng)度超過(guò)1K,那么它將無(wú)法被索引
6.【建議】盡量存放統(tǒng)一了大小寫后的數(shù)據(jù) ;
7.【建議】如果評(píng)估單集合數(shù)據(jù)量較大,可以將一個(gè)大表拆分為多個(gè)小表,然后將每一個(gè)小表存放在獨(dú)立的庫(kù)中或者sharding分表。
四、索引設(shè)計(jì)規(guī)范
1.【強(qiáng)制】MongoDB 的組合索引使用策略與 MySQL 一致,遵循”最左原則”;
2.【強(qiáng)制】索引名稱長(zhǎng)度不要超過(guò) 128 字符;
3.【強(qiáng)制】應(yīng)盡量綜合評(píng)估查詢場(chǎng)景,通過(guò)評(píng)估盡可能的將單列索引并入組合索引以降低所以數(shù)量,結(jié)合1,2點(diǎn);
4.【建議】?jī)?yōu)先使用覆蓋索引;
5.【建議】創(chuàng)建組合索引的時(shí)候,應(yīng)評(píng)估索引中包含的字段,盡量將數(shù)據(jù)基數(shù)大(唯一值多的數(shù)據(jù))的字段放在組合索引的前面;
6.【建議】MongoDB 支持 TTL 索引,該索引能夠按你的需要自動(dòng)刪除XXX秒之前的數(shù)據(jù)并會(huì)盡量選擇在業(yè)務(wù)低峰期執(zhí)行刪除操作;看業(yè)務(wù)是否需要這一類型索引;
7.【建議】在數(shù)據(jù)量較大的時(shí)候,MongoDB 索引的創(chuàng)建是一個(gè)緩慢的過(guò)程,所以應(yīng)當(dāng)在上線前或數(shù)據(jù)量變得很大前盡量評(píng)估,按需創(chuàng)建會(huì)用到的索引;
8.【建議】如果你存放的數(shù)據(jù)是地理位置信息,比如:經(jīng)緯度數(shù)據(jù)。那么可以在該字段上添加 MongoDB 支持的地理索引:2d 及 2dsphere,但他們是不同的,混用會(huì)導(dǎo)致結(jié)果不準(zhǔn)確。
五、API使用規(guī)范
1.【強(qiáng)制】在查詢條件的字段或者排序條件的字段上必須創(chuàng)建索引;
2.【強(qiáng)制】查詢結(jié)果只包含需要的字段,而不查詢所有字段;
3.【強(qiáng)制】在文檔級(jí)別更新是原子性的,這意味著一條更新 10 個(gè)文檔的語(yǔ)句可能在更新 3 個(gè)文檔后由于某些原因失敗。應(yīng)用程序必須根據(jù)自己的策略來(lái)處理這些失敗;
4.【建議】單個(gè)文檔的BSON size不能超過(guò)16M;
5.【建議】禁用不帶條件的update、remove或者find語(yǔ)句;
6.【建議】限定返回記錄條數(shù),每次查詢結(jié)果不超過(guò) 2000 條。如果需要查詢 2000 條以上的數(shù)據(jù),在代碼中使用多線程并發(fā)查詢;
7.【建議】在寫入數(shù)據(jù)的時(shí)候,如果你需要實(shí)現(xiàn)類似 MySQL 中 INSERT INTO ON DUPLICATE KEY UPDATE 的功能,那么可以選擇 upsert() 函數(shù);
8.【建議】寫入大量數(shù)據(jù)的時(shí)候可以選擇使用 batchInsert,但目前 MongoDB 每一次能夠接受的最大消息長(zhǎng)度為48MB,如果超出48MB,將會(huì)被自動(dòng)拆分為多個(gè)48MB的消息;
9.【建議】索引中的-1和1是不一樣的,一個(gè)是逆序,一個(gè)是正序,應(yīng)當(dāng)根據(jù)自己的業(yè)務(wù)場(chǎng)景建立適合的索引排序,需要注意的是{a:1,b:-1} 和 {a:-1,b:1}是一樣的;
10.【建議】在開發(fā)業(yè)務(wù)的時(shí)候盡量檢查自己的程序性能,可以使用 explain() 函數(shù)檢查你的查詢執(zhí)行詳情,另外 hint() 函數(shù)相當(dāng)于 MySQL 中的 force index();
11.【建議】如果你結(jié)合體積大小/文檔數(shù)固定,那么建議創(chuàng)建 capped(封頂)集合,這種集合的寫入性能非常高并無(wú)需專門清理老舊數(shù)據(jù),需要注意的是 capped 表不支持remove() 和 update()操作;
12.【建議】查詢中的某些操作符可能會(huì)導(dǎo)致性能低下,如ne,not,exists,nin,or,盡量在業(yè)務(wù)中不要使用;
exist:因?yàn)樗缮⒌奈臋n結(jié)構(gòu)導(dǎo)致查詢必須遍歷每一個(gè)文檔
ne:如果當(dāng)取反的值為大多數(shù),則會(huì)掃描整個(gè)索引
not:可能會(huì)導(dǎo)致查詢優(yōu)化器不知道應(yīng)當(dāng)使用哪個(gè)索引,所以會(huì)經(jīng)常退化為全表掃描
nin:全表掃描
or:有多少個(gè)條件就會(huì)查詢多少次,最后合并結(jié)果集,所以盡可能的使用in
13.【建議】不要一次取出太多的數(shù)據(jù)進(jìn)行排序,MongoDB 目前支持對(duì)32MB以內(nèi)的結(jié)果集進(jìn)行排序,如果需要排序,那么請(qǐng)盡量限制結(jié)果集中的數(shù)據(jù)量;
14.【建議】MongoDB 的聚合框架非常好用,能夠通過(guò)簡(jiǎn)單的語(yǔ)法實(shí)現(xiàn)復(fù)雜的統(tǒng)計(jì)查詢,并且性能也不錯(cuò);
15.【建議】如果需要清理掉一個(gè)集合中的所有數(shù)據(jù),那么 remove() 的性能是非常低下的,該場(chǎng)景下應(yīng)當(dāng)使用 drop();remove() 是逐行操作,所以在刪除大量數(shù)據(jù)的時(shí)候性能很差;
16.【建議】在使用數(shù)組字段做為查詢條件的時(shí)候,將與覆蓋索引無(wú)緣;這是因?yàn)閿?shù)組是保存在索引中的,即便將數(shù)組字段從需要返回的字段中剔除,這樣的索引仍然無(wú)法覆蓋查詢;
17.【建議】在查詢中如果有范圍條件,那么盡量和定值條件放在一起進(jìn)行過(guò)濾,并在創(chuàng)建索引的時(shí)候?qū)⒍ㄖ挡樵冏侄畏旁诜秶樵冏侄吻啊?/p>
六、連接規(guī)范
1.【強(qiáng)制】正確連接副本集,副本集提供了數(shù)據(jù)的保護(hù)、高可用和災(zāi)難恢復(fù)的機(jī)制。如果主節(jié)點(diǎn)宕 機(jī),其中一個(gè)從節(jié)點(diǎn)會(huì)自動(dòng)提升為從節(jié)點(diǎn)。
2.【建議】合理控制連接池的大小,限制連接數(shù)資源,可通過(guò)Connection String URL中的 maxPoolSize 參數(shù)來(lái)配置連接池大小。
3.【建議】復(fù)制集讀選項(xiàng) 默認(rèn)情況下,復(fù)制集的所有讀請(qǐng)求都發(fā)到Primary,Driver可通過(guò)設(shè)置的Read Preference 來(lái)將 讀請(qǐng)求路由到其他的節(jié)點(diǎn)。