Qcon/dbaplus/mongodb社群分享-萬億級資料庫MongoDB叢集效能數十倍提升最佳化實踐

y123456yzzyz發表於2021-02-03

說明:

本文是2020 年深圳 Qcon 全球軟體開發大會 專場 mongodb2020 年終盛會 分享,分享內容如下( 體驗萬億級 mongodb 服務層、儲存引擎、高併發執行緒模型、異地多活容災等實現細節 )

MongoDB OPPO 網際網路推廣經驗分享 - 如何把一個淘汰邊緣的資料庫逐步變為公司主流資料庫

談談當前國內對MongoDB 誤解(丟資料、不安全、難維護)?

MongoDB 跨機房多活方案 - 實現成本、效能、一致性 " 三豐收 "

MongoDB 執行緒模型瓶頸及其最佳化方法

並行遷移:MongoDB 核心擴容遷移速率數倍 / 數十倍提升最佳化實踐

百萬級高併發讀寫/ 千億級資料量 MongoDB 叢集效能數倍提升最佳化實踐

萬億級資料量MongoDB 叢集效能數十倍提升最佳化實踐

磁碟800% 節省 - 記某服務介面千億級資料遷移 MongoDB ,近百臺 SSD 伺服器節省原理

展望:藉助MongoDB 完善的分散式、高可用、機房多活等功能,如何實現 NoSQL NewSQL 融合

其他- 那些年我們踩過的坑

分享目錄

推廣經驗分享

機房多活實現

效能最佳化案例

成本最佳化案例

其他

分享主題一 :如何把mongodb 從淘汰邊緣變為公司主流資料庫?

背景:

入職前多個大資料量業務使用mongodb ,使用中經常超時抖動

多個核心業務忍受不了抖動的痛苦,準備遷移回mysql

mongodb 口碑差,新業務想用不敢用。

入職1 個月,業務遷移 mongodb 到公司其他資料庫, mongodb 總叢集數減少 1 5 %

我做了啥?

從服務層最佳化、儲存引擎最佳化、部署方式最佳化等方面入手,逐一解決抖業務抖動問題

總結各個叢集抖動原因及最佳化方法,公司內部分享。

收集公司所有mongodb 叢集對應使用者,成立 mongodb 使用者群

入職2 月後, mongodb 公司內部狀態:

之前準備遷移到mysql 的幾個核心業務繼續使用 mongodb

對應業務負責人開始考慮把其他大資料量叢集遷移到mongodb

越來越多的未使用過mongodb 的部門開始使用 mongodb

 

入職1 年後, mongodb 相關資料增長:

總叢集數增長比例:> 700%

總資料量增長比例:> 2000%

讀寫流量增長比例:> 550%

mongodb 使用者群使用者數增長比例: > 800%

 

總結:

mongodb 贏得使用者信任原因總結: 口碑

分享主題二 :當前國內對mongodb 誤解 ( 丟資料、不安全、難維護 )


業務接入過程中經常諮詢的幾個問題:

1.  誤解一. 丟資料

2.  誤解二. 不安全,網上一堆說 mongodb 被駭客攻擊,截圖一堆新聞

3.  誤解三. DBA 吐槽 mongodb 太難維護

誤解原因:

mongodb 本身很優秀,但是很多 DBA 和相應開發把控不住

國內系統性分析mongodb 核心實現原理相關資料欠缺

網路社會以訛傳訛,DBA 或者相關開發自身把控不住演變為 mongodb 的鍋

分享主題三 mongodb 機房多活方案 - 實現成本、效能、一致性 " 三豐收 "

社群mongodb雙向同步方案(放棄該方案)

放棄該方案原因:

資料兩份、叢集兩份、物理成本高。三機房、五機房等更多機房多活,成本及複雜性更高。

存在一致性問題,兩地叢集資料不一致,balance 情況下尤為突出

由於人力原因,如果開源同步工具出現問題把控不在。

方案一:同城三機房多活方案(1mongod+1mongod+1mongod方式)

每個機房代理至少部署2 個,保證業務訪問代理高可用

如果某機房異常,並且該機房節點為主節點,藉助mongodb 天然的高可用機制,其他機房 2 mongod 例項會自動選舉一個新節點為主節點。

客戶端配置nearest 就近訪問,保證讀走本機房節點。

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

方案二:同城兩機房多活方案(2mongod+2mongod+1arbiter模式)

每個機房代理至少部署2 個,保證業務訪問代理高可用

如果機房A 掛掉,則會在 B 機房 mongod 中重新選舉一個新的主節點。 arbiter 選舉節點不消耗資源

客戶端配置nearest 引數,保證讀走本機房節點

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

方案三:異地三機房多活方案(1mongod+1mongod+1mongod方式)-解決跨機房寫


每個機房代理透過打標籤的方式,代理轉發資料到主節點在本機房的分片上去。

A 機房資料透過標籤識別轉發到分片 shard-1 B 機房資料轉發到分片 shard-2 C 機房資料轉發到分片 shard-3

分享主題四 mongodb 執行緒模型瓶頸及其最佳化方法

mongodb預設執行緒模型(一個連結一個執行緒)

說明:

listener 執行緒負責接受所有的客戶端連結

listener 執行緒每接收到一個新的客戶端連結就建立一個執行緒,該執行緒只負責處理該連結請求處理。

 

該網路執行緒模型缺陷:

一個連結建立一個執行緒,如果10 萬個連結,那麼就需要 10 萬個執行緒,系統負責、記憶體消耗也會很多

當連結關閉的時候,執行緒銷燬,頻繁的執行緒建立和消耗進一步增加系統負載

 

典型案例:

mysql 預設方式、 mongodb 同步執行緒模型配置,適用於請求處理比較耗時的場景,如資料庫服務

mongodb預設執行緒模型(動態執行緒模型:單佇列方式)

說明:

該模型把一次請求轉換為多個任務:mongodb 資料讀操作 ( 網路 IO) db 層資料訪問 ( 磁碟 IO)

任務入隊到全域性佇列,執行緒池中的執行緒從佇列中獲取任務執行。

同一個請求訪問被拆分為多個任務,大部分情況下透過遞迴呼叫同一個請求的多個任務會由同一個執行緒處理;。

當任務太多,系統壓力大的時候,執行緒池中執行緒數動態增加;當任務減少,系統壓力減少的時候,執行緒池中執行緒數動態減少;

 

該網路執行緒模型缺陷:

執行緒池獲取任務執行,有全域性鎖競爭,這裡就會成為系統瓶頸

 

典型案例:

mongodb 動態 adaptive 執行緒模型,適用於請求處理比較耗時的場景,如資料庫服務

mongodb最佳化後執行緒模型(動態執行緒模型-多佇列方式)

說明:

把一個全域性佇列拆分為多個佇列,任務入隊的時候按照session 連結 hash 雜湊到各自的佇列,工作執行緒獲取獲取任務的時候,同理透過同樣的 hash 演算法去對應的佇列獲取任務,透過這種方式減少鎖競爭,同時提升整體效能。

 

典型案例:

mongodb 核心多佇列 adaptive 執行緒模型最佳化,特定場景效能有很好的提升,適用於請求處理比較耗時的場景,如資料庫服務。

分享主題五 並行遷移- 叢集擴容速率 N 倍提升最佳化實踐

並行遷移-叢集擴容速率N倍提升最佳化實踐(高版本)

並行遷移過程(假設需要遷移的表名為:test , 從 3 節點擴容到 6 節點):

選取需要遷移的塊,假設源叢集有M 分片,擴容新增 N 分片,則一般情況需要遷移的塊 =min(M,N)

遷移步驟:1. configServer-master 選出需要遷移的塊; 2. config.locks 表中 id=test 這條記錄上鎖; 3. 通知需要遷移的源分片開始遷移; 4. 遷移完成後延時 10s ,重複 1-4 步驟實現持續性 chunk 資料遷移

並行遷移步驟:

    說明: 假設需要遷移的表名為test , 源分片數 M ,擴容後新增分片數 N

configServer-master 選出需要遷移的塊,一般 S=min(M, N) ,也就是 M N 中的最小值;

config.locks 表中獲取 id=test 這條記錄對應的分散式鎖;

非同步通知需要遷移的S 個源分片開始遷移;

等待S chunk 遷移完成

遷移完成後延時10

重複步驟1-5

並行遷移瓶頸:

獲取分散式鎖時間太長,原因:config.locks 表中 id=test 表的分散式鎖可能被其他操作鎖住

configServer 非同步通知源分片中的 S 個分片同時開始遷移資料到目的分片,任一個 chunk 遷移慢會拖累整個遷移過程。

本批次確認遷移完成後,還需要延時10s ;一般 SSD 伺服器,一個 chunk 遷移都在幾百 ms 內完成。

 

最佳化方法:

避免其他操作佔用分散式鎖,例如splite 我們可以關閉 autoSplite 功能,或者調大 chunksize

configServer 並行遷移不把多個分片的並行遷移放到同一個邏輯,而是放到各自的邏輯。

延時放到各自分片遷移邏輯裡面控制,不受全域性延時控制

分片延時可配置,支援實時動態命令列調整

分享主題六: 效能最佳化案例

案例1.千億級資料量mongodb叢集效能數倍提升最佳化實踐-背景

業務背景:

核心後設資料

資料量千億級

前期寫多讀少,後期讀多寫少

高峰期讀寫流量百萬級

時延敏感

資料增長快,不定期擴容

同城多活叢集

最佳化策略1 :部署及使用方式最佳化

預分片,寫入負載均衡。

WriteConcern { w: "majority"} ,寫大部分節點成功才返回客戶端 OK

讀寫分離,讀從優先。

enableMajorityReadConcern 關閉,有效能損耗。

最佳化策略2 :儲存引擎 cache 淘汰策略最佳化

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

wiredtiger 儲存引擎 cache 淘汰策略最佳化後配置 :

eviction_target: 75% eviction_trigger 97% eviction_dirty_target: %3 eviction_dirty_trigger 25% evict.threads_min 4 evict.threads_max 16

 

總體思想: evict 執行緒儘早淘汰髒頁 page 到磁碟,增加 evict 淘汰執行緒數加快髒資料淘汰,避免使用者請求執行緒進行髒資料淘汰。

最佳化策略3 :儲存引擎 checkpoint 最佳化

     儲存引擎checkpoint 檢測點,把當前儲存引擎髒資料全部記錄到磁碟。觸發條件如下 :

固定週期做一次checkpoint 快照,預設 60s

增量journal 日誌達到 2G

 

少部分例項存在如下現象: 一會兒磁碟IO 幾乎空閒 0% ,一會兒磁碟 IO 短暫性 100% 。進行如下最佳化後可以緩解該問題 :

      checkpoint=(wait=30,log_size=1GB)

 

該最佳化總體思路: 縮短checkpoint 週期,減少 checkpoint 期間積壓的髒資料,緩解磁碟 IO 高問題。

遺留問題: SSD 盤只有極少數節點有該問題,原因未知,後續繼續跟蹤。

瓶頸點:

代理快取所有客戶端的連結資訊到記憶體中,並定期更新到config 庫的 system.sessions 表中。

大流量大資料量叢集客戶端連結眾多,大量更新sessions 表,最終主分片效能下降引起整個叢集效能瞬間數倍下降。

最佳化方法:

config 庫的 system.sessions 表啟用分片功能。  

mongos 定期更新最佳化為雜湊到不同時間點進行更新。

最佳化策略4

sharding 叢集 system.session 最佳化

 

該最佳化總體思路:

之前代理集中式更新單個分片,最佳化為雜湊到不同時間點更新多個分片。

該最佳化後system.sessions 表更新引起的瞬間效能數倍降低和大量慢日誌問題得到了解決。

最佳化策略5 tcmalloc 記憶體最佳化

db.serverStatus().tcmalloc 監控發現部分 mongod 例項 pageheap 、記憶體碎片等消耗過高。透過系統呼叫分析得出:記憶體碎片率、 pageheap 過高,會引起分配記憶體過程變慢,引起叢集效能嚴重下降。

 

該最佳化總體思路:

藉助gperftools 三方庫中 tcmalloc 記憶體管理模組,實時動態調整 tcmalloc 記憶體 Release Rate ,儘早釋放記憶體,避免儲存引擎獲取 cache 過程阻塞變慢。

案例2.萬億級資料量mongodb叢集效能數倍提升最佳化實踐

業務背景:

叢集儲存離線資料

叢集總資料量萬億級

前期主要為資料寫入,要求萬億級資料幾周內儘快全部寫入叢集

後期主要是讀流量,單次查詢資料條數比較多,要求快速返回

每隔一定時間週期( 周為單位 ) 會有持續性大量寫入

最佳化策略1 :基礎性最佳化

分享主題六中讀寫分離、預分片、wiredtiger 儲存引擎最佳化、 session 最佳化、 tcmalloc 使用最佳化等基礎性最佳化策略同樣適用於該叢集,具體詳見《分享主題六 : 百萬級高併發讀寫 / 千億級資料量 mongodb 叢集效能數倍提升最佳化實踐》

最佳化策略2 :儲存模型最佳化前狀況

     最佳化前資料模型結構如下:

1. {  
2.     "_id": ObjectId("5fh2ebd18856960dbac31abc"),  
3.     "characteristic": "xxxx",  
4.     "key1": "***",  
5.     ......  
6.     "keyn": "***",  
7. }

以上為單條資料的資料模型,該叢集總資料量萬億級。

數十萬條資料擁有同樣的characteristic 特性,總特性數總計數百萬個。

一次性查詢數十個characteristic 很慢。

 

瓶頸點:   一次性查詢數十個characteristic 特徵條件的資料,每個特徵擁有數百萬資料,一次查詢總計千萬行資料。由於資料量很大,每行資料幾乎全在磁碟,一次查詢需要千萬次 IO 操作,查詢成為瓶頸。  

最佳化策略2 :第一輪資料儲存模型最佳化:

1. {  
2.     "_id": ObjectId("5f29ebd18856960dbac31abc"),  
3.     "characteristic": "xxxx"  
4.     "group": [  
5.            {  
6.             "key1": "***"  
7.             ......  
8.             "keyn": "***"  
9.         },   #該characteristic下第一條資料  
10.             ......  
11.         {  
12.             "key1": "***"  
13.             ......  
14.             "keyn": "***"  
15.         } #該characteristic下第n條資料  
16.     ]  
}

該資料模型把相同characteristic 特性的數十萬資料合併到為一條資料,減少磁碟 IO 操作,整個讀效能會有近百倍提升。

 

瓶頸點: 該輪最佳化解決了讀瓶頸,卻引入了新的寫瓶頸。

透過$ addToSet 方式向group 陣列中去重追加資料,資料長度越來越長,磁碟 IO 壓力越來越大、寫效能成為新的瓶頸。

最佳化策略2 :第二輪資料儲存模型最佳化:

1. {  
2.     "_id": ObjectId("5f29ebd18856960dbac31abc"),  
3.     "characteristic": "xxxx",  
4.    "hashNum": num,     
5.     "group": [  
6.            {  
7.             "key1": "***",  
8.             ......  
9.             "keyn": "***",  
10.         },   #該characteristic下第一條資料  
11.             ......  
12.         {  
13.             "key1": "***",  
14.             ......  
15.             "keyn": "***",  
16.         } #該characteristic下第n條資料  
17.     ]  
18. }

    如上,把同一個characteristic 特徵的數十萬 / 數百萬 資料雜湊為500 份,這樣合併後 group 陣列中也就只包含數百條資料資訊,這樣合併後單條資料過大、 mongodb 單條資料 64M 限制問題 磁碟IO 過高 等瓶頸問題都可以得到解決。

 

總體資料模型最佳化思路: 透過合理的資料合併操作來減少網路IO 、磁碟 IO mongodb 核心處理時間,最終使讀和寫達到平衡。

分享主題七 成本節省- 記某服務千億級資料遷移 mongodb ,百臺 SSD 伺服器節省最佳化實踐

成本節省-千億級資料遷移mongodb,百臺SSD伺服器節省最佳化實踐

遷移背景:

需要遷移的資料量數千億級

源叢集磁碟緊張,業務寫入快,需要快速完成資料遷移

源叢集資料儲存於高io ssd 伺服器

業務對效能沒太高要求

目的mongodb 叢集採用低 io 大容量 sata

 

遷移難點:

如何快速完成資料遷移?

瓶頸點:

由於目的叢集為低io 大容量 sata 盤,遷移太慢,源叢集磁碟有寫滿風險 

最佳化策略:

同步資料到大容量SSD 中轉叢集

複製中轉叢集資料到目標大容量SATA 盤伺服器

載入資料

成本節省:

mongodb 預設的 snappy 壓縮演算法壓縮比約為 2.2-3.5

zlib 壓縮演算法壓縮比約為 4.5-7.5 ( 本次遷移採用 zlib 高壓縮演算法 )

 

千億級資料遷移mongodb 收益:

源叢集磁碟消耗: 目的叢集磁碟消耗 = 8:1( 即使目的 mongo 叢集也用 SSD 伺服器,成本也可以節省七倍 )

源叢集物理資源: 百臺SSD 伺服器

目的mongodb 叢集資源消耗: 6 SATA 盤伺服器

分享主題八 展望- 如何實現 mongodb SQL 融合

問題背景:

      隨著mongodb-4.2 版本中對分散式事務的支援,以及 mongodb-4.4 版本產品規劃路線圖可以看出, mongodb 除了保持 nosql 特性外,還在朝著 newSql 方向前行。但是在實際業務接入中發現以下現象 :

開發習慣了SQL ,轉 mongodb 語法各種不習慣。

運營和資料分析崗位人員只會寫SQL ,不會 mongo 語句。

 

 

我們能做什麼?

mongos 代理增加 mongodb 協議和 SQL 轉換支援,用最小開發成本滿足業務 SQL 需求。

5%-10% 左右的 SQL 協議支援,滿足 90% 的使用者需求。

分享主題九 其他- 那些年我們踩過的坑

“那些年我們踩過的坑” :       

     實際業務接入mongodb 資料庫過程中,我們踩過很多坑,包括業務不合理使用、不合理運維、叢集不合理配置、 mongodb 核心踩坑、誤操作等,甚至出現過同一個核心業務幾次抖動。

 

       本次分享中叢集最佳化只列舉了主要的最佳化過程,實際最佳化過程比本次分享內容更加複雜,叢集更多最佳化細節及數十例典型踩坑過程將逐步在Qconf 平臺、 OPPO 網際網路、 mongodb 中文社群釋出。

 

踩坑不可怕,在踩坑過程中學習,學習過程中減少踩坑

2021 規劃:

     國內真正擁有企業級分散式資料庫自研能力的公司主要集中在阿里、騰訊頭部幾家,即使二三線網際網路公司也無法做到真正意義上的企業級分散式資料庫研發能力,擁抱開源是一個明智的選擇。

    mongodb 擁有天然的高可用、分散式擴縮容、機房多活容災、完善的負載均衡及一致性策略等功能,可以做到最少人力成本滿足業務快速增長的需求,個人認為 mongodb 絕對是頭部公司以外企業會分散式資料庫需求的一個值得信賴的選擇。    

正如在 mongodb 中文社群所分享,當前 mongodb 國內影響力待提升最大的問題在於國內真正研究 mongodb 核心實現細節的人太少,造成很多複雜問題無法解決,最終這些 的問題演變為mongodb 問題”。

在此,後續持續性分享業務接入過程中的典型踩坑,同時持續性模組化分析mongodb 核心設計原理,為 mongodb 國內影響力提升做點實事,具體詳見:

 

程式碼最能說明mongo 實現細節, 21 年持續分析及最佳化 mongodb 核心原始碼

 


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

相關文章