某智能產品業務數據以前存儲在Elasticsearch(Es)中,磁盤佔用約30T(按照單副本計算),總數據量25億,按照不一樣業務分類分別存在於不一樣表中。遷移前,業務存在較嚴重的性能及成本問題,當前業務已經遷移部分數據到mongodb中,遷移後效果明顯,成本實現十倍級節省,業務抖動問題也得以解決。html
當前我司已有數百億Es數據遷移mongodb,同時也有數百億mongodb遷移Es,根本緣由業務就是選型錯誤引發。mysql
本文以該場景業務遷移做爲案例,主要分享如下方面的內容:git
- mongodb適用場景及不適用場景
- mongodb和Es各自優點
- mongodb和Es一樣數據,真實磁盤消耗對比
- 對《從MongoDB遷移到ES後,咱們減小了80%的服務器》一文的一些不一樣見解
沒有萬能的數據庫,本文最後會總結mongodb和Es各自的適用場景,以客觀立場分析評價mongodb和Es,拒絕「捧一個,踩一個」。github
Es絕對是一款優秀的搜索引擎,在模糊匹配、全文搜索、複雜檢索等方面相比mongodb擁有更大的優點。算法
本文對應業務場景查詢比較簡單,查詢更新等條件都是固定字段,不涉及複雜檢索,因此在此場景mongodb更具優點。另外,mongodb當前默認的wiredtiger存儲引擎,在高壓縮、高性能、鎖粒度等方面進一步提高了mongodb在該場景下的優點。sql
我司已有多個業務數百億級數據從Es遷移mongodb,因爲其餘業務遷移mongodb的時間較早,以前沒有詳細記錄遷移先後的ES和mongodb詳細資源對比,只有大概資源消耗比值。爲了儘可能客觀評價遷移先後的數據對比,所以選擇近期正在從Es遷移mongodb的一個集羣,同時記錄源集羣和目的集羣的詳細資源佔用狀況,這樣的對比結果會更加客觀真實。mongodb
關於做者
前滴滴出行專家工程師,現任OPPO文檔數據庫mongodb負責人,負責數萬億級數據量文檔數據庫mongodb內核研發、性能優化及運維工做,一直專一於分佈式緩存、高性能服務端、數據庫、中間件等相關研發。後續持續分享《MongoDB內核源碼設計、性能優化、最佳運維實踐》,Github帳號地址:https://github.com/y123456yz數據庫
序言
本文是oschina專欄《mongodb 源碼實現、調優、最佳實踐系列》的第21篇文章,其餘文章能夠參考以下連接:數組
Qcon-萬億級數據庫 MongoDB 集羣性能數十倍提高及機房多活容災實踐緩存
Qcon 現代數據架構 -《萬億級數據庫 MongoDB 集羣性能數十倍提高優化實踐》核心 17 問詳細解答
百萬級高併發 mongodb 集羣性能數十倍提高優化實踐 (上篇)
百萬級高併發 mongodb 集羣性能數十倍提高優化實踐 (下篇)
Mongodb特定場景性能數十倍提高優化實踐(記一次mongodb核心集羣雪崩故障)
經常使用高併發網絡線程模型設計及mongodb線程模型優化實踐
盤點 2020 | 我要爲分佈式數據庫 mongodb 在國內影響力提高及推廣作點事
話題討論 | mongodb 擁有十大核心優點,爲什麼國內知名度遠不如 mysql 高?
mongodb 詳細表級操做及詳細時延統計實現原理 (快速定位表級時延抖動)
[圖、文、碼配合分析]-Mongodb write 寫 (增、刪、改) 模塊設計與實現
Mongodb集羣搭建一篇就夠了-複製集模式、分片模式、帶認證、不帶認證等(帶詳細步驟說明)
300條數據變動引起的血案-記某十億級核心mongodb集羣部分請求不可用故障踩坑記
- 業務背景
該業務存儲智能產品相關數據,總數據量20多億,單個集羣ES磁盤消耗約30T。業務遷移背景以下(如下爲業務開發同事整理):
- Es集羣不太穩定,形成秒級耗時,對咱們業務影響挺大,感知很是明顯。
- 具體咱們業務需求,主要是根據用戶id來進行精確查詢,沒有複雜全文檢索、模糊查詢等需求,因此其實用不到Es的優勢。
- Es成本過高。
- 源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自己性能會更好。
- 目的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,該功能開啓對性能有必定影響,參考:
OPPO百萬級高併發MongoDB集羣性能數十倍提高優化實踐
- 存儲引擎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內核涉及實現參考: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" : "04A193398BE7xxx7E080E2C3CC7B3sxxxxxxxxxC99F9520B8CD0842638DB0F550E125xxxxxxxxxxxxxDB5D3F320642A42CECD3EB5C27adfadfasdfasfdasdfadfa669D6633A0E48C65B2623EA15E6DBB0FBF643150E18DD3D0575BDE448C03735A8841E312F8AF0D2BF67D1D357D1AB6249BF3FA4E014C5Axxxxxxxxxxxxxx30C10487667", 5. "create_time" : ISODate("2021-02-16T09:56:03Z"), 6. "duddddd" : "6F9E856EDDBB5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxF41B0676FB2DE2171C18450E683DE1E9523B518F266856E01B0D6855E29911E5D10F0FA7E4A8EE5816333D89296E7554F05A58", 7. "update_time" : ISODate("2021-02-16T09:56:03Z") 8.}
表2文檔內容以下:
1.{ 2. "_id" : "F9654874C1A37F74DA5E862C408EDC45", 3. "channel" : "10001", 4. "content" : "BA7adfafadfaF5XXXXXXXXX6D7adfafafda9XXXXXXXXXXXXXXfurwt54fewwrsfgsE", 5. "create_time" : ISODate("2021-01-21T11:49:46Z"), 6. "imssses" : "F96548XXXXXXXXXXXXXXXXX2C408EDC45", 7. "update_time" : ISODate("2021-01-21T11:49:46Z") }
7. Elasticsearch和mongodb各自適用場景總結
因爲業務開發對業務場景評估不到位,當前我司線上mongodb和Es適用過程存在以下現象:
- 數百億Es數據遷移mongodb
- 也有數百億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!
後續將分享《單集羣萬億級在線數據高併發讀寫優化實踐》
- 沒有人敢在覈心項目中使用MongoDB?
我司25%-35%以上數據存儲文件、圖片等元數據,甚至包括少許交易集羣,很是核心,當前我司規模早已超過萬億級。
8.2 文章如下回復的不一樣見解
- mongodb有的,Es都有?
沒有萬能的數據庫,正如上文所述,mongodb在高併發寫、固定字段索引查詢方面的性能表現。此外mongodb存儲引擎高壓縮高性能,在成本上面體現很明顯。
業務場景很重要,不能「捧一個,踩一個」,主流數據庫都有其存在的理由,排名第五毫不是浪得虛名。
- 只有用事務的纔是核心數據?
不太同意這樣定義核心數據,用事務的不必定是核心數據,不用事務的也未必不是核心數據。例如我司存儲的幾千億文件、圖片等元數據,沒有用到事務,可是是很是核心的數據,丟失會形成嚴重後果。
8.3 業界對數據庫幾個錯誤認識(以OPPO接入業務過程真實案例分享)
結合公司內部使用mongodb爲例,有時候出現如下狀況:一些不適合mongodb的業務場景,例如全文檢索、8字段以上的隨機組合查詢、非前綴匹配模糊查詢,這些場景自己不適合選用mongodb,可是業務選型錯誤,形成使用過程當中的瓶頸。
甚至有相關研發人員由於選型錯誤在各類羣裏面說:「遠離mongo,珍愛生命」(該業務有全文檢索需求);此外還存在業務數組索引使用不當引發集羣抖動(該業務數組用法沒建索引引發),認爲mongodb設計有問題,這些都是極不負責的行爲。
經過這些真實業務接觸過程當中的案例,總結以下幾點:
- 沒有萬能的數據庫,切記結合自身業務場景,選擇最優數據庫;
- 主流數據庫都有其存在的理由,不要由於在某些場景不適合而全盤否認該數據庫其餘層面的優點。例如不能由於mongodb在全文檢索等複雜檢索上面的弱勢而全面否認mongodb,也不能由於Es在磁盤成本、高併發讀寫等方面的劣勢而否認Es在複雜檢索上面的優點。
- 切記以偏概全,捧一個踩一個,這都是及其不客觀的行爲。