您好,登錄后才能下訂單哦!
一.命名規則
1.mongodb版本選擇:
默認新裝數據庫使用MongoDB 3.X 社區版。建議3.2.10+
2.數據庫設計規范
數據庫名可以是滿足以下條件的任意UTF-8字符串:
(1)不能出現除“_”字符以外的特殊字符;
(2)不能含有”(空格)、.、$、/、、和(空字符);
(3)應全部小寫;
(4)最多30字符。
(5)禁止使用數字打頭的庫名
3.集合命名規則
必須滿足下列條件的任意UTF-8字符串
(1)集合名不能是空字符串“”; 不能出現除“_”字符以外的特殊字符,禁止使用數字開頭的名稱;
(2)集合名不能以“system.”開頭,這是為系統集合保留的前綴。例如system.users這個集合保存著數據庫的用戶信息,system.namespaces集合保存著所有數據庫集合的信息;
(3)用戶創建的集合名字不能含有保留字符$。除非你要訪問系統創建的集合,否則不可在名字里出現$;
(4)集合名應簡潔明了,盡量都使用小寫;
4.字段命名規范
(1)字段不能含有(空字符)。
(2)禁止使用數字開頭的字段名;
(3)不可以“”開頭命名字段名稱,不能出現除“”字符以外的特殊字符;
(4)字段引用必須采用集合名+被引用字段名稱。例如集合user的鍵id在集合user_info中被引用,用user_id作為鍵名;
(5)只有在遇到引用情況下,字段中包含的集合名首字母需要大寫,其他一律小寫格式。
(6)如果字段較大,應盡量壓縮存放
(7)如果字段較大且會成為查詢條件,例如一長串的url,可以轉成md5后存放
(8)禁止自定義_id的值。
二:數據庫設計規范
1.
(1) 合理容量規劃和庫級拆分
創建新的數據庫時,提前進行容量規劃庫的集合數,存儲容量,QPS等, 是放在已有集群,還是新創 建集群部署。
(2) 避免把所有集合都放在同一個數據庫,造成一個庫中集合過多;
(3) 業務禁止使用id字段;
業務避免向id字段寫入自定義的業務數據:因MongoDB的 Jd字段默認是主鍵, 類似于MySQL InnoDB表的主鍵,如果業務寫入無序數據(如uuid/md5),集合本身是B+ Tree,為保證樹的平衡,會大副度調整內部存儲數據結構;寫入數據的代價很大,容易導致寫入性能低;
(4) MongoDB數據是大小寫敏感的,如業務不區分大小,建議冗余一個全部大寫或小寫字段,用于不區分大小寫的數據檢索效率*
mongo中數據查詢是大小寫敏感的,例如{f,"aA"}的查詢條件, 不能匹配字段為“aa”,“AA", “Aa” 值的文檔。有的業務需忽略大小,需通過正則方式進行處理{f:aa/},雖實現忽略大小功能,但查詢效率很低,同時很耗CPU資源。 解決這類需求,希望冗余一個全大寫(或小寫)的字段,用于業務忽略大小的檢索需求。例如對f字段冗余tupper字 段,存儲字段內容全大寫{f_upper."AA'}
(5) 對高頻大字段進行壓縮存儲:
很多高頻的查詢,如果存在返回較大字段數據(如10 KB以上),當QPS增加后很容易把MongoDB服務器網絡帶寬占滿。
或寫入頻次較高,會導數oplog實體很大。建議這類高頻和較大的數據, 在業務層進行 壓縮后,再存入MongoDB中。
(6)ObjectId存儲時,作為ObjectId存儲,不可存成字符串類型;
原因:第一,方便查詢(字符串和ObjectId不能相互匹配)第二,ObjectId 含有有用的信息,如從插入的時間戳可以得知創建日期;第三,字符串表示的ObjectId要多占用兩倍的磁盤空間;
2.索引設計規范
(1)MongoDB的索引僅支持1K以內的字段,如果你存入的數據長度超過1K,那么它將無法被索引
(2)索引名稱長度不要過長;命名方式:idx_字段名 ;組合索引建議包含所有字段名,過長的字段名可以采用縮寫形式。
(3)唯一索引命名規范:uniq_字段名稱
(3)應盡量綜合評估查詢場景,通過評估盡可能的將單列索引并入組合索引以降低所以數量;
(4)索引越多,插入或修改記錄就會導致 mongodb 越慢。
(5)創建索引要在后臺創建,避免阻塞業務正常DML和查詢。db.works.createIndex({a:1,b:1},{"name":'idx_字段名'},{background:true})
(6)禁止在數組字段上創建索引;
(7)在創建組合索引的時候,應評估索引中包含的字段,盡量將選擇性高(唯一值多的數據)的字段放在組合索引的前面;
(8)在開發業務的時候盡量檢查自己的程序性能,多使用explain()查看執行計劃;
(9)禁止冗余索引。 例如索引idx_account_sName_createTime {"account" : 1,"sName" : 1,"createTime" : -1}和索引idx_account {"account" : 1} 索引冗余,可刪除idx_account索引。
3.查詢規范
(1)查詢語句是否使用到索引,在查詢條件的鍵上,或者排序條件的鍵上必須有索引(數據量較小的集合除外);
(2)使用limit()限定返回結果集的大小,減少數據庫服務器的資源消耗,以及網絡傳輸的數據量。
(3)只查詢使用到的字段,而不查詢所有字段;盡量不要讓數組字段成為查詢條件
(4)執行remove()刪除操作,未帶查詢條件,警告或報錯;
(5)查詢中的某些$操作符可能會導致性能低下,如 $ne,$not,$exists,$nin,$or,$where盡量在業務中不要使用
(6)MongoDB 的組合索引使用策略 遵循"最左原則",優先使用覆蓋索引,查詢語句遵守復合索引字段順序
(7)必要時使用hint()強制使用某個索引查詢
(8)更新操作時,先查詢后更新,通過主鍵key更新,可以提高更新效率;
###應用程序連接配置
合理設置讀寫分離,減少主節點壓力,提高可集群可擴展性
(1)mongo客戶端通過只讀偏好(read -preference)屬性設置,決定客戶端只讀查詢的路由規則。
(2)mongo客戶端默認所有查詢都路由到主節點查詢,而很多應用程序只讀業務一-致性不高 (接受秒級別的同步延時), 可把只讀查詢路由到從節點。MongoDB正常 復制同步延時在1秒內。
(3)如果業務只讀查詢,對數據- -致性要求不高(比如最壞情況按受60秒延時).建議程序drver的[只讀偏好]屬性設置為 secondaryPreferred.
mongo客戶端[只讀偏好]支持5種模式:
Read Preference Mode | Description |
---|---|
primary | 默認模式,客戶端所有只讀命令都發向主節點 |
primaryPreferred | 只讀查詢默認發給主節點,當主節點不可用時,轉發給從節點 |
secondary | 所有的只讀查詢發向從節點 |
secondaryPreferred | 所有只讀查詢發向從節點,如果所有從節點不可用時,轉發給主節點 |
nearest | 只讀查詢發給最近可用數據節點,不考慮節點的角色 |
1.分片鍵的幾個原則:
分片鍵是不可變。
分片鍵必須是索引。
分片鍵大小限制512bytes。
分片鍵用于路由查詢。
MongoDB不接受已進行collection級分片的collection上插入無分片鍵的文檔。
好的 shard key 應該擁有如下特性:
1.key 分布足夠離散 (sufficient cardinality)
2.寫請求均勻分布 (evenly distributed write)
3.盡量避免 scatter-gather 查詢 (targeted read)
MongoDB的內部機制保證了每個副本集(RS)包含了同樣數量的塊。
片鍵的選擇決定了三個重要的方面:
#####1. 讀和寫的分布
其中最重要的一點是讀和寫的分布。如果你總是朝一臺機器寫,那么這臺機器將會成為寫瓶頸,則你的集群的寫性能將會降低。這無關乎你的集群有多少個節點,因為所有的寫操作都只在一個地方進行。因此,你不應該使用單調遞增的_id
或時間戳作為片鍵,這樣將會導致你一直往最后一個副本集中添加數據。
相類似的是如果你的讀操作一直都在同一個副本集上,那么你最好祈求你的任務能在機器內存所能承受的范圍之內。通過副本集將讀請求劃分開能夠使你的工作數據集大小隨著分片數線性擴展。這樣的話你能夠將負載壓力均分到各臺機器的內存和磁盤之上。
其次是數據塊的大小。MongoDB能夠將大的數據塊劃分成更小的,但這種情況僅僅在片鍵不同的情況下發生。如果你有巨量的數據文檔都使用了同樣的片鍵,那么你相應的會得到巨大的數據塊。出現巨大塊是非常不好的,不僅僅因為它會導致數據的不平均分布,還因為一旦這個數據塊的大小超過某個值,那么你就不能夠在分片之間移動它了。
最后一點,如果能夠保證大部分的查詢請求都能夠命中盡可能少的分片那就最好了。對于一個查詢請求來說,其延遲直接取決于最慢的那個命中服務器的延遲;所以你命中的分片越少,那么理論上來說查詢將會越快。這一點并不是硬性的規定,不過如果能夠做到充分考慮那么應該是很有利的。因為數據塊在分片上的分布僅僅是近似的遵循片鍵的順序,而并不是嚴格的強制指定。
讀和寫都能夠平均分布,并且它能夠保證每個文檔都有不同的片鍵所以數據塊能夠很精細。
對多個文檔的查詢必將命中所有的分片。
數據文件挪動小(優勢)
因為數據文件遞增,所以會把insert的寫IO永久放在最后一片上,造成最后一片的寫熱點。同時,隨著最后一片的數據量增大,將不斷的發生遷移至之前的片上。
數據分布均勻,insert的寫IO均勻分布在多個片上。(優勢)
對多個文檔的查詢必將命中所有的分片;大量的隨機IO,磁盤不堪重荷。
為防止巨大塊的產生,建議使用組合鍵,引入_id來細化。{keyname: 1, _id: 1}
原則就是:keyname可以是一個經常被查詢的字段,盡可能基數較大;_id字段是有非常多不同的值可以供mongodb進行分割,這種策略適合大多業務情況;如果實在找不到keyname這樣字段,那么就對_id進行Hashed吧。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。