記十億級Es資料遷移mongodb成本節省及效能優化實踐

y123456yzzyz發表於2021-06-01

某智慧產品業務資料之前儲存在 Elasticsearch (Es) 中,磁碟佔用約 30T( 按照單副本計算 ) ,總資料量 25 億,按照不同業務分類分別存在於不同表中。遷移前,業務存在較嚴重的效能及成本問題,當前業務已經遷移部分資料到 mongodb 中,遷移後效果明顯,成本實現十倍級節省,業務抖動問題也得以解決。

當前我司已有數百億Es 資料遷移 mongodb ,同時也有數百億 mongodb 遷移 Es ,根本原因業務就是選型錯誤引起。

     本文以該場景業務遷移作為案例,主要分享以下方面的內容:

mongodb 適用場景及不適用場景

mongodb Es 各自優勢

mongodb Es 同樣資料,真實磁碟消耗對比

《從MongoDB 遷移到 ES 後,我們減少了 80% 的伺服器》 一文的一些不同看法

     沒有萬能的資料庫,本文最後會總結mongodb Es 各自的適用場景,以客觀立場分析評價 mongodb Es ,拒絕“捧一個,踩一個”。

    Es 絕對是一款優秀的搜尋引擎,在模糊匹配、全文搜尋、複雜檢索等方面相比 mongodb 擁有更大的優勢。

     本文對應業務場景查詢比較簡單,查詢更新等條件都是固定欄位,不涉及複雜檢索,所以在此場景mongodb 更具優勢。另外, mongodb 當前預設的 wiredtiger 儲存引擎,在高壓縮、高效能、鎖粒度等方面進一步提升了 mongodb 在該場景下的優勢。

     我司已有多個業務數百億級資料從Es 遷移 mongodb ,由於其他業務遷移 mongodb 的時間較早,之前沒有詳細記錄遷移前後的 ES mongodb 詳細資源對比,只有大概資源消耗比值。為了儘量客觀評價遷移前後的資料對比,因此選擇近期正在從 Es 遷移 mongodb 的一個叢集,同時記錄源叢集和目的叢集的詳細資源佔用情況,這樣的對比結果會更加客觀真實。

1.  業務背景

該業務儲存智慧產品相關資料,總資料量20 多億,單個叢集 ES 磁碟消耗約 30T 。業務遷移背景如下 ( 以下為業務開發同事整理 )

①  Es 叢集不太穩定,造成秒級耗時,對我們業務影響挺大,感知非常明顯。

②  具體我們業務需求,主要是根據使用者id 來進行精確查詢,沒有複雜全文檢索、模糊查詢等需求,所以其實用不到 Es 的優點。

③  Es 成本太高。

2.  Elasticsearch叢集資源及部署情況

ES 叢集業務在兩個機房各申請了一個叢集,由業務自己通過雙寫的方式來保障資料一致性,當一個叢集異常業務自己切流量到另外一個叢集。

ES 叢集部署架構及資源規格如下:

2.1 Elasticsearch 叢集部署架構

如上圖所示,由於為了實現兩機房雙活容災及單叢集抖動引起的業務故障,在A 機房和 B 機房各搭建了一個 ES 叢集,業務通過雙寫來自己維護兩個叢集的資料一致性。

A 機房叢集 1 異常,或者 A 機房掉電,則業務切流量到 B 機房備叢集 2 ,對應架構圖如下:

2.2 叢集資源規格

    A 機房叢集 1 B 機房叢集 2 內部部署架構完全已有,單個叢集總共有 26 個節點,每個節點都部署在容器中,單個容器規格資源如下所示:

CPU 32

記憶體:64G

磁碟:2T

磁碟型別:SSD

      單個叢集總資源消耗如下:

CPU 32*26=832

記憶體:64G*32=2048G

磁碟:2T*32=64T

      兩個叢集總資源消耗如下:

CPU 32*26*2=1664

記憶體:64G*32*2=4096G

磁碟:2T*32*2=128T

2.3 源叢集架構業務痛點

從上面的分析可以看出,為了保障業務多活和叢集高可用,業務通過雙寫實現,異常後業務自己判斷切換,這增加了業務痛點。該架構主要痛點如下:

①  成本高,本身每個叢集都是多副本,第2 個備叢集進一步增加了成本

②  增加了業務開發難度,業務需要雙寫邏輯

③  資料一致性無法得到保障,例如叢集1 異常或者故障,業務讀寫切到叢集 2 ,當叢集 1 恢復正常,異常這斷時間內,叢集 2 的資料會比叢集 1 多。

④  不利於業務快速迭代開發

⑤  業務只是按照固定欄位做查詢,查詢條件單一,這種場景選擇mongodb 本身效能會更好。

3.  目的mongodb叢集架構

業務開始遷移mongodb 的時候,通過和業務對接梳理,該叢集規模及業務需求總結如下:

①  總資料量20 多億

②  Es 資料單叢集磁碟消耗總和 30.5T 左右

③  讀寫峰值流量流量很小,幾百上千

④  同城兩機房多活容災

3.1 mongodb 資源評估

     分片數及儲存節點套餐規格選定評估過程如下:

記憶體評估

我司都是容器化部署,以以網經驗來看,mongodb 對記憶體消耗不高,歷史百億級以上 mongodb 叢集單個容器最大記憶體基本上都是 64Gb ,因此記憶體規格確定為 64G

分片評估

     務讀寫流量很低,但是資料量較大,因此分片數確定為2 個分片。

磁碟評估

按照以往測試驗證及線上真實資料遷移對比,同樣的資料存入mongodb Es 中真實磁碟消耗佔比如下:

mongodb:Es   1 6

25 Es 真實磁碟消耗 30.5T ,預計 mongodb 磁碟消耗 5T 左右,考慮到未來資料增長,我們按照 50 億資料計算,預計需要 10T 空間。 2 個分片,因此每個分片 5T 資料,最終確定單個 mongod 例項容器磁碟規格 5T

CPU 規格評估

由於容器排程套餐化限制,因此CPU 只能限定為 16CPU( 實際上用不了這麼多 CPU)

mongos 代理及 config server 規格評估

此外,由於分片叢集還有mongos 代理和 config server 複製集,因此還需要評估 mongos 代理和 config server 節點規格。由於 config server 只主要儲存路由相關後設資料,因此對磁碟、 CUP MEM 消耗都很低; mongos 代理只做路由轉發只消耗 CPU ,因此對記憶體和磁碟消耗都不高。最終,為了最大化節省成本,我們決定讓一個代理和一個 config server 複用同一個容器,容器規格如下:

8CPU/8G 記憶體 /50G 磁碟,一個代理和一個 config server 節點複用同一個容器。

分片及儲存節點規格總結: 2 分片 /16CPU 64G 記憶體、 5T 磁碟。

mongos config server 規格總結: 8CPU/8G 記憶體 /50G 磁碟

3.2 叢集部署架構

   由於該業務所在城市只有兩個機房,因此我們採用2+2+1(2mongod+2mongod+1arbiter 模式 ) ,在 A 機房部署 2 mongod 節點, B 機房部署 2 mongod 節點, C 機房部署一個最低規格的選舉節點,如下圖所示:

說明:

①  每個機房代理部署2 mongos 代理,保證業務訪問代理高可用,任一代理掛掉,對應機房業務不受影響。

②  如果機房A 掛掉,則機房 B 和機房 C 剩餘 2mongod+1arbiter ,則會在 B 機房 mongod 中從新選舉一個主節點。 arbiter 選舉節點不消耗資源

③  客戶端配置nearest  ,實現就近讀,確保請求通過代理轉發的時候,轉發到最近網路時延節點,也就是同機房對應儲存節點讀取資料。

弊端:如果是異地機房,B 機房和 C 機房寫存在跨機房寫場景。如果 A B C 為同城機房,則沒用該弊端,同城機房時延可以忽略。

4. 效能優化過程

該叢集優化過程按照如下兩個步驟優化:資料遷移開始前的提前預優化、遷移過程中瓶頸分析及優化、遷移完成後效能優化。

4.1 資料遷移開始前的提前預操作

和業務溝通確定,業務每條資料都攜帶有唯一_id (使用者生成的,不是 mongodb 內部生成),同時業務查詢更新等都是根據 _id 維度查詢該裝置下面的單條或者一批資料,因此片建選擇 _id

分片方式

為了充分雜湊資料到2 個分片,因此選擇 hash 分片方式,這樣資料可以最大化雜湊,同時可以滿足同一個 _id 資料落到同一個分片,保證查詢效率。

預分片

mongodb 如果分片片建為 hashed 分片,則可以提前做預分片,這樣就可以保證資料寫進來的時候比較均衡的寫入多個分片。預分片的好處可以規避非預分片情況下的 chunk 遷移問題,最大化提升寫入效能。

sh.shardCollection("user_xxx.user_xxx", {_id:"hashed"}, false, { numInitialChunks: 8192} )

注意事項: 切記提前對ssoid 建立 hashed 索引,否則對後續分片擴容有影響。

就近讀

客戶端增加nearest  配置,從離自己最近的節點讀,保證了讀的效能。

mongos代理配置

      A機房業務只配置A機房的代理,B機房業務只配置B機房代理,同時帶上nearest配置,最大化的實現本機房就近讀,同時避免客戶端跨機房訪問代理。

禁用enableMajorityReadConcern

禁用該功能後ReadConcern majority將會報錯,ReadConcern majority功能注意是避免髒讀,和業務溝通業務沒該需求,因此可以直接關閉。

mongodb預設使能了enableMajorityReadConcern,該功能開啟對效能有一定影響,參考:

MongoDB readConcern 原理解析

   

儲存引擎cacheSize規格選擇

單個容器規格:16CPU、64G記憶體、7T磁碟,考慮到全量遷移過程中對記憶體壓力,記憶體碎片等壓力會比較大,為了避免OOM,設定cacheSize=42G。

4.2 資料遷移過程中優化過程

全量資料遷移過程中,遷移速度較塊,記憶體漲資料較多,當髒資料比例達到一定比例後使用者讀寫請求對應執行緒將會阻塞,使用者執行緒也會去淘汰記憶體中的髒資料page ,最終寫效能下降明顯。

wiredtiger 儲存引擎 cache 淘汰策略相關的幾個配置如下 :

      由於業務全量遷移資料是持續性的大流量寫,而不是突發性的大流量寫,因此eviction_target eviction_trigger eviction_dirty_target eviction_dirty_trigger 幾個配置用處不大,這幾個引數閥值只是在短時間突發流量情況下調整才有用。

      但是,在持續性長時間大流量寫的情況下,我們可以通過提高wiredtiger 儲存引擎後臺執行緒數來解決漲資料比例過高引起的使用者請求阻塞問題,淘汰漲資料的任務最終交由 evict 模組後臺執行緒來完成。

      全量大流量持續性寫儲存引擎優化如下:

db.adminCommand( { setParameter : 1, "wiredTigerEngineRuntimeConfig" : "eviction=(threads_min=4, threads_max=20)"})

      更多儲存引擎及mongodb 核心涉及實現參考:

4.3 業務流量讀寫優化

前面章節我們提到,在容器資源評估的時候,我們最終確定選擇單個容器套餐規格為如下:

16CPU 64G 記憶體、 5T 磁碟。

全量遷移過程中為了避免OOM ,預留了約 1/3 記憶體給 mongodb server 層、作業系統開銷等,當資料遷移完後,業務寫流量相比全量遷移過程小了很多。

也就是說,前量遷移完成後,cache 中漲資料比例幾乎很少,基本上不會達到 20% 閥值,業務讀流量相比之前多了很多 ( 資料遷移過程中讀流量走原 Es 叢集 ) 。為了提升讀效能,因此做了如下效能調整 ( 提前建好索引 )

節點cacheSize 從之前的 42G 調整到 55G ,儘量多的快取熱點資料到記憶體,供業務讀,最大化提升讀效能。

每天凌晨低峰期做一次cache 記憶體加速釋放,避免 OOM

5. 遷移mongodb後效能對比

當前已有2 個表從 Es 遷移到該 mongodb 叢集,同時該業務新增了 15 億其他業務資料到該叢集,當前目的 mongodb 叢集已有近 20 億資料。

5.1 Es 時延情況

由於該叢集ES 沒有歷史時延統計曲線統計,因此 ES 的時延統計只有以下現象 ( 來自業務方反饋 )

查詢秒級耗時,對我們業務影響挺大,感知非常明顯。

5.2 mongodb 叢集時延曲線

      從上面的監控可以看出,由於除了遷移有源Es 的資料,另外還有該業務的其他業務資料流量流向該叢集,因此 mongodb 叢集流量相比 Es 會更高, mongodb 整體時延約 1.5ms 左右,遠遠好於之前 Es 的有時秒級時延抖動。

6. 遷移成本收益對比

6.1 ElasticSearch 叢集規格

  Es 單個叢集一共 26 個節點,每個節點副本容器規格: 32CPU 64Gmem 2T 磁碟,磁碟型別 SSD ,單個叢集規格總結如下:

①  單叢集節點總數:26

②  每個節點規格:32CPU 64Gmem 2T 磁碟

③  總資料量:25

④  為了實現機房多活容災和業務高可用,實際部署了兩個Es 叢集,實際規格成本還的在上面的基礎上增加一倍。

6.2 mongodb 叢集規格

當前該mongodb 叢集已有約 16 億資料 ( 其中部分為 Es 叢集以外資料,該叢集除了儲存部分 Es 遷移過來的資料,還儲存該業務線其他業務資料 ) ,該 mongodb 叢集規格如下:

①  分片數:2

②  單分片副本數:4

③  每個節點規格:16CPU 64G mem 5T 磁碟

④  兩個分片預計儲存最大資料量:預計儲存Es 叢集中總資料量的兩倍。

6.3 成本對比計算過程

CPU MEM 記憶體成本對比計算過程

Es 兩個叢集和目的 mongodb 叢集資源對比如下:

說明: 由於叢集部署方式可能有很多冗餘,上面的CPU 和記憶體成本比對比實際上不客觀,可能 Es 部署時候規格設定浪費。當然, mongodb 實際上 CPU 資源也非常空閒,所以 CPU 和記憶體指標對比無太大參考作用。

磁碟成本對比計算過程( 成本比約 6 1)

由於目的mongodb 叢集中當前除了有源 ES 遷移過來的部分表外,還有該業務的其他資料,為了保障磁碟對比的客觀性,磁碟對比選材過程如下 ( 說明:源 Es 有兩個叢集,這裡只計算單個叢集單分資料的磁碟消耗,如果按照兩個叢集計算,磁碟成本比為 12:1 ,這種對比方法不客觀 )

①  只對比從源Es 中遷移到 mongodb 中的表

②  只對比源Es 叢集和目的 mongodb 叢集表中資料量完全一樣的表

③  排除源ES 遷移到 mongodb 但是當前還沒有遷移完的表

④  Es 叢集只計算一個叢集單副本的磁碟消耗

通過上面的選擇演算法,基本上做到了同樣資料在Es mongodb 中的對比,磁碟真實消耗對比結果如下 ( 說明:以下資料的 Es 磁碟佔用為單個 Es 叢集單副本方式計算結果,由我司 Es 運維開發人員提供; mongodb 磁碟佔用計算方法為 2 個分片主節點真實磁碟佔用之和,包括資料磁碟消耗 + 索引磁碟消耗 )

從上面的資料對比可以看出,同樣的資料Es 磁碟佔用約為 mongodb 磁碟佔用的 6 倍,和之前其他 Es 遷移 mongodb 過程的資料佔用比值類似。

1 文件內容如下:

1. {  
2.      "_id" : null,  
3.      "channel" : null,  
4.      "content" : "04A193398BE7xxx7E080E2C3CC7B3sxxxxxxxxxC99F9520B8CD0842638DB0F550E125xxxxxxxxxxxxxDB5D3F320642A42CECD3EB5C27714524D0C1BF2A0C6B607D0DFDB669D6633A0E48C65B2623EA15E6DBB0FBF643150E18DD3D0575BDE448C03735A8841E312F8AF0D2BF67D1D357D1AB6249BF3FA4E014C5Axxxxxxxxxxxxxx30C10487667",  
5.      "create_time" : ISODate("2021-02-16T09:56:03Z"),  
6.      "duid" : "6F9E856EDDBB5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxF41B0676FB2DE2171C18450E683DE1E9523B518F266856E01B0D6855E29911E5D10F0FA7E4A8EE5816333D89296E7554F05A58",  
7.      "update_time" : ISODate("2021-02-16T09:56:03Z")  
8. }

2 文件內容如下:

1. {  
2.      "_id" : "F9654874C1A37F74DA5E862C408EDC45",  
3.      "channel" : "10001",  
4.      "content" : "BA7110279AF5XXXXXXXXX6D7ACB8D0F9XXXXXXXXXXXXXX5CDB4693BE949F70E78A20E",  
5.      "create_time" : ISODate("2021-01-21T11:49:46Z"),  
6.      "imei" : "F96548XXXXXXXXXXXXXXXXX2C408EDC45",  
7.      "update_time" : ISODate("2021-01-21T11:49:46Z")  
8. }

7. Elasticsearch mongodb各自適用場景總結

由於業務開發對業務場景評估不到位,當前我司線上mongodb Es 適用過程存在如下現象:

1)  數百億Es 資料遷移 mongodb

2)  也有數百億mongodb 資料遷移到 Es    

從線上真實業務使用情況為例,以下場景不適合mongodb ,實際上也不適合 mysql 等資料庫:

8 欄位以上的隨機組合查詢

有些業務場景,查詢條件是由使用者觸發,查詢條件不固定,可能存在多個欄位的隨機組合查詢。mongodb mysql 等資料庫,都需要手動建立索引,由於 8 欄位以上的隨機組合查詢情況種類太多,因此很難手動建索引覆蓋所有場景,所以選擇 Es 更優,只是成本會更高。

全文檢索

雖然mongodb 也支援全文檢索, mongodb-4.2 以下版本全文檢索能力效能和 ES 沒法比,建議全文檢索適用 Es

mongodb-4.2 全文搜尋已經開始支援 Lucene  引擎,可能效能會有很大提升,暫時沒做研究,也沒做效能對比,後續有空在研究。

其他複雜檢索,例如非字首模糊匹配查詢

例如查詢db.member.find({"name":{ $regex:/XXX/ }}) ,查詢 name 欄位包含 XXX 的查詢,這類查詢 Es 更優,因為 mongodb mysql 等底層都是 KV 儲存,查詢 KEY 的時候都是從左到右比較 key 字串,如果是非字首匹配模糊查詢,就需要全表掃描。

查詢以某欄位為開頭的文件,db.member.find({"name":{$regex:/^XXX/}}) 這類就比較適合用 mongodb 查詢,字首匹配。

 

mongodb Es 不同場景效能對比 ( 以下為真實線上資料對比 )

最後,脫離業務場景評估一個資料庫優劣很不合適,主流資料庫都優其存在的意義,不能因為資料庫在某種場景下不合適而全盤否定該資料庫。

8. 《從MongoDB遷移到ES後,我們減少了80%的伺服器》 一文的不同看法

    《從MongoDB 遷移到 ES 後,我們減少了 80% 的伺服器》 一文中以下觀點個人認不太贊同,主要如下:

8.1 文章內容的不同看法

    mongodb 近幾年持續排名全球前五,市值近兩年已翻數倍,當前市值近 200 億左右。 DB-Engines Ranking 排名得分持續提升,說明本身有自己得市場和應用場景,而不是浪得虛名,沒 《從MongoDB 遷移到 ES 後,我們減少了 80% 的伺服器》 一文中說的不堪一擊。

伺服器80% 節省? mongodb 部署架構嚴重資源浪費

從該文章可以看出,單個文件200 多位元組, mongodb 儲存引擎 wiredtiger 預設高壓縮、高效能、細粒度鎖。單個複製集即可儲存數十億資料,你們用了十多個容器。

同樣的資料,預設mongodb 磁碟佔用是 Es 的六分之一,加上這是日誌叢集, mongodb 可以採用 1mongod+1mongod+1arbiter 部署,規格 8c/32gb/100gb 2 個容器就可以滿足要求。這樣的部署才是合理的,成本會比同樣資料 Es 減少數倍。如果用 mongodb ,本身 2 8c/32gb/100gb+1 個低規格選舉節點容器即可搞定的事,你用了 15 臺。

任意組合的,現有MongoDB 是不支援的?

任意組合的查詢不是mongodb 不支援,是建索引麻煩,包括 mysql tidb 等資料庫都是需要手動一個一個建索引。

效能提高十倍?一個走索引一個不走索引,這種資料對比不客觀

這本身就是個資料庫選型問題,隨機組合條件太多,索引不好建,你應該把索引查詢條件對應索引建好後對比。不過多欄位的隨機組合查詢,確實不適合用mongodb ,建索引麻煩。

建議把mongodb 對應查詢索引建好,重新測試下查詢效能資料。

MongoDB 單集合資料量超過10 億條,此情況下即使簡單條件查詢效能也不理想

我司最大的mongodb 叢集單表幾千億資料,查詢 2ms 以內。

10 億規模對我們線上業務就是毛毛雨,我們把 mongodb 叢集歸類為如下幾檔:

①  小規模叢集:資料量<100

②  中型叢集:資料量100 億到 1000 億之間

③  大型叢集:資料量大於1000

當前我司15%-20% 左右叢集是百億級以上叢集,已成功實現單個叢集 萬億級離線資料 讀寫儲存,當前正在挑戰單個 萬億級實時線上資料 高併發線上讀寫。

萬億級離線資料讀寫優化案例詳見Qcon dbaplus mongodb 社群等分享:

     後續將分享《單叢集萬億級線上資料高併發讀寫優化實踐》

沒有人敢在核心專案中使用 MongoDB

     我司25%-35% 以上資料儲存檔案、圖片等後設資料,甚至包括少量交易叢集,非常核心,當前我司規模早已超過萬億級。

8.2 文章以下回復的不同看法

mongodb 有的, Es 都有?

沒有萬能的資料庫,正如上文所述,mongodb 在高併發寫、固定欄位索引查詢方面的效能表現。此外 mongodb 儲存引擎高壓縮高效能,在成本上面體現很明顯。

業務場景很重要,不能“捧一個,踩一個”,主流資料庫都有其存在的理由,排名第五絕不是浪得虛名。

只有用事務的才是核心資料?

不太贊成這樣定義核心資料,用事務的不一定是核心資料,不用事務的也未必不是核心資料。例如我司儲存的幾千億檔案、圖片等後設資料,沒有用到事務,但是是非常核心的資料,丟失會造成嚴重後果。

8.3 業界對資料庫幾個錯誤認識 ( OPPO 接入業務過程真實案例分享 )

結合公司內部使用mongodb 為例,有時候出現以下情況:一些不適合 mongodb 的業務場景,例如全文檢索、 8 欄位以上的隨機組合查詢、非字首匹配模糊查詢,這些場景本身不適合選用 mongodb ,但是業務選型錯誤,造成使用過程中的瓶頸。

甚至有相關研發人員因為選型錯誤在各種群裡面說:“遠離 mongo ,珍愛生命” ( 該業務有全文檢索需求 ) ;此外還存在業務陣列索引使用不當引起叢集抖動 ( 該業務陣列用法沒建索引引起 ) ,認為 mongodb 設計有問題,這些都是極不負責的行為。

通過這些真實業務接觸過程中的案例,總結如下幾點:

①  沒有萬能的資料庫,切記結合自身業務場景,選擇最優資料庫;

②  主流資料庫都有其存在的理由,不要因為在某些場景不適合而全盤否定該資料庫其他層面的優勢。例如不能因為mongodb 在全文檢索等複雜檢索上面的弱勢而全面否定 mongodb ,也不能因為 Es 在磁碟成本、高併發讀寫等方面的劣勢而否定 Es 在複雜檢索上面的優勢。

③  切記以偏概全,捧一個踩一個,這都是及其不客觀的行為。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69984922/viewspace-2774783/,如需轉載,請註明出處,否則將追究法律責任。

相關文章