300條數據變動引起的血案-記某十億級核心mongodb集羣部分請求不可用故障踩坑記

        線上某核心mongodb集羣數據量不大,單表數據量十億級,可是該集羣比較核心,影響公司收入流水。本文經過分享本次踩坑來分享整個故障通過,該故障爲一次經典的mongodb分片sharding集羣踩坑故障,包括變動通知不到位、部署架構不到位、變動考慮不仔細等。mysql

關於做者

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

序言

       本文是oschina專欄《mongodb 源碼實現、調優、最佳實踐系列》的第20篇文章,其餘文章能夠參考以下連接:github

Qcon-萬億級數據庫 MongoDB 集羣性能數十倍提高及機房多活容災實踐sql

Qcon 現代數據架構 -《萬億級數據庫 MongoDB 集羣性能數十倍提高優化實踐》核心 17 問詳細解答mongodb

百萬級高併發 mongodb 集羣性能數十倍提高優化實踐 (上篇)數據庫

百萬級高併發 mongodb 集羣性能數十倍提高優化實踐 (下篇)緩存

Mongodb特定場景性能數十倍提高優化實踐(記一次mongodb核心集羣雪崩故障)安全

經常使用高併發網絡線程模型設計及mongodb線程模型優化實踐性能優化

爲什麼要對開源mongodb數據庫內核作二次開發服務器

盤點 2020 | 我要爲分佈式數據庫 mongodb 在國內影響力提高及推廣作點事

 百萬級代碼量 mongodb 內核源碼閱讀經驗分享

話題討論 | mongodb 擁有十大核心優點,爲什麼國內知名度遠不如 mysql 高?

Mongodb 網絡模塊源碼實現及性能極致設計體驗

網絡傳輸層模塊實現二

網絡傳輸層模塊實現三

網絡傳輸層模塊實現四

command 命令處理模塊源碼實現一

command 命令處理模塊源碼實現二

mongodb 詳細表級操做及詳細時延統計實現原理 (快速定位表級時延抖動)

[圖、文、碼配合分析]-Mongodb write 寫 (增、刪、改) 模塊設計與實現

Mongodb集羣搭建一篇就夠了-複製集模式、分片模式、帶認證、不帶認證等(帶詳細步驟說明)

300條數據變動引起的血案-記某十億級核心mongodb集羣部分請求不可用故障踩坑記

  1. 問題背景

     某核心mongodb歷史集羣(入職前就有的一個集羣),在對如今全部mongodb集羣進行風險梳理過程當中,發現該集羣存在一些潛在的集羣抖動風險,該集羣架構及流量時延曲線以下:

      如上圖所示,該分片集羣由3個分片組成,集羣讀寫流量很低,峯值QPS約4-6W/s,平均時延1ms,每一個分片採用mongodb複製集架構實現高可用。經過巡檢發現該集羣存在以下幾個問題:

  1. 該集羣只包含兩個用戶庫,userbucket庫和feeds_content庫,兩個庫中只有feeds_xxxxxxx.collection1啓用了分片功能;第一個userbucket庫存儲集羣路由信息,第二個feeds_xxxxxxx庫存儲約十億數據信息;
  2. 因爲該集羣主要是讀多寫少集羣,讀流量都是讀取feeds_xxxxxxx庫中的數據,而且客戶端作了讀寫分離,因此幾乎大部分讀流量都在分片1。分片2和分片3只有少許數據。

      庫表信息以下表所示:

    上面的描述能夠總結爲下圖:

       從上圖能夠看出,分片2和分片3幾乎沒起到任何做用;因爲分片3有兩個節點爲低IO的sata盤,可能影響userbucket庫的讀寫,所以考慮直接removeShard從集羣中剔除分片3和分片2。

2. 操做過程

       因爲分片3爲低IO服務器,有潛在抖動集羣抖動分享;同時分片2和分片3幾乎都是浪費的分片,所以打散直接經過以下removeshad命令刪除分片3和分片2信息,騰出無用服務器資源,以下圖所示:

  • 步驟1:登錄任一一個代理,假設是代理mongos1。
  • 步驟2:因爲分片3(也就是shard_8D5370B4分片)爲userbucket庫的主分片,所以報錯了,提示"you need to drop or movePrimary these databases",意思是咱們須要提早把該庫的主分片信息遷移到其餘分片。
  • 步驟3:經過movePrimary命令把userbucket庫的主分片從分片3遷移到分片1。
  • 登錄監控列表中的其餘兩個代理mongos二、mongos3,經過db.adminCommand({"flushRouterConfig":1}) 強制刷新路由信息。

 注意事項:因爲movePrimary過程,其餘代理不會感知到該庫的主分片變化,所以須要強制刷新路由信息或者重啓其餘節點的mongos,參考以下:

3. 用戶反饋大部分請求業務請求不可用

       對含有300條數據的userbucket庫變動後,當我還在若無其事的處理其餘集羣性能調優的時候,用戶忽然很急的電話我反饋該核心集羣整個訪問不可用(注意:是整個10億數據的集羣不可用)。

      收到電話後很忽然,和業務人員詳細對接後能夠基本上肯定是由於這300條數據變動引發。業務獲取這300條數據的時候,部分請求獲取成功,部分請求獲取失敗,說明確定和movePrimary有關係。

      因而,除了對監控列表中的全部代理作flushRouterConfig強制路由刷新外,還重啓了全部的代理,可是業務反饋,仍是有部分請求獲取不到數據。比較棘手,我本身經過全部的mongos代理查看userbucket庫下面的300條數據,徹底能夠獲取到數據。

      因而懷疑是否是還有未刷新路由的mongos代理,因而登錄任一mongos代理獲取config.mongos表,查看結果以下:

上面的config.mongos表記錄了該集羣全部的代理信息,同時記錄了這些代理和集羣最後一次ping通訊的詳細時間信息。很明顯,該表中記錄的代理原不止集羣監控列表中的代理個數,比監控列表中的個數要多。

最終,把config.mongos表中羅列的當前在線的全部代理強制經過flushRouterConfig刷新路由後,業務恢復。

4. 問題總結

       經過前面的分析能夠得出,因爲早期集羣監控中漏掉了部分代理,形成這部分代理對應的userbucket路由信息是movePrimary前的路由信息,也就是指向了錯誤的分片,所以出現了路由不到數據的狀況,以下圖所示:

  • 爲什麼用戶userbucket庫對應表中數據有的成功有的失敗?

    由於部分代理在moveprimary後,沒有強制刷新該表路由信息,形成部分代理路由獲取數據的時候路由錯誤。

  • 爲什麼該300條數據部分路由信息錯誤會形成整個10億集羣部分訪問不可用?

和業務實現邏輯有關係,由於業務在獲取這10億條數據前首先須要獲取業務的路由信息,恰好業務路由信息存在了userbucket庫對應表中,業務在獲取數據前必需要獲取到業務的路由信息數據,若是userbucket數據獲取不到,用戶就沒法肯定指向feeds_xxxxxxx數據

  • 爲什麼會遺漏部分代理重啓或者強制路由刷新?

歷史緣由,形成部分代理業務代碼有配置,可是服務端集羣監控元數據遺漏了,也就是服務端集羣監控漏掉了部分代理,這部分代理沒有監控起來。也有多是mongos代理擴容,可是集羣監控列表中沒有加入元數據。

  • movePrimary操做最安全的操做方法?

官方建議movePrimary操做成功後須要強制路由刷新或者重啓mongos,可是movePrimary操做成功和mongos重啓這個過程當中有個中間狀態,若是中間狀態業務讀或者些該遷移的庫下面的表,仍是可能路由錯誤。所以,最佳安全的moveprimary能夠經過以下兩個方法操做:

法一:shutdown全部代理,只留下一個代理,等該代理moveprimary成功後在重啓其餘mongos代理。切記別遺漏代理,出現本文踩坑相似狀況,提早檢查config.mongos表。

法二:對主分片在該須要removeShard的分片的庫中的全部表啓用分片功能,啓用分片功能後會有chunk信息,mongodb會自動遷移該分片的chunk到其餘分片,整個過程能夠保證路由信息一致。

相關文章
相關標籤/搜索