線上某IOT核心業務集羣以前採用mysql做爲主存儲數據庫,隨着業務規模的不斷增長,mysql已沒法知足海量數據存儲需求,業務面臨着容量痛點、成本痛點問題、數據不均衡問題等。html
400億該業務遷移mongodb後,一樣的數據節省了極大的內存、CPU、磁盤成本,同時完美解決了容量痛點、數據不均衡痛點,而且實現了必定的性能提高。此外,遷移時候的mysql數據爲400億,3個月後的如今對應mongodb集羣數據已增加到1000億,若是以1000億數據規模等比例計算成本,實際成本節省比例會更高。mysql
當前國內不少mongod文檔資料、性能數據等還停留在早期的MMAP_V1存儲引擎,實際上從mongodb-3.x版本開始,mongodb默認存儲引擎已經採用高性能、高壓縮比、更小鎖粒度的wiredtiger存儲引擎,所以其性能、成本等優點相比以前的MMAP_V1存儲引擎更加明顯。git
關於做者
前滴滴出行專家工程師,現任OPPO文檔數據庫mongodb負責人,負責數萬億級數據量文檔數據庫mongodb內核研發、性能優化及運維工做,一直專一於分佈式緩存、高性能服務端、數據庫、中間件等相關研發。後續持續分享《MongoDB內核源碼設計、性能優化、最佳運維實踐》,Github帳號地址:https://github.com/y123456yzgithub
序言
本文是oschina專欄《mongodb 源碼實現、調優、最佳實踐系列》的第22篇文章,其餘文章能夠參考以下連接:算法
Qcon-萬億級數據庫 MongoDB 集羣性能數十倍提高及機房多活容災實踐sql
Qcon 現代數據架構 -《萬億級數據庫 MongoDB 集羣性能數十倍提高優化實踐》核心 17 問詳細解答mongodb
百萬級高併發 mongodb 集羣性能數十倍提高優化實踐 (上篇)數據庫
百萬級高併發 mongodb 集羣性能數十倍提高優化實踐 (下篇)數組
Mongodb特定場景性能數十倍提高優化實踐(記一次mongodb核心集羣雪崩故障)緩存
經常使用高併發網絡線程模型設計及mongodb線程模型優化實踐
盤點 2020 | 我要爲分佈式數據庫 mongodb 在國內影響力提高及推廣作點事
話題討論 | mongodb 擁有十大核心優點,爲什麼國內知名度遠不如 mysql 高?
mongodb 詳細表級操做及詳細時延統計實現原理 (快速定位表級時延抖動)
[圖、文、碼配合分析]-Mongodb write 寫 (增、刪、改) 模塊設計與實現
Mongodb集羣搭建一篇就夠了-複製集模式、分片模式、帶認證、不帶認證等(帶詳細步驟說明)
300條數據變動引起的血案-記某十億級核心mongodb集羣部分請求不可用故障踩坑記
- 業務遷移背景
該業務在遷移mongodb前已有約400億數據,申請了64套mysql集羣,由業務經過shardingjdbc作分庫分表,提早拆分爲64個庫,每一個庫100張表。主從高可用選舉經過依賴開源orchestrator組建,mysql架構圖以下圖所示:
說明:上圖中紅色表明磁盤告警,不少節點磁盤使用水位即將100%。
如上圖所示,業務一年多前一次性申請了64套MySQL集羣,單個集羣節點數一主三從,每一個節點規格以下:
- cpu:4
- mem:16G
- 磁盤:500G
- 總節點數:64*4=256
- SSD服務器
該業務運行一年多時間後,總集羣數據量達到了400億,並以每個月200億速度增加,因爲數據不均衡等緣由,形成部分集羣數據量大,持續性耗光磁盤問題。因爲節點衆多,愈來愈多的集羣節點磁盤突破瓶頸,爲了解決磁盤瓶頸,DBA不停的提高節點磁盤容量。業務和DBA都面臨嚴重痛點,主要以下:
- 數據不均衡問題
- 節點容量問題
- 成本持續性增長
- DBA工做量劇增(部分磁盤提高不了須要遷移數據到新節點),業務也提心吊膽
業務
2. 爲什麼選擇mongodb-附十大核心優點總結
業務遇到瓶頸後,基於mongodb在公司已有的影響力,業務開始調研mongodb,經過和業務接觸瞭解到,業務使用場景都是普通的增、刪、改、查、排序等操做,同時查詢條件都比較固定,用mongodb徹底沒任何問題。
此外,mongodb相比傳統開源數據庫擁有以下核心優索:
- 優點一:模式自由
mongodb爲schema-free結構,數據格式沒有嚴格限制。業務數據結構比較固定,該功能業務不用,可是並不影響業務使用mongodb存儲結構化的數據。
- 優點二:自然高可用支持
mysql高可用依賴第三方組件來實現高可用,mongodb副本集內部多副本經過raft協議自然支持高可用,相比mysql減小了對第三方組件的依賴。
- 優點三:分佈式-解決分庫分表及海量數據存儲痛點
mongodb是分佈式數據庫,完美解決mysql分庫分表及海量數據存儲痛點,業務無需在使用數據庫前評估須要提早拆多少個庫多少個表,mongodb對業務來講就是一個無限大的表(當前我司最大的表存儲數千億數據,查詢性能無任何影響)。
此外,業務在早期的時候通常數據都比較少,能夠只申請一個分片mongodb集羣。而若是採用mysql,就和本次遷移的IOT業務同樣,須要提早申請最大容量的集羣,早期數據量少的時候嚴重浪費資源。
- 優點四:完善的數據均衡機制、不一樣分片策略、多種片建類型支持
關於balance:支持自動balance、手動balance、時間段任意配置balance.
關於分片策略:支持範圍分片、hash分片,同時支持預分片。
關於片建類型:支持單自動片建、多字段片建
- 優點五:不一樣等級的數據一致性及安全性保證
mongodb在設計上根據不一樣一致性等級需求,支持不一樣類型的Read Concern 、Write Concern讀寫相關配置,客戶端能夠根據實際狀況設置。此外,mongodb內核設計擁有完善的rollback機制。
- 優點六:高併發、高性能
爲了適應大規模高併發業務讀寫,mongodb在線程模型設計、併發控制、高性能存儲引擎等方面作了不少細緻化優化。
- 優點七:wiredtiger高性能存儲引擎設計
網上不少評論還停留在早期MMAPv1存儲引擎,相比MMAPv1,wiredtiger引擎性能更好,壓縮比更高,鎖粒度更小,具體以下:
- WiredTiger提供了低延遲和高吞吐量
- 處理比內存大得多的數據,而不會下降性能或資源
- 系統故障後可快速恢復到最近一個checkpoint
- 支持PB級數據存儲
- 多線程架構,盡力利用樂觀鎖併發控制算法減小鎖操做
- 具備hot-caches能力
- 磁盤IO最大化利用,提高磁盤IO能力
- 其餘
更多WT存儲引擎設計細節能夠參考:
http://source.wiredtiger.com/3.2.1/architecture.html
- 優點八:成本節省-WT引擎高壓縮比支持
mongodb對數據的壓縮支持snappy、zlib算法,在以往線上真實的數據空間大小與真實磁盤空間消耗進行對比,能夠得出如下結論:
- mongodb默認的snappy壓縮算法壓縮比約爲2.2-4.5倍
- zlib壓縮算法壓縮比約爲4.5-7.5倍(本次遷移採用zlib高壓縮算法)
此外,以線上已有的從mysql、Es遷移到mongodb的真實業務磁盤消耗統計對比,一樣的數據,存儲在mongodb、Mysql、Es的磁盤佔比≈1:3.5:6,不一樣數據存儲佔比有差距。
- 優點九:自然N機房(無論同城仍是異地)多活容災支持
mongodb自然高可用機制及代理標籤自動識別轉發功能的支持,能夠經過節點不一樣機房部署來知足同城和異地N機房多活容災需求,從而實現成本、性能、一致性的「三豐收」。更多機房多活容災的案例詳見Qcon分享:
- 優點十:完善的客戶端均衡訪問策略
mongodb客戶端訪問路由策略由客戶端本身指定,該功能經過Read Preference實現,支持primary 、primaryPreferred 、secondary 、secondaryPreferred 、nearest 五種客戶端均衡訪問策略。
- 分佈式事務支持
mongodb-4.2 版本開始已經支持分佈式事務功能,當前對外文檔版本已經迭代到 version-4.2.12,分佈式事務功能也進一步加強。此外,從 mongodb-4.4 版本產品規劃路線圖能夠看出,mongodb 官方將會持續投入開發查詢能力和易用性加強功能,例如 union 多表聯合查詢、索引隱藏等
2. mongodb資源評估及部署架構
業務開始遷移mongodb的時候,經過和業務對接梳理,該集羣規模及業務需求總結以下:
- 已有數據量400億左右
- 數據磁盤消耗總和30T左右
- 讀寫峯值流量4-5W/s左右,流量很小
- 同城兩機房多活容災
- 讀寫分離
- 每個月預計增長200億數據
- 知足幾個月內1500億新增數據需求
說明:數據規模和磁盤消耗按照單副本計算,例如mysql 64個分片,256個副本,數據規模和磁盤消耗計算方式爲:64個主節點數據量之和、64個分片主節點磁盤消耗之和。
3.1 mongodb資源評估
分片數及存儲節點套餐規格選定評估過程以下:
- 內存評估
我司都是容器化部署,以往經驗來看,mongodb對內存消耗不高,歷史百億級以上mongodb集羣單個容器最大內存基本上都是64Gb,所以內存規格肯定爲64G。
- 分片評估
業務流量峯值3-5W/s,考慮到可能後期有更大峯值流量,所以按照峯值10W/s寫,5w/s讀,也就是峯值15W/s評估,預計須要4個分片。
- 磁盤評估
mysql中已有數據400億,磁盤消耗30T。按照以網線上遷移經驗,mongodb默認配置磁盤消耗約爲mysql的1/3-1/5,400億數據對應mongodb磁盤消耗預計8T。考慮到1500億數據,預計4個分片,按照每一個分片400億規模,預計每一個分片磁盤消耗8T。
線上單臺物理機10多T磁盤,幾百G內存,幾十個CPU,爲了最大化利用服務器資源,咱們須要預留一部分磁盤給其餘容器使用。另外,由於容器組套餐化限制,最終肯定肯定單個節點磁盤在7T。預計7T節點,4個分片存儲約1500億數據。
- 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節點複用同一個容器。
分片及存儲節點規格總結:4分片/16CPU、64G內存、7T磁盤。
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 爲同城機房,則沒有該弊端,同城機房時延能夠忽略。
4. 業務全量+增量遷移方式
遷移過程由業務本身完成,經過阿里開源的datax工具實現,該遷移工具的更多細節能夠參考:https://github.com/alibaba/DataX
5. 性能優化過程
該集羣優化過程按照以下兩個步驟優化:數據遷移開始前的提早預優化、遷移過程當中瓶頸分析及優化、遷移完成後性能優化。
5.1 數據遷移開始前的提早預操做
和業務溝通肯定,業務每條數據都攜帶有一個設備標識ssoid,同時業務查詢更新等都是根據ssoid維度查詢該設備下面的單條或者一批數據,所以片建選擇ssoid。
- 分片方式
爲了充分散列數據到4個分片,所以選擇hash分片方式,這樣數據能夠最大化散列,同時能夠知足同一個ssoid數據落到同一個分片,保證查詢效率。
- 預分片
mongodb若是分片片建爲hashed分片,則能夠提早作預分片,這樣就能夠保證數據寫進來的時候比較均衡的寫入多個分片。預分片的好處能夠規避非預分片狀況下的chunk遷移問題,最大化提高寫入性能。
sh.shardCollection("xxx.xxx", {ssoid:"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。
5.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)"})
5.3 全量遷移完成後,業務流量讀寫優化
前面章節咱們提到,在容器資源評估的時候,咱們最終肯定選擇單個容器套餐規格爲以下:
16CPU、64G內存、7T磁盤。
全量遷移過程當中爲了不OOM,預留了約1/3內存給mongodb server層、操做系統開銷等,當全量數據遷移完後,業務寫流量相比全量遷移過程小了不少,峯值讀寫OPS約2-4W/s。
也就是說,前量遷移完成後,cache中髒數據比例幾乎不多,基本上不會達到20%閥值,業務讀流量相比以前多了不少(數據遷移過程當中讀流量走原mysql集羣)。爲了提高讀性能,所以作了以下性能調整(提早建好索引):
- 節點cacheSize從以前的42G調整到55G,儘可能多的緩存熱點數據到內存,供業務讀,最大化提高讀性能。
- 天天凌晨低峯期作一次cache內存加速釋放,避免OOM。
上面的內核優後後,業務測時延監控曲線變化,時延更加平穩,平均時延也有25%左右的性能優後,以下圖所示:
6. 遷移先後,業務測時延統計對比(Mysql vs mongodb)
6.1 性能收益對比
- 遷移前業務測時延監控曲線(平均時延7ms, 2月1日數據,此時mysql集羣只有300億數據):
- 遷移mongodb後而且業務流量所有切到mongodb後業務測時延監控曲線(平均6ms, 3月6日數據,此時mongodb集羣已有約500億數據))
總結:
- mysql(300億數據)時延:約7ms
- mongodb(500億數據)時延:約6ms
6.2 性能質疑解答
該文有部分同窗可能質疑性能數據,認爲mongodb實例規格是16CPU/64G內存/7T磁盤,而mysql是4CPU/16G內存/500G磁盤。認爲mongodb規格更高,而mysql資源規格低。可是忽略了單節點數據量和流量這個因素,按照單實例對比,總結以下(因爲只記錄了mysql 300億時候、mongodb 500億時候的業務測時延,所以仍是以這兩個時間點爲例比較):
Mysql和mongodb的CPU都不是瓶頸,都很空閒,二者之間容器規格惟一區別就是內存,單實例規格、數據量、業務測時延等對比總結(單實例mysql數據量約300/64=4.7億,mongodb約125億):
若是mysql採用mongodb一樣的規格,因爲mysql一樣數據磁盤消耗是mongodb 3.3倍,所以須要22T左右磁盤,而且承擔一樣的數據量和流量,性能會不會好於方案1?這個不是很肯定,由於都是線上環境,不可能爲了驗證這個測試而大費周章。
如上,方案3和方案一、方案2的性能對比有待驗證。實際上,mongodb當前4個分片已經1000億數據了,客戶端訪問時延基本上沒有變化,仍是約6ms,所以實際上若是同等資源規格驗證,客觀數mysql單個節點須要承擔以下數據量和業務流量:
7. 遷移成本收益對比
7.1 Mysql集羣規格及存儲數據最大量
原mysql集羣一共64套,每套集羣4副本,每一個副本容器規格:4CPU、16G mem、500G磁盤,總共能夠存儲400億數據,這時候大部分節點已經開始磁盤90%水位告警,DBA對部分節點作了磁盤容量提高。
總結以下:
- 集羣總套數:64
- 單套集羣副本數:4
- 每一個節點規格:4CPU、16G mem、500G磁盤
- 該64套集羣最大存儲數據量:400億
7.2 mongodb集羣規格及存儲數據最大量
mongodb從mysql遷移過來後,數據量已從400億增長到1000億,並以每月增長200億數據。mongodb集羣規格及存儲數據量總結以下:
- 分片數:4
- 單分片副本數:4
- 每一個節點規格:16CPU、64G mem、7T磁盤
- 四個分片存儲數據量:當前已存1000億,最大可存1500億數據。
7.3 成本對比計算過程
說明:因爲mysql遷移mongodb後,數據不在往mysql中寫入,流量切到mongodb時候mysql中大約存儲有400億數據,所以咱們以這個時間點作爲對比時間點。以400億數據爲基準,資源消耗對好比下表(每一個分片只計算主節點資源消耗,由於mysql和mongodb都是4副本):
因爲mongodb四個分片還有不少磁盤冗餘,該四個分片相比400億數據,還能夠寫1200億數據。若是按照1600億數據計算,若是仍是按照mysql以前套餐規格,則mysql集羣數須要再增長三倍,也就是總集羣套數須要64*4=256套,資源佔用對好比下:
7.4 收益總結(客觀性對比)
從上面的內容能夠看出,該業務遷移mongodb後,除了解決了業務容量痛點、促進業務快速迭代開發、性能提高外,成本還節省了數倍。成本節省總結以下:
- 400億維度計算(mysql和mongodb都存儲相同的400億數據):
CPU和內存成本比例:4:1
磁盤成本比例:3.3:1
- 1500億維度計算(mysql集羣都採用以前規格等比例換算):
CPU和內存成本比例:16:1
磁盤成本比例:3.3:1
從上面的分析能夠看出,數據量越大,按照等比例換算原則,mongodb存儲成本會更低,緣由以下:
- CPU/內存節省緣由:
主要是由於mongodb海量數據存儲及高性能緣由,索引建好後,單實例單表即便幾百億數據,讀寫也是ms級返回(注意:切記查詢更新建好索引)。
此外,因爲mongodb分佈式功能,對容量評估更加方便,就無需提早一次性申請不少套mysql,而是根據實際須要能夠隨時加分片。
- 磁盤節省緣由:
mongodb存儲引擎wiredtiger默認高壓縮、高性能。
最後,鑑於客觀性成本評價,CPU/內存成本部分可能會有爭議,好比mysql內存和CPU是否申請的時候就申請過大。mongodb對應CPU也一樣存在該問題,例如申請的單個容器是16CPU,實際上真實只消耗了幾個CPU。
可是,磁盤節省是實時在在的,是相同數據狀況下mysql和mongodb的真實磁盤消耗對比。
當前該集羣總數據量已經達到千億級,並以每月200億規模增長,單從容器計費層面上換算,1000億數據按照等比例換算,預計可節省極大的成本。
8. 最後:千億級中等規模mongodb集羣注意事項
mongodb無需分庫分表,單表能夠無限大,可是單表隨着數據量的增多會引發如下問題:
- 切記提早建好索引,不然影響查詢更新性能(數據越多,無索引查詢掃描會越慢)。
- 切記提早評估好業務須要那些索引,單節點單個表數百億數據,加索引執行時間較長。
- 服務器異常狀況下節點替換時間相比會更長。
- 切記數據備份不要採用mongodump/mongorestore方式,而是採用熱備或者文件拷貝方式備份。
- 節點替換儘可能從備份中拷貝數據加載方式恢復,而不是經過主從全量同步方式,全量同步過程較長。
9. 將來挑戰(該集羣將來萬億級實時數據規模挑戰)
隨着時間推移,業務數據增加也會愈來愈多,單月數據量增加曲線預計會直線增長(當前每個月數據量增長200億左右),預計將來2-3年該集羣總數據量會達到萬億級,分片數也會達到20個分片左右,可能會遇到各自各樣的問題。
- 可是,IOT業務數據存在明顯的冷數問題,一年前的數據用戶基本上不會訪問,所以咱們考慮作以下優後來知足性能、成本的進一步提高:冷數據歸檔到低成本SATA盤
- 冷數據提高壓縮比,最大化減小磁盤消耗
- 如何解決冷數據歸檔sata盤過程當中的性能問題
冷熱歸檔存儲能夠參考以前在Qcon、dbaplus、mongodb中文社區分享的另外一篇文章:
10. 最後說明(業務場景總結)
本千億級IOT業務使用場景總結以下:
- 本分享的業務數據讀、更新、排序等均可以走索引,包括單字段索引、多字段索引、數組索引,全部查詢和更新都能肯定走具體的某個最優索引。
- 查詢都是單表查詢,不涉及多表聯合查詢。
數據庫場景很是重要,脫離業務場景談數據庫優劣無任何意義。例如本文的業務場景,業務能肯定須要建那些索引,同時全部的更新、查詢、排序均可以對應具體的最優索引,所以該場景就很是適合mongodb。