03.04 CTO之瞳-數據庫-MongoDB

MongoDB,常用的NoSql數據庫,在https://db-engines.com/en/ranking 裡被分類為文檔型數據庫。

本文從以下五個方面來了解MongoDB (和上一篇一樣,基礎操作請查詢官方文檔或者菜鳥教程)

  1. 使用場景
  2. 存儲引擎
  3. 性能測試
  4. 索引-B樹
  5. 分片與複製


1.使用場景


一個業務系統的搭建,什麼情況下用關係型數據庫MySql,又在什麼情況下用文檔型數據庫MongoDB呢?


在回答這個問題之前,先來了解一下MongoDB與關係型數據庫的幾個顯著區別。在MongoDB的自述中,抽取出個人認為重要的兩個點:

https://www.mongodb.com/nosql-explained


1. Dynamic Schemas:動態的數據結構


MySql需要先定義好一張表的字段,然後每個字段的值才能被插入;MongoDB不用預先定義字段和數據類型,可以隨時動態插入新增的字段。對於一個不斷變化發展的業務,數據定義也必然是變化發展的,因此一個靈活可變的數據結構才能較好的應對。比如,社交類軟件,每一次的改版,後臺的數據結構都有相應的變化。


2. Auto-sharding:自動分片


數據庫層面原生的水平分庫分表方案,對於海量數據,不用人為的去做分庫分表操作。基本原理如下圖所示(圖片來自MongoDB官網)。

CTO之瞳-數據庫-MongoDB


基於以上兩個特點,不難看出在什麼情況下需要使用MongoDB。


  • 遇到經常變化的數據需求。產品今天提需求要支持每個用戶設定3個興趣愛好;明天起床覺得3這個數貌似不是自己的幸運數字啊,還是改為7個興趣愛好吧;後天老闆說我有8個愛好怎麼辦,產品又默默的改了需求。如果用MySql來存儲,相信DBA會默默的準備麻袋和棍棒。所以,一般不經常變的個人數據存在MySql裡,例如生日、姓名、籍貫,當然還有性別。而經常變化的數據通過userid關聯到MongoDB裡存儲,比如頭像、自我介紹、興趣愛好,可能、也許、應該還有婚姻狀況。
  • 海量數據,例如日誌。


其實MongoDB的使用場景,在官網的用戶案例裡已經給出了很多答案:


百度在什麼場景用MongoDB?信息,圖片分享,百度雲,百度地圖,社交論壇,用戶行為日誌。


奇虎呢?基於地理位置信息的移動搜索與結果分發,單點登錄信息的緩存(The user’s SSO session is cached in MongoDB for ultra-fast access. MongoDB supports millions of concurrent users, handling 30,000 operations per second and 1.8 billion queries daily. 關於性能在本篇第3部分中闡述),日誌分析平臺。


還有很多其他公司的應用實例,大家可以訪問下面這個鏈接獲取信息。

https://www.mongodb.com/mongodb-scale


最常用的幾個場景還是:文檔,LBS相關的地理位置信息,日誌。這幾個場景的共同特點:數據量大,需要經常查詢。


2.存儲引擎


MongoDB 4.x版本有兩個常用的存儲引擎(關於存儲引擎的概念,請參看上一篇文章 CTO之瞳-數據庫-MySql)


1. WiredTiger:默認引擎,也是社區版(免費版)唯一支持的引擎。


從下圖(圖片來自MongoDB官網)可以看出,WT引擎在內存中分了兩個緩存區域,一個是沒做數據壓縮的WT Cache,另一個是做了數據壓縮的FS Cache,查詢的順序是先去WT Cache,沒有命中再去FS Cache,最後再去磁盤;而存進磁盤的數據都是壓縮過的(默認壓縮)。


CTO之瞳-數據庫-MongoDB


2. In-Memory:企業版才支持的引擎


看名字就想象的出,所有的數據是存在內存中的,目的是為了避免硬盤I/O操作,提升性能。缺點也很明顯,一旦關機或重啟,所有數據都會丟失。看到這裡,始終想不明白In-Memory引擎的用途,直到看見了MongoDB的又一特性Replication(複製)才秒懂。


Replication類似於MySql Router機制。試想一下,如果把Master設為In-Memory模式,而數據持久化到Slave上,讀寫不經過硬盤,性能是何其的強勁;或者把一臺slave設為高頻數據的專用讀取源,比如用戶token,這個訪問性能也一定是槓槓的。猜想第1節裡奇虎案例提到的性能參數 (MongoDB supports millions of concurrent users, handling 30,000 operations per second and 1.8 billion queries daily),就是通過使用In-Memory引擎實現的。


對於In-Memory引擎的使用場景,在第5節-分片與複製裡再詳述。


3.性能測試


測試環境

MongoDB 4.2, Windwos社區版, WT engine

IDEA 2019

Windows10

i7-9700F, 8G內存, 東芝固態硬盤


代碼訪問路徑

https://gitlab.com/ctoeyes/mongodb


Database:test


Collection:WiredTiger


為了和上一篇MySql的測試結果比對,MongoDB的數據表設計如下


CTO之瞳-數據庫-MongoDB


實驗一:單線程連續插入5w條數據,數據和MySql測試案例保持一致。

實驗二:單線程連續查詢1w次,每次以_id列作為查詢條件(索引查詢)。

實驗三:單線程連續查詢1w次,每次以D列作為查詢條件(非索引查詢)。

實驗四:查看數據佔用空間大小。


實驗結果如下:

CTO之瞳-數據庫-MongoDB

CTO之瞳-數據庫-MongoDB


和上一篇MySql的結果比對如下:


CTO之瞳-數據庫-MongoDB


插入速度:MongoDB 4.2支持事務,與同樣支持事務處理的MySql-InnoDB比較,性能是較優的。


索引列查詢速度:MongoDB劣於MySql的兩個引擎,這可能與MongoDB的索引採用B樹的數據結構,而MySql索引採用B+樹數據結構有關,詳細的在下一節“索引-B樹”裡討論。


非索引列查詢速度,MongoDB也明顯慢於MySql,原因是否和MongoDB的數據默認壓縮後再存進磁盤有關?查詢前要解壓縮,有一定耗時。


佔用空間:MongoDB佔優。


4.索引-B樹


MongoDB索引採用的數據結構是B樹,以上一篇MySql裡相同的數據表為例,畫一下在MongoDB裡的數據結構。


CTO之瞳-數據庫-MongoDB


這些數據長成這樣:

CTO之瞳-數據庫-MongoDB

回顧上一篇MySql InnoDB引擎的B+樹

CTO之瞳-數據庫-MongoDB


可以發現兩者有兩個很明顯的區別


1. B+樹只有最下層的葉子節點保存數據,其他節點只保存關鍵字;而B樹每一層節點均保存數據。因此單一數據查詢,B+樹必須查到最下一層,而B樹只有在最壞情況下需要查詢到最下層。但第3節的實驗結果明明索引查詢是MySql的B+樹勝出,為什麼?個人猜測(未必正確),因為B+樹的非葉節點不保存數據,空間佔用小而被緩存在內存中,這樣訪問速度快;B樹的非葉節點因為保存數據,空間佔用大,有些存在磁盤裡,因而訪問速度慢。


2. B+樹每個相鄰的葉子節點有指針連接,而B樹沒有。因此範圍查詢,B+樹更有優勢。


思考:如果把Seat No也設為索引,數據應該長什麼樣(此時B+樹只有葉子節點保存數據的優勢就體現出來了)?


5.分片與複製


分片(Sharding)與複製(Replication)是MonoDB的兩種擴展方式,前文也提到過。


分片:實質是一種水平方向上的分庫分表,主要目的是為了增大容量、提升性能。第1節裡的示意圖一目瞭然,不再重複。


複製:類似於MySql Router,主要目的是數據備份、故障熱切換、讀寫分離。而第2節裡提到的In-Memory引擎用在複製模式裡,也可以幫助提升性能,看下圖(圖片來自MongoDB官網)。


CTO之瞳-數據庫-MongoDB


如果把右邊的secondary DB設為讀操作的默認DB,同時設定它使用In-Memory引擎,那麼一些常用的數據讀取會極大的提速。當然,這種情況下,需要保證最少兩臺secondary。為什麼呢?試想如果只有一臺secondary且是In-Memory模式,此時primary掛了,secondary自動接替為primary,然後它也宕機了,那麼primary切換後寫入的數據就會全部丟失。這時咋辦?趕緊回家捲鋪蓋跑路吧 ^^


如果把primary設為In-Memory模式,讀寫都通過primary,而數據持久化到secondary中,那麼讀寫性能都可以得到極大的提升。


瞭解了分片與複製機制後,想到一個問題,這兩種方式能不能放到一起用?也就是既要分表擴容,又要數據備份與故障熱切換。仔細看了下MondoDB的官網,其實已經給出了答案,看下圖(圖片來自MongoDB官網)。


CTO之瞳-數據庫-MongoDB


在介紹Sharding架構的圖中,已經明確標明瞭(紅色圈圈),每一臺Shard DB和Config Server都可以是一組Replica集群。


所以

  • 對於小型業務,一臺Primary+一臺Secondary的Replication方式即可滿足業務需求。
  • 對於中大型業務,採用Sharding + Replication的矩陣組合基本也可滿足業務需求。


MongoDB就聊到這裡,依然是九牛一毛,關鍵是思考;另外,官方文檔仔細看,有很多有價值的信息可以挖掘。


下一篇開始說說後端體系,坑中坑,頭大,現在覺得B坑的一年之約太樂觀了。


分享到:


相關文章: