MongoDB分區中片鍵的選擇

來源:互聯網
上載者:User

轉載自 http://www.cnblogs.com/spnt/

當MongoDB整個架構已經部署好以後,真正考驗架構者能力的時候就到了:該如何選擇片鍵。

如果選擇了一個不恰當的片鍵,他可能會在訪問量變大的時候,使你的整個應用系統崩潰,同樣好的片鍵可以構成一個良性的生態系統,根據需要增刪伺服器,MongoDB會確保系統一直正確的運行下去。

咱們先看看幾種不恰當的片鍵

1,小基數片鍵

    假設我們有一個儲存使用者資訊的應用程式,每個文檔有一個continent的欄位,儲存使用者所在地區,其值有:africa,antarctica,asia,australia,europe,north america,south america。考慮到我們在每個州都有一個資料中心,並且想從人們所在地的資料中心為其提供資料,我們決定按該欄位分區。

     集合開始於某個資料中心的一個分區的初始塊(-∞,∞),所有的插入和讀取都落在這一塊上,一旦他變得足夠大,就會被分成兩個塊(-∞,europe)和[europe,∞),這樣一來,所有來自africa,antarctica,asia和australia的文檔都會被分到第一塊,其他的都會被分到第二塊,隨著更多的文檔被添加到資料庫,集合最終會變成7個塊,如下

   (-∞,antarctica)

   [anrarctica,asia)

   [asia,australia)

   [australia,europe)

   [europe,north america)

   [north america,south america)

   [south america,∞)

然後呢?

MongoDB不能再進一步分割這些塊了,快會越來越大,雖然暫時不會出問題,但是當伺服器硬碟空間被用完的時候,你就沒辦法了,只能購買新的硬碟,悲劇的是硬碟是有極限的。

  由於片鍵數量有限,因此這種片鍵稱為小基數片鍵,如果選擇了一個基數很小的片鍵,到頭來肯定會得到一堆巨大無法移動也不能分割的塊,這時候做維護做擴充是什麼感覺,你懂得。

 如果是因為需要在某個欄位上做大量查詢而採用小基數片鍵,那就需要使用組合片鍵了,一個片鍵包含兩個欄位,並確保第二個欄位有非常多不同的值供MongoDB用來進行分割,比如大部分的查詢都和時間關聯,可以用時間欄位做第二個欄位,又可以減輕負載。

2,升序片鍵

從RAM中讀取資料要比磁碟取快,所以目標是儘可能多的訪問記憶體中的資料。一次,如果有些資料總是被一起訪問,我們就希望能夠把他們保持在一起。對大部分應用來說,新資料被訪問的次數總比老的多,所以往往會使用如時間戳記或者objectId一類的欄位來分區,但是這並不想我們期望的那樣可行。

 比如我們有一個類似微博的服務,其中每個文檔都包含一條訊息,發送人和發送時間,我們按時間來分區,讓我們看看MongoDB會如何運行

  首先還是一個大塊(-∞,∞),文檔會全部插入到這個分區上,然後開始分裂,比如(-∞,1294516901),[1294516901,-∞)----(使用的是時間戳記),由於是從片鍵中點把塊分開,所以在分割開快的那一刻開始,說有資料都會插入到第二個塊上,不會在插入帶第一個塊上,一旦塊二被插滿,他會在分割成兩塊,但同樣的只會在最後一塊插入資料,這種情況會一直持續下去,這就造成了一個單一且不可分散的熱點。在網站高峰期可見這個點上的壓力。

3,隨機片鍵

    有時為了避免熱點,會採用一個取值隨機的欄位來做分區,採用這種片鍵一開始還不錯,但是隨著資料量越來越大,他會越來越慢。

     比如我們在分區集合中儲存照片縮圖,每個文檔包含了照片的位元據,位元據的md5散列值,以及描述等欄位,我們決定在md5散列值上做分區。

    隨著集合的增長,我們最終會得到一組均勻分佈於各分區的資料區塊。目前一起正常。現在假設我們非常忙而分區2上的一個塊填滿並分裂了,設定管理員注意到分區2比分區1多出了10個塊並判定應該抹平分區間的差距,這樣MongoDB就需要隨機載入5個塊的資料到記憶體中並發給片1,考慮到資料序列的隨機性,一般情況下這些資料可能不會出現在記憶體中,所以此時的MongoDB會給RAM帶來更大的壓力,而且還會引發大量的磁碟IO。

   另外,片鍵上必須有索引,因此如果選擇了從不依據索引查詢的隨機鍵,基本上可以說浪費了一個索引,另一方面索引的增加會降低寫操作的速度,所以降低索引量也是非常必要的。

那麼怎麼樣的片鍵才是好的片鍵呢?

從上面的分析可得出一個好的片鍵應該具備良好的資料局部性,但又不會因為太局部而導致熱點出現。

1,准升序鍵加搜尋鍵

     許多應用程式都是訪問新資料更頻繁,所以我們希望資料大致按時間排序,但是同時也要均勻分布,這樣一來既能把我們正在讀寫的資料保持在記憶體中,又可以均衡的分散在叢集中。

     我們可以通過像{coarselyAscending:1,search:1}這樣的組合片鍵來實現,其中coarselyAscending的每個值最好能對應幾十到幾百個資料區塊,而search則應當是應用程式通常都會一句其進行查詢的欄位。

  舉個例子:有個剖析器,使用者定期通過他訪問過去一個月的資料,而我們希望能盡量保持資料便於使用,因此可以使用{month:1,user:1}來做分區,現在來說說運行過程

   首先一個大資料區塊((-∞,-∞),(∞,∞)),當他被填滿,MongoDB將自動分割成兩塊,比如:

     ((-∞,-∞),("2012-07","susan"))

    [("2012-07","susan"),(∞,∞))

假設現在還是7月,則所有寫操作會被均勻的分布到兩個塊上。所有使用者名稱小於susan的資料被寫入塊1中,所有大於susan的資料被寫入塊2,然後整個生態系統就良性運行了,等到8月,MongoDB又開始建立2012-08的塊,分布還是均衡的(這裡不是時時均衡,肯定有個抹平的過程),等到9月,7月的資料無人訪問就開始退出記憶體,不再佔用資源。

 

--------------------------------------------------------------------------------------------------------------------------------------

當然情境不同,應用就不同,上面也只是基本的東西,具體選擇片鍵還應該根據自己的程式來做,選鍵的時候多考慮以下問題。

   1,寫操作是怎麼樣的,有多大?

   2,系統沒小時會寫多少資料,每天呢,高峰期呢

   3,那些欄位是隨機的,那些是增長的

   4,讀操作是怎麼樣的,使用者在訪問那些資料

   5,資料索引做了嗎?應不應該索引呢?

  6,資料總量有多少

 總的來說,在進行分區前,你需要清楚的瞭解你的資料。

 

 以上內容參考了“深入學習MongoDB” 一書,如果需瞭解更多MongoDB最佳化的知識,這本數絕對值得一讀,這本書還列出了50例MongoDB最佳化,維護等等需要注意的地方

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.