本文探討了如何合理設置MongoDB片鍵以發揮分片機制的優勢,作者為Bugsnag.com的工程師Conrad Irwin。Bugsnag為移動應用開發者提供實時的Bug追蹤及檢測服務,Bugsnag使用MongoDB存儲超過TB級的文檔數據。 簡而言之,使用{_id: ‘hashed’}或{projectId: 1, _i
本文探討了如何合理設置MongoDB片鍵以發揮分片機制的優勢,作者為Bugsnag.com的工程師Conrad Irwin。Bugsnag為移動應用開發者提供實時的Bug追蹤及檢測服務,Bugsnag使用MongoDB存儲超過TB級的文檔數據。
簡而言之,使用{_id: ‘hashed’}或{projectId: 1, _id: 1}來作為片鍵。
幾個月前,我們對MongoDB集群進行分片(shard)處理,數據設置了兩個副本集合(replica set)。上周,我們添加了一個新的分片。首次分片花了一些功夫,不過我們仍然在沒有停機的情況下完成了這個工作,如今添加一個新的分片是很輕而易舉的事情。
MongoDB的分片機制能夠幫助你將你的數據庫劃分到多個服務器,通常在生產環境中可以將數據集劃分到多個副本集中。但分片最好在數據庫建立早期劃分,因為一旦你的數據大于512GB那么分片劃分就不是那么容易了。這受到MongoDB縱向擴展能力的限制。
為了實現分片,你必須向MongoDB指定使用哪個索引作為片鍵,然后MongoDB會根據你的設置將你的數據劃分到有著相同片鍵的數據塊(Chunk)中。而后這些數據塊將根據片鍵的大致順序分散到副本集中。
正如你所見,分片之后數據的存放位置依賴于片鍵,所以合理的選擇片鍵十分重要。
MongoDB的內部機制保證了每個副本集(RS)包含了同樣數量的塊,在上圖中一個RS包含兩個塊,而在Bugsnag.com的集群中,每個RS包含6300個塊。但這幾乎是唯一的保證機制了。
片鍵的選擇決定了三個重要的方面:
其中最重要的一點是讀和寫的分布。如果你總是朝一臺機器寫,那么這臺機器將會成為寫瓶頸,則你的集群的寫性能將會降低。這無關乎你的集群有多少個節點,因為所有的寫操作都只在一個地方進行。因此,你不應該使用單調遞增的`_id`或時間戳作為片鍵,這樣將會導致你一直往最后一個副本集中添加數據。
相類似的是如果你的讀操作一直都在同一個副本集上,那么你最好祈求你的任務能在機器內存所能承受的范圍之內。通過副本集將讀請求劃分開能夠使你的工作數據集大小隨著分片數線性擴展。這樣的話你能夠將負載壓力均分到各臺機器的內存和磁盤之上。
其次是數據塊的大小。MongoDB能夠將大的數據塊劃分成更小的,但這種情況僅僅在片鍵不同的情況下發生。如果你有巨量的數據文檔都使用了同樣的片鍵,那么你相應的會得到巨大的數據塊。出現巨大塊是非常不好的,不僅僅因為它會導致數據的不平均分布,還因為一旦這個數據塊的大小超過某個值,那么你就不能夠在分片之間移動它了。
最后一點,如果能夠保證大部分的查詢請求都能夠命中盡可能少的分片那就最好了。對于一個查詢請求來說,其延遲直接取決于最慢的那個命中服務器的延遲;所以你命中的分片越少,那么理論上來說查詢將會越快。這一點并不是硬性的規定,不過如果能夠做到充分考慮那么應該是很有利的。因為數據塊在分片上的分布僅僅是近似的遵循片鍵的順序,而并不是嚴格的強制指定。
上面說了這么多,那么怎么才能設計一個好的片鍵呢?
作為第一個方案,你可以使用數據文檔_id的哈希作為片鍵。
db.events.createIndex({_id: 'hashed'})
這個方案能夠是的讀和寫都能夠平均分布,并且它能夠保證每個文檔都有不同的片鍵所以數據塊能夠很精細。
似乎還是不夠完美,因為這樣的話對多個文檔的查詢必將命中所有的分片。雖說如此,這也是一種比較好的方案了。
如果想擊敗哈希索引模式,那么你需要將關聯的文檔在索引中盡可能聚集在一起的方法。在Bugsnag,我們通過project聚合文檔,因為在我們的業務場景中,我們的app大部分的查詢請求都在project范圍內。所以對于你的app來說你得指定適合你的聚合方式。
但是我們不能簡單地使用projectID作為片鍵,因為那會導致巨大塊的產生,所以我們引入了_id來將大project打散到多個塊中。這些打散的塊仍舊是索引連續的,所以仍然會分布在用一個分片上。
db.events.createIndex({projectId: 1, _id: 1})
這個方案很適合我們,因為對于一個project來說,讀和寫幾乎是獨立于project存在時間的,并且舊的project通常都會被刪除掉。如果情況改變,我們可能會看到在新的project會有微小的負載上升情況。
為了避免這種問題,我們未來可能會在當MongoDB支持哈希值的混合索引之后,將索引設置為{projectId: ‘hashed’, _id: 1}。相關文檔(SERVER-10220)
找一個好的片鍵是很難的,不過這真的只有兩種方案。如果在應用中找不出一個好的聚合鍵,那么對_id做哈希吧。如果你能夠找到,那么將它與`_id`聚合以避免巨大塊的產生。請記住無論你使用何種聚合鍵,它都需要能夠將讀和寫平均分布以充分利用集群中的每個節點。
轉自: https://bugsnag.com/blog/mongo-shard-key http://blog.jobbole.com/68854/
原文地址:MongoDB 分片片鍵如何選擇, 感謝原作者分享。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com