怎麼對10億資料量級的mongoDB作高效的全表掃描

來源:互聯網
上載者:User

標籤:

轉自:http://quentinxxz.iteye.com/blog/2149440

一、正常情況下,不應該有這種需求

首先,大家應該有個概念,標題中的這個問題,在大多情況下是一個偽命題,不應該被提出來。要知道,對於一般較大資料量的資料庫,全表查詢,這種操作一般情況下是不應該出現的,在做正常查詢的時候,如果是範圍查詢,你至少應該要加上limit。

說一下,我的應用程式情境:用於全量建立搜尋引擎的索引。這就是一種需要用到全表掃描的非一般情況。對於全表掃描的結果,我們沒有排序要求。

 

二、情況說明

既然有如此大的資料量,那儲存所佔空間基本都是上T的了。所以肯定是使用了mongodb叢集,而且配置了分區的分布式環境。

公司的伺服器,效能比較好,應該是24核,96g記憶體的。所以讀者們使用不同機器,測出來的用時,跟我這的結果可能不一定相符。

 

三、第一種方法,利用chunk資訊作劃分。

    原理:我們知道,在分區環境下,mongodb使用chunk塊來組織資料。同一個chunk塊的資料肯定存在於同一個分區上。假設,我們以 “_id”作分區時所用的片鍵。Mongodb為了保證範圍尋找的效率,一定會將一定範圍內的_id值的document方在同一個chunk中。而且通過mongodb自身提供的方法,我們可以很方便的擷取,每一個chunk的中maxKey與minKey。[minKey,maxKey) 這個範圍內的資料肯定在同一個chunk內,也並定在同一個分區中。

做法:1、先擷取所有chunk資訊,得到他們的maxKey與minKey。

2、多線程執行,將這些chunk資訊,分發給這些執行線程。

3、各線程,根據當前的chunk與 maxKey與minKey資訊,做範圍尋找。

4、最後將結果匯總。

     這樣做的好處在於:

1、每次對一個chunk做的範圍尋找,肯定是只在一個分區(意味著同一塊硬碟)中進行的,不會分散到多個分區。這樣很高效。

2、可以方便的利用多線程,提高效率。

     這種方法我沒試過,公司的前輩嘗試過,據說,最終用時3小時以內。是最為理想的效果。

 

四、改用散列片鍵後的全表掃描方法

用上面的方法,有一個前題,就是分區策略採用的是mongodb預設的升序片鍵的方法。這樣才保證,升序的_id,會按排序範圍分布在chunk塊中。這樣這策略,存在一個明顯的問題,就是會造成所以新增的doucument的寫入肯定都會命中到具有當前最大_id的chunk上。造成寫入的分發的不平衡。

前文中,說過,全表掃描,應該是一個正常情況下不被允許的情況。所以資料庫策略的制定也不應該以考慮全表掃描的效率為優先,當前情況下,就應以寫入效為優先考慮。公司正在使用的片鍵策略,是片鍵策略散列片鍵(hashed shard key),這樣的話,寫入請況會被很好地分發到多個分區上,但是不利用進行範圍尋找。上面用的全表掃描方法就沒法再用了。

做法:1、獲得全域的最大id maxID與全域的最小id minID。

      2、設定一個stepSize ,比如5000。將[minID,maxID]按5000為一個chunk(我們定義的一個邏輯chunk)作切分,那麼第一個區塊範圍[minID,minID+5000),

 3、各線程,根據分配到的chunk塊的maxID與minID資訊,做範圍尋找。

4、最後將結果匯總。

這樣做法的問題:

               1、對一個chunk進行查詢,會命中多個分區進行查詢,查詢效率大幅降低。

               2、 如果_id分布稀疏,查詢變得更快。因為以5000為stepSize, 其中可能有不少_id是不存在的。測試同學幫我搭線下測試資料時,2000w條資料,由於計算錯誤,_id的範圍分布劇然從10億起,到130億止。導致的線程幾乎一起在空跑chunk。所以_id分布稀疏的情況下,這種查詢方式完全不適用。

               3、 _id分布不均。可能某個chunk中幾乎5000個滿載,有些chunk只有很少幾個_id有效。那麼就會導致計算資源分布不均。

     最後的結果不理想,我一開始,由於涉及一些聯表join操作,用時16多個小時。後來各種調整,加線程,去掉一些操作,差不多仍需10小時。

 

五、改用散列片鍵後的較高效全表掃描方法

上面的那種方法,當然是不理想的。光查資料就需要16個小時,加上後續處理,肯定更久,這樣我們的搜尋引擎索引建立,就不可能當前完成了。但一直苦於沒有更好的方法。

最終這個問題,還是被我的頭解決了。 先說一下,最終效果吧。20w條/秒,約3小時完成。

其實,最終的方法很簡單,但必須放棄多線程(多cursor),至多一個分區一個線程。

做法:使用單線程掃描,不加適合可能影響排序的條件。

 

這樣做的目的是使用mongodb中的自然排序。掃描時,必然是依次命中某一個分區讀取,不會帶來磁碟震蕩問題。

怎麼對10億資料量級的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.