用最少人力玩轉萬億級數據,我用的就是MongoDB!


本文根據楊亞洲老師在〖deeplus直播第258期〗線上分享演講內容整理而成。(文末有獲取本期PPT&回放的方式,不要錯過)

 

楊亞洲

OPPO MongoDB負責人

 

  • 負責OPPO數萬億級數據量文檔數據庫MongoDB內核研發、性能優化及運維工作,一直專注於分佈式緩存、高性能服務端、數據庫、中間件等相關研發。

 

本文主要分享內容如下:

 

  • MongoDB在OPPO互聯網推廣經驗分享-如何把一個淘汰邊緣的數據庫逐步變爲公司主流數據庫;

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

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

  • MongoDB線程模型瓶頸及其優化方法;

  • 並行遷移:MongoDB內核擴容遷移速率數倍/數十倍提升優化實踐;

  • 百萬級高併發讀寫/千億級數據量MongoDB集羣性能數倍提升優化實踐;

  • 萬億級數據量MongoDB集羣性能數十倍提升優化實踐;

  • 磁盤800%節省-記某服務接口千億級數據遷移MongoDB,近百臺SSD服務器節省原理;

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

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

 

一、如何把MongoDB從淘汰邊緣變爲公司主流數據庫?

 

  背景

 

  • 入職前多個大數據量業務使用MongoDB,使用中經常超時抖動;

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

  • MongoDB口碑差,新業務想用不敢用;

  • 入職1個月,業務遷移MongoDB到公司其他數據庫,MongoDB總集羣數減少15%。

 

  我做了啥?

 

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

  • 總結各個集羣抖動原因及優化方法,公司內部分享;

  • 收集公司所有MongoDB集羣對應用戶,成立MongoDB用戶羣。

 

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

 

  • 之前準備遷移到MySQL的幾個核心業務繼續使用MongoDB;

  • 對應業務負責人開始考慮把其他大數據量集羣遷移到MongoDB;

  • 越來越多的未使用過MongoDB的部門開始使用MongoDB。

 

  入職1年後,MongoDB相關數據增長

 

  • 總集羣數增長比例:> 700%

  • 總數據量增長比例:> 2000%

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

  • MongoDB用戶羣用戶數增長比例:> 800%

 

  總結

 

  • MongoDB贏得用戶信任原因總結:口碑

 

二、當前國內對MongoDB誤解(丟數據、不安全、難維護)?

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

 

  • 誤解一:丟數據;

  • 誤解二:不安全,網上一堆說MongoDB被黑客攻擊,截圖一堆新聞;

  • 誤解三: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倍提升優化實踐(高版本)

 

 

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

 

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

  • 遷移步驟:

1. configServer-master選出需要遷移的塊;

2. config.locks表中id=test這條記錄上鎖;

3.通知需要遷移的源分片開始遷移;

4. 遷移完成後延時10s,重複1-4步驟實現持續性chunk數據遷移。

 

2)並行遷移步驟:

 

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

 

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

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

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

  • 等待S個chunk遷移完成;

  • 遷移完成後延時10秒;

  • 重複步驟1-5。

 

3)並行遷移瓶頸:

 

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

  • configServer異步通知源分片中的S個分片同時開始遷移數據到目的分片,任一個chunk遷移慢會拖累整個遷移過程;

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

 

4)優化方法:

 

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

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

  • 延時放到各自分片遷移邏輯裏面控制,不受全局延時控制;

  • 分片延時可配置,支持實時動態命令行調整。

 

六、性能優化案例

 

  案例1.千億級數據量MongoDB集羣性能數倍提升優化實踐-背景

 

1)業務背景:

 

  • 核心元數據;

  • 數據量千億級;

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

  • 高峯期讀寫流量百萬級;

  • 時延敏感;

  • 數據增長快,不定期擴容;

  • 同城多活集羣。

 

2)優化策略1:部署及使用方式優化

 

  • 預分片,寫入負載均衡;

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

  • 讀寫分離,讀從優先;

  • enableMajorityReadConcern關閉,有性能損耗。

 

 

3)優化策略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淘汰線程數加快髒數據淘汰,避免用戶請求線程進行髒數據淘汰。

 

4)優化策略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定期更新優化爲散列到不同時間點進行更新。

 

5)優化策略4:sharding集羣system.session優化

 

該優化總體思路:

 

  • 之前代理集中式更新單個分片,優化爲散列到不同時間點更新多個分片;

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

 

6)優化策略5:tcmalloc內存優化

 

  • db.serverStatus().tcmalloc監控發現部分mongod實例pageheap、內存碎片等消耗過高。通過系統調用分析得出:內存碎片率、pageheap過高,會引起分配內存過程變慢,引起集羣性能嚴重下降。

 

該優化總體思路:

 

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

 

  案例2.萬億級數據量MongoDB集羣性能數倍提升優化實踐

 

1)業務背景:

 

  • 集羣存儲離線數據;

  • 集羣總數據量萬億級;

  • 前期主要爲數據寫入,要求萬億級數據幾周內儘快全部寫入集羣;

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

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

 

2)優化策略1:基礎性優化

 

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

 

3)優化策略2:

 

存儲模型優化前狀況

 

優化前數據模型結構如下:

 

 

1.{  

2.    "_id": ObjectId("5fh2ebd18856960dbac31abc"),  

3.    "characteristic": "xxxx",  

4.    "key1": "***",  

5.    ......  

6.    "keyn": "***",  

7.}  

 

  • 以上爲單條數據的數據模型,該集羣總數據量萬億級;

  • 數十萬條數據擁有同樣的characteristic特性,總特性數總計數百萬個;

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

 

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

 

 

第一輪數據存儲模型優化:

 

 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.    ]  

17.} 

 

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

 

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

 

  • 通過$addToSet方式向group數組中去重追加數據,數據長度越來越長,磁盤IO壓力越來越大、寫性能成爲新的瓶頸。

 

 

第二輪數據存儲模型優化:

 

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.    ]  

17.} 

 

 

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服務器節省優化實踐

 

1)遷移背景:

 

  • 需要遷移的數據量數千億級;

  • 源集羣磁盤緊張,業務寫入快,需要快速完成數據遷移;

  • 源集羣數據存儲於高io ssd服務器;

  • 業務對性能沒太高要求;

  • 目的MongoDB集羣採用低io 大容量sata盤。

 

2)遷移難點:如何快速完成數據遷移?

 

 

3)瓶頸點:

 

  • 由於目的集羣爲低io大容量sata盤,遷移太慢,源集羣磁盤有寫滿風險。

 

 

4)優化策略:

 

  • 同步數據到大容量SSD中轉集羣;

  • 拷貝中轉集羣數據到目標大容量SATA盤服務器;

  • 加載數據。

 

5)成本節省:

 

  • MongoDB默認的snappy壓縮算法壓縮比約爲2.2-3.5倍;

  • zlib壓縮算法壓縮比約爲4.5-7.5倍(本次遷移採用zlib高壓縮算法)。

 

6)千億級數據遷移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內核踩坑、誤操作等,甚至出現過同一個核心業務幾次抖動。

 

本次分享中集羣優化只列舉了主要的優化過程,實際優化過程比本次分享內容更加複雜,集羣更多優化細節及數十例典型踩坑過程將在今後逐步分享出來。

 

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

 

十、2021規劃

 

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

 

MongoDB擁有天然的高可用、分佈式擴縮容、機房多活容災、完善的負載均衡及一致性策略等功能,可以做到最少人力成本滿足業務快速增長的需求,個人認爲MongoDB絕對是國內互聯網企業對分佈式數據庫需求的一個值得信賴的選擇。 

 

>>>>

Q&A

 

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

 

A1:《MongoDB》常用性能分析主要如下:

 

1.1 MongoDB自帶性能分析工具

 

1)MongoDB官方對外工具mongostat

 

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

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

 

 

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

 

  • dirty:存儲引擎髒數據比例,默認該值爲5%的時候,wiredtiger存儲引擎自帶的evict現成開始選擇髒數據page淘汰到磁盤;如果該值達到20%,客戶端請求對應MongoDB處理現成將會選擇髒數據page淘汰到磁盤,等page淘汰騰出內存空間後,纔會處理客戶端請求的DB訪問,所以如果閥值達到20%客戶端訪問將會變慢;

  • used:存儲引擎cacheSize配置佔用百分比,如果配置cacheSize=10G,存儲引擎實際使用了7G,則used贊比爲70%。當該統計值達到80%,evict線程將會觸發選擇漲數據淘汰,如果這個佔比提高到95%,用戶請求線程將會觸發淘汰,客戶端請求將會變慢;

  • qrw arw:等待隊列數,如果該值越大,說明會引起客戶端請求排隊處理。一般該值會再dirty佔比超過20%,used佔比過高超過95%,或者磁盤IO慢會出現;

  • vsize res:虛擬內存和物理內存真實佔用,如果vsize過高,遠遠超過res,或者res過高,遠遠超過cachesize配置,則說明內存碎片,pageheap等問題,這時候可以通過加速tcmalloc內存釋放速率來解決問題。

 

2)慢日誌分析

 

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

 

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

   

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

 

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

 

 

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

 

  • 找出文件末尾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

 

3)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)})

 

4)節點存儲引擎監控信息

 

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

 

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

 

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

https://github.com/y123456yz/reading-and-annotate-wiredtiger-3.0.0

 

1.2 操作系統性能瓶頸分析

 

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

 

1.3 開源MongoDB詳細監控套記

 

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

Grafana+Prometheus+node_exporter+mongodb_exporter

 

  • 服務端組件:

Prometheus #服務端

Grafana #前端展示

 

  • 客戶端組件:

node_exporter

mongodb_exporter

 

Q2:會話加標籤是怎麼指定服務器?

 

A2:舉一個例子形象說明:我們把用戶分爲三組,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'。

 

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

 

Q3:髒數據比例多少算高?

 

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

 

 

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

 

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

 

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

 

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

 

Q5:比如想定位詳細的慢查詢呢?

  

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

 

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

 

A6:我們用mysql_fdw進行遷移,這也是很方便的一種方式。關於遷移的注意事項,除了數據類型是適配,需要注意PG一定要使用UTF8編碼。另外PG不支持\0000這個特殊的Unicode字符。當然這個字符也沒是什麼實際意義,主要是有一些應用系統數據入庫不規範,在以前的DB2或MySQL庫裏不小心寫入的這個字符,後面遷移到PG的時候就需要規範化,把這個非法字符刪掉。  

 

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

 

  • db.serverStatus().opLatencies監控mongod實例時延 ;

  • 如果由運維研發能力,可以自己收集時延展示,如果沒有。則可以藉助開源工具系統實現,參考《1.3 開源MongoDB詳細監控套記》;

  • 充分利用mongostat監控集羣所有節點實時髒數據、隊列、內存信息;

  • 參考《1.1 MongoDB自帶性能分析工具》;

  • 慢日誌分析。

 

參考問題5的回答。

 

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

 

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

 

  • 賬號鑑權認證,一個庫一個賬號;

  • readWrite權限去除刪庫、刪表等危險操作權限;

  • 不同業務不混用同一個集羣;

  • 啓用黑白名單功能;

  • 我司MongoDB內核增加審計、流量控制、危險操作控制等功能(注:部分功能是MongoDB企業級功能,需要付費,可以使用percona mongodb版本);

  • 數據定期備份,我司MongoDB內核增加有熱備功能。

 

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

   

Q8:MySQL和MongoDB雙寫的話怎麼保證事務呢?

 

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

 

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

https://zhuanlan.zhihu.com/p/343524817

 

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

 

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

 

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

 

Q10:對分片鍵設計要求高嗎?

 

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

 

1)首先需要考慮集羣部署是否需要分片?

 

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

 

2)片建選擇原則?

 

片建選擇原則如下: 

 

  • 保證數據儘量離散;

  • 儘量保證更新和查詢到同一個分片(如果同一次更新或者查詢到多個分片,只要任何一個分片慢,該操作都會慢;同時部分查詢會進一步加劇代理聚合負擔)。

 

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

 

Q11:大表分片後,寫表還是會跨機房嗎?

 

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

 

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

 

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

 

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

 

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

 

1)磁盤容量限制

 

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

 

2)流量超過閥值

 

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

 

3)CPU閥值

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

  • 同一個表數據字段各不相同,建議同一個表所有數據的字段保持一致,即使新數據增加字段也需要在老數據中增加該字段,保持字段一致;

  • 同一個表的數據的字段控制在50個KV以內,這樣對應更新、查詢等性能分析有利,減少磁盤IO消耗;

  • 如果數據字段過多,查詢的時候不要返回所有字段,只獲取對本次查詢有用的字段,減少忘了IO開銷;

  • 數組別亂用,數組中的文檔保持格式統一;

  • 數組中的子文檔如果需要查詢指定字段,一定記得對數組中嵌套的字段添加子索引;

  • 數組字段中的文檔一定要控制在一定範圍,避免該數組過大,數組過大有遍歷、磁盤IO過高等問題;

  • 嵌套子文檔層數不宜過多;

  • .......

 

Q16:現在有多大數據量?

 

A16:公司內部MongoDB規模已經很大了,總體超過萬億級,具體數據不太方便透露。

 

Q17:你們對這個大數據平臺有多少開發人員?

 

A17:我們研發+運維人員很少,MongoDB擁有天然的高可用、分佈式擴縮容、機房多活容災等功能,保證了可以用很少的人力來滿足公司快速增長的業務需求。

 

獲取本期PPT 請添加右側二維碼微信

↓點這裏可回看本期直播

閱讀原文


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章