萬億級數據庫 MongoDB 集羣性能數十倍提升優化實踐核心 17 問詳細解答

關於作者

       前滴滴出行技術專家,現任 OPPO 文檔數據庫 mongodb 負責人,負責數萬億級數據量文檔數據庫 mongodb 內核研發、性能優化及運維工作,一直專注於分佈式緩存、高性能服務端、數據庫、中間件等相關研發。後續持續分享《MongoDB 內核源碼設計、性能優化、最佳運維實踐》,Github 賬號地址:https://github.com/y123456yz

  1. 性能優化有推薦的分析和監控工具麼?

      mongodb 常用性能分析主要如下:

1.1 mongodb 自帶性能分析工具

**   mongodb 官方對外工具 mongostat**

    命令行使用方法 (ip:port 爲代理 ip 和端口):

       mongostat  -h  ip:port  -u 用戶名 -p 密碼 --authenticationDatabase=admin --discover

      mongostat 工具帶上 --discover,可以把所有分片節點信息一起打印出來,直觀查看整個集羣所有節點實例級監控信息。mongostat 統計信息中最核心的幾個影響性能的統計項:

  1. ****dirty:****存儲引擎髒數據比例,默認該值爲 5% 的時候,wiredtiger 存儲引擎自帶的 evict 現成開始選擇髒數據 page 淘汰到磁盤;如果該值達到 20%,客戶端請求對應 mongodb 處理現成將會選擇髒數據 page 淘汰到磁盤,等 page 淘汰騰出內存空間後,纔會處理客戶端請求的 DB 訪問,所以如果閥值達到 20% 客戶端訪問將會變慢。
  2. ****used:****存儲引擎 cacheSize 配置佔用百分比,如果配置 cacheSize=10G,存儲引擎實際使用了 7G,則 used 贊比爲 70%。當該統計值達到 80%,evict 線程將會觸發選擇漲數據淘汰,如果這個佔比提高到 95%,用戶請求線程將會觸發淘汰,客戶端請求將會變慢。
  3. ****qrw arw:****等待隊列數,如果該值越大,說明會引起客戶端請求排隊處理。一般該值會再 dirty 佔比超過 20%,used 佔比過高超過 95%,或者磁盤 IO 慢會出現。
  4. ****vsize res:****虛擬內存和物理內存真實佔用,如果 vsize 過高,遠遠超過 res,或者 res 過高,遠遠超過 cachesize 配置,則說明內存碎片,pageheap 等問題,這時候可以通過加速 tcmalloc 內存釋放速率來解決問題。

    通過以下命令分析日誌文件

1)找出文件末尾 1000000 行中存在掃表的操作,不包含 oplog,getMore

      tail  mongod.log  -n 1000000 | grep ms |grep COLLSCAN |grep -v "getMore" | grep -v "oplog.rs"

2)找出文件末尾 1000000 行中所有的慢日誌,不包含 oplog,getMore

      tail mongodb.log -n 1000000 |grep ms | grep op_msg | grep find | grep -v "oplog.rs" |grep -v "getMore"

3.)找出文件末尾 1000000 行中執行時間 1-10s 的請求,不包含 oplog,getMore

    tail mongodb.log -n 1000000 |grep ms | grep op_msg | grep find | grep -v "oplog.rs" |grep -v "getMore" | egrep [1-9][0-9][0-9][0-9]ms

4)currentOp 正在執行的慢操作分析

      慢日誌只有當請求執行完畢纔會,如果一個表很大,一個查詢掃表,則整個執行過程可能需要數小時,可能還沒記錄慢日誌,則可以通過如下命令獲取當前執行時間超過 5s 的所有請求,查詢請求,command 請求:

    db.currentOp({"secs_running":{"$gt":5}})

    db.currentOp({"secs_running":{"$gt":1}, "op":"query"})

    db.currentOp({"secs_running":{"$gt":5}, "op":"command"})

   kill 查詢時間超過 5s 的所有請求:

      db.currentOp().inprog.forEach(function(item){if(item.secs_running > 5 )db.killOp(item.opid)})

       db.serverStatus().wiredTiger 可以獲取 mongod 節點對應存儲引擎的各自詳細統計信息,裏面可以完整獲取時延消耗在存儲引擎哪一個環節。

       下面是空餘時間分析的 wiredtiger 源碼,分析不是很完整,後續等 mongodb server 層單機、複製集、分片等完整模塊化分析後,會回頭繼續分析。

       wiredtiger 存儲引擎源碼詳細註釋分析

1.2 操作系統性能瓶頸分析

      系統層面性能分析工具主要有:top、iostat、pstak、ptress、perf、iotop、isof 等,具體請參考對應工具說明。

1.3 開源 mongodb 詳細監控套記

**    開源方案可以參考以下組件:**

**      Grafana+Prometheus+node_exporter+mongodb_exporter**

2. 會話加標籤是怎麼指定服務器?

   ****  舉一個例子形象說明:****我們把用戶分爲三組,20 歲以下(junior),20 到 40 歲(middle)和 40 歲以上(senior),按照下面的幾條命令執行以後,我們的數據會按照用戶年齡段拆分成若干個 chunk,並分發到不同的 shard cluster 中。

      如果對下面的命令不熟悉,可以查看 MongoDB 官方文檔關於 Shard Zone/Chunk 的解釋。

       sh.addShardTag('shard01', 'junior')

      sh.addShardTag('shard02', 'middle')

      sh.addShardTag('shard03', 'senior')

      sh.addTagRange('test.users', {'user.age': MinKey}, {'user.age':20}, 'junior')

      sh.addTagRange('test.users', {'user.age': 21}, {'user.age':40}, 'middle')

      sh.addTagRange('test.users', {'user.age': 41}, {'user.age': MaxKey}, 'senior')

      通過上面的 6 個命令給'test 庫的 user 表加標籤,20 以下對應標籤爲'junior',21-40 對應標籤爲'middle',41 以上對應標籤爲'senior'。同時把'junior'標籤分配給'shard01',也就是 0-20 歲的 user 會全部寫到'shard01',21-40 歲的 user 會全部寫到'shard01',41 歲以上的 user 會全部寫到'shard01'。

      這樣就可以解決跨機房寫的問題,只要對應分片主節點在對應機房即可。

3. 髒數據比例多少算高?

      默認 20% 算高,如果髒數據比例持續性超過 20%,可以試着提高 wiredtiger 存儲引擎後臺淘汰線程數:

  db.adminCommand({ setParameter : 1, "wiredTigerEngineRuntimeConfig" : "cache_size=35GB, eviction=(threads_min=4, threads_max=12)"})

4. 寫分開,會有時延嗎,是不是有一致性問題?

      一致性默認完全由 mongodb 複製集自帶的主從同步機制來保證最終一致性,不存在雙向同步兩集羣的一致性問題。

      如果要實現複製集中主從節點的強一致性,可以通過客戶端配置 writeconcern 策略來解決。

5. 比如想定位詳細的慢查詢呢**?******

      和問題 1 雷同,可以通過分析 currentop、日誌文件或者 system.profile 慢日誌表來獲取詳細的慢日誌信息。建議平臺化收集慢日誌,這樣界面展示分析更加直觀。

6. 如何快速定位 Mongodb 的問題發生在集羣中的哪些節點?  在啓用讀寫分離的情況下?

      主要通過如下幾個步驟來分析:

7. 楊老師,就您經驗來講,您覺得如何保證 MongoDB 的安全性呢?

      安全性方面主要由以下幾方面保證:

      注意:如果數據量很大,建議不要使用 mongodump 備份,mongodump 備份會很慢,同時通過 mongorestore 恢復也是一條數據一條數據恢復,同樣很慢。如果有內核研發能力,可以增加熱備功能。如果沒有內核研發能力,可以通過如下步驟備份:1. 隱藏節點;2. 鎖庫;3. 拷貝數據文件。或者採用 percona mongodb 版本來備份。

8. mysql 和 mongodb 雙寫的話怎麼保證事務呢

      mysql 我不是很瞭解,mongodb 不推薦搭兩集羣雙向同步來備份,直接利用 mongodb 原生的複製集功能來完成多活容災,成本、性能、一致性都可以得到保證。即使是 4.2 分佈式事務功能也可以直接利用 mongodb 自身的機制來保證,具體方案參考我在 Qcon 全球軟件開發大會的分享:

     萬億級數據庫 MongoDB 集羣性能優化及機房多活容災實踐

9. hashnum 的方式來講數組中的方式來拆分成多個表? 沒太明白

      分享的案例 2:萬億級數據量 mongodb 集羣性能數倍提升優化實踐,不是拆分數據到多個表,而是把一條數據 (該數據保護一個數組,數組中包含數百萬個子文檔) 通過 hash 的方式散列爲多條數據。也就是之前數百萬個子文檔歸屬於一條數據,現在把他拆分爲歸屬到多條數據。

      通過這樣合理的數據合併和拆分,最終平衡磁盤 IO,實現讀和寫達到一種平衡態,既能滿足業務讀需求,同時也能滿足業務寫需求。

10. 對分片鍵設計要求高嗎?

      分片集羣片建選擇非常重要,對分片模式集羣性能起着核心至關重要的作用,分片集羣片建選擇遵循以下幾個原則:

11. 首先需要考慮集羣部署是否需要分片?

      只有以下情況才需要分片功能:1. 數據量太大,一個分片撐不住;2. 寫流量太大,寫只能走主節點,一個主節點撐不住,需要擴分片分擔寫流量。

12. 片建選擇原則?

      片建選擇原則如下: 1. 保證數據儘量離散;2. 儘量保證更新和查詢到同一個分片 (如果同一次更新或者查詢到多個分片,只要任何一個分片慢,該操作都會慢;同時部分查詢會進一步加劇代理聚合負擔)。

      此外,如果查詢注意是範圍查詢,建議選擇範圍分片,這樣有利於範圍數據集中到同一個分片。

13. 大表分片後,寫表還是會跨機房嗎?

      機房多活打標籤方式解決跨機房寫問題,同樣可以對對應 tag 表啓用分片功能,保證數據到指定的多個分片,每個分片主節點在指定機房,可以解決跨機房問題。詳情參考:《會話加標籤是怎麼指定服務器?》

14. 老師您好,想請問下:MongoDB 適合做商城 app 數據庫嗎?一般在哪些場景使用呢?謝謝!

      個人覺得完全可以滿足要求,同時還有利於業務的快速迭代開發。mongodb 天然的模式自由 (加字段方便)、高可用、分佈式擴縮容、機房多活容災機制,可以快速推進業務迭代開發。以我的經驗,至少 90% 以上使用 mysql 的場景,mongodb 同樣可以滿足要求。mongodb 唯一缺點可能是生態沒 mysql 健全,研究 mongodb 的人相當少。

15. 老師能講講你們容量預警是怎麼做的嗎?

****     容量水位我們分爲以下幾種:****

      當一個分片中磁盤使用率超過 80%,我們開始擴容增加分片。

      讀寫流量閥值水位如下:1. 如果是分片的寫流量持續性超過 3.5W/s(ssd 服務器) 則擴容分片;2. 如果是讀流量單節點持續性超過 4W/s(ssd 服務器,所有讀走磁盤 IO),則擴容從節點來解決讀流量瓶頸,注意需要配置讀寫分離。

      我們所有實例容器部署,實例如果 CPU 使用率持續性超過 80%,考慮增加容器 CPU。

16. 數據一致性在遷移過程中同步你們是怎麼保證的呢

      如果通過 mongoshake 等工具遷移集羣,需要提前關閉 blance 功能,否則無法解決一致性問題。

      我們線上集羣只有把數據從集羣遷移到另一個集羣的時候纔會使用 mongoshake,我們機房多活不是多個集羣雙寫方式,而是同一個集羣,通過夫直接的主從同步拉取 oplog 機制實現一致性,所以不存在一致性問題。可以參考   萬億級數據庫 MongoDB 集羣性能優化及機房多活容災實踐

17. 我們數據體量不太大,主要是雜,這種環境想做好數據治理,老師你建議把重點放在哪些方面?然後有沒有一些比較常見的坑?

      數據量不大,比較雜的場景,一般集羣搞一個複製集即可滿足要求,無需分片模式部署。

      我猜測你們的比較雜可能是利用 mongodb 的模式自由,造成每條數據的字段各不相同,數據長度大小各不一致。建議在使用模式自由這一功能的時候,一定不要” 濫用”、” 亂用”,在使用時代碼邏輯需要簡單控制。我重節線上遇到的對模式自由的” 濫用”、” 亂用” 引起的集羣問題:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://my.oschina.net/u/4087916/blog/4956301