天天看點

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

一、前言

為什麼調研MongoDB?

下圖是DB-Engines2017年8月資料庫的排名統計,可以看到MongoDB總排名在第5,在Nosql資料庫中排名第1。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

優點:

1)社群活躍,使用者較多,應用廣泛。

2)MongoDB在記憶體充足的情況下資料都放入記憶體且有完整的索引支援,查詢效率較高。

3)MongoDB的分片機制,支援海量資料的存儲和擴充。

缺點:

1)不支援事務

2)不支援join、複雜查詢

初步調研下來,MongoDB具備我們需要的特性,而缺點不影響我們的應用場景,故接下來我們就開始做實際的性能壓測。

二、壓測性能對比

1、準備條件

1)Mysql 、MongoDB資料庫所在伺服器硬體環境

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

2)最新的資料庫版本

MongoDB server version: 3.4.5

MongoDB client version: mongo-java-driver-2.14.3

Mysql server version:5.6.34

Mysql connector version: mysql-connector-java-6.0.6

MongoDB使用的儲存引擎wiredTiger

Mysql使用的儲存引擎InnoDB

3)資料庫表結構及索引

MongoDB索引為dateTime 且是唯一索引。我們實際測試使用的MongoDB資料結構及字段如圖所示。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

Mysql索引為DATETIME,PARTNER_ID,GOODS_ID,SCOPE且是唯一索引。我們實際測試使用的Mysql資料結構及字段如圖所示。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

sql語句根據datetime字段進行時間範圍的查詢

4)連接配接池最大連接配接數都設定為200個。sql語句調到最優

2、百萬、千萬級别的下不同查詢量不同并發量的壓測結果

資料庫表中記錄數總量在百萬、千萬級别的壓測資料及結果如表所示。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

3、億級别的下不同查詢量不同并發量的壓測結果

資料庫表中記錄數總量在億級别的壓測資料及結果如表所示。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

壓測結果分析:

1)當每次查詢資料量在500條時,無論表中資料總量千萬或者億級别,Mysql和MongoDB在100線程并發的情況下查詢性能相當,表現良好,平均響應時間在500ms以内,TPS在230左右。

2)當每次查詢資料量在5000條時,表中資料總量為千萬級别時,MongoDB在50線程并發情況下查詢性能不及Mysql 的一半,100線程并發情況查詢性能都很差,平均響應時間在4500ms左右,表中資料總量為億級别時,在50個及以上的并發情況下,MongoDB和Mysql性能都較差。

在本案例簡單資料模型下的時間範圍内的等值查詢應用場景下,MongoDB在高并發條件下的大資料量查詢性能并沒有比Mysql更好。另外還有一點需要注意的是,在本案例中,資料總量由百萬級别到千萬級别再到億級别的變化過程中,對于查詢性能的影響都不是很大,但對于查詢資料量的數倍增長卻十分敏感,是以在考量資料庫查詢性能的時候,也要重點考量應用的單次查詢量的需求。

盡管MongoDB在我們的這種應用場景下并沒有達到我們預期的性能,我們也簡單的調研了下Mysql和MongoDB對于記憶體的使用機制以及一些可能影響查詢效率的内部配置。

三、Mysql和MongoDB記憶體結構

1、InnoDb記憶體使用機制

Innodb體系結構如圖所示。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

壓測的Mysql使用的是Innodb存儲引擎,Innodb關于查詢效率有影響的兩個比較重要的參數分别是innodb_buffer_pool_size,innodb_read_ahead_threshold。

innodb_buffer_pool_size指的是Innodb緩沖池的大小,本例中Innodb緩沖池大小為20G,該參數的大小可通過指令指定innodb_buffer_pool_size 20G。緩沖池使用改進的LRU算法進行管理,維護一個LRU清單、一個FREE清單,FREE清單存放空閑頁,資料庫啟動時LRU清單是空的,當需要從緩沖池分頁時,首先從FREE清單查找空閑頁,有則放入LRU清單,否則LRU執行淘汰,淘汰尾部的頁配置設定給新頁。

innodb_read_ahead_threshold相對應的是資料預加載機制,innodb_read_ahead_threshold 30表示的是如果一個extent中的被順序讀取的page超過或者等于該參數變量的,Innodb将會異步的将下一個extent讀取到buffer pool中,比如該參數的值為30,那麼當該extent中有30個pages被sequentially的讀取,則會觸發innodb linear預讀,将下一個extent讀到記憶體中;在沒有該變量之前,當通路到extent的最後一個page的時候,Innodb會決定是否将下一個extent放入到buffer pool中;可以在Mysql服務端通過show innodb status中的Pages read ahead和evicted without access兩個值來觀察預讀的情況:

Innodb_buffer_pool_read_ahead:表示通過預讀請求到buffer pool的pages;

Innodb_buffer_pool_read_ahead_evicted:表示由于請求到buffer pool中沒有被通路,而驅逐出記憶體的頁數。

可以看出來,Mysql的緩沖池機制是能充分利用記憶體且有預加載機制,在某些條件下目标資料完全在記憶體中,也能夠具備非常好的查詢性能。

2、MongoDB的存儲結構及資料模型

1)本例中MongoDB使用的儲存引擎是WiredTiger,WiredTiger的結構如圖所示。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

WiredTiger Cache的實作原理圖如圖所示。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

Wiredtiger的Cache采用Btree的方式組織,每個Btree節點為一個page,root page是btree的根節點,internal page是btree的中間索引節點,leaf page是真正存儲資料的葉子節點;btree的資料以page為機關按需從磁盤加載或寫入磁盤。

可以通過在配置檔案中指定storage.wiredTiger.engineConfig.cacheSizeGB參數設定引擎使用的記憶體量。此記憶體用于緩存工作集資料(索引、namespace,未送出的write,query緩沖等)。

2)資料模型

内嵌

MongoDB的文檔是無模式的,是以可以支援各種資料結構,内嵌模型也叫做非規格化模型(denormalized)。在MongoDB中,一組相關的資料可以是一個文檔,也可以是組成文檔的一部分。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

内嵌類型支援一組相關的資料存儲在一個文檔中,這樣的好處就是,應用程式可以通過比較少的的查詢和更新操作來完成一些正常的資料的查詢和更新工作。

當遇到以下情況的時候,我們應該考慮使用内嵌類型:

如果資料關系是一種一對一的包含關系,例如下面的文檔,每個人都有一個contact字段來描述這個人的聯系方式。像這種一對一的關系,使用内嵌類型可以很友善的進行資料的查詢和更新。

{  ”_id”: ,  ”name”: “Wilber”,  ”contact”: {     “phone”: “12345678”,     “email”: “[email protected]”   }}
           

如果資料的關系是一對多,那麼也可以考慮使用内嵌模型。例如下面的文檔,用posts字段記錄所有使用者釋出的部落格。在這中情況中,如果應用程式會經常通過使用者名字段來查詢改使用者釋出的部落格資訊。那麼,把posts作為内嵌字段會是一個比較好的選擇,這樣就可以減少很多查詢的操作。

{   “_id”: ,   “name”: “Wilber”,   “contact”: {    ”phone”: “12345678”,    ”email”: “[email protected]”  },  ”posts”: [  {    ”title”: “Indexes in MongoDB”,    ”created”: “12/01/2014”,    ”link”: “www.linuxidc.com”  },  {    ”title”: “Replication in MongoDB”,    ”created”: “12/02/2014”,    ”link”: “www.linuxidc.com”  },  {    ”title”: “Sharding in MongoDB”,    ”created”: “12/03/2014”,    ”link”: “www.linuxidc.com”  } ]}
           

根據上面的描述可以看出,内嵌模型可以給應用程式提供很好的資料查詢性能,因為基于内嵌模型,可以通過一次資料庫操作得到所有相關的資料。同時,内嵌模型可以使資料更新操作變成一個原子寫操作。然而,内嵌模型也可能引入一些問題,比如說文檔會越來越大,這樣就可能會影響資料庫寫操作的性能,還可能會産生資料碎片(data fragmentation)。

引用

相對于嵌入模型,引用模型又稱規格化模型(Normalized data models),通過引用的方式來表示資料之間的關系。這裡同樣使用來自MongoDB文檔中的圖檔,在這個模型中,把contact和access從user中移出,并通過user_id作為索引來表示他們之間的聯系。

mongodb如何寫入圖檔_Mysql和MongoDB性能對比及應用場景分析

當我們遇到以下情況的時候,就可以考慮使用引用模型了:

使用内嵌模型往往會帶來資料的備援,卻可以提升資料查詢的效率。但是,當應用程式基本上不通過内嵌模型查詢,或者說查詢效率的提升不足以彌補資料備援帶來的問題時,我們就應該考慮引用模型了。

當需要實作複雜的多對多關系的時候,可以考慮引用模型。比如我們熟知的例子,學生-課程-老師關系,如果用引用模型來實作三者的關系,可能會比内嵌模型更清晰直覺,同時會減少很多備援資料。

當需要實作複雜的樹形關系的時候,可以考慮引用模型。

四、應用場景分析

1、MongoDB的應用場景

1)表結構不明确且資料不斷變大

MongoDB是非結構化文檔資料庫,擴充字段很容易且不會影響原有資料。内容管理或者部落格平台等,例如圈子系統,存儲使用者評論之類的。

2)更高的寫入負載

MongoDB側重高資料寫入的性能,而非事務安全,适合業務系統中有大量“低價值”資料的場景。本身存的就是json格式資料。例如做日志系統。

3)資料量很大或者将來會變得很大

Mysql單表資料量達到5-10G時會出現明細的性能降級,需要做資料的水準和垂直拆分、庫的拆分完成擴充,MongoDB内建了sharding、很多資料分片的特性,容易水準擴充,比較好的适應大資料量增長的需求。

4)高可用性

自帶高可用,自動主從切換(副本集)

不适用的場景

1)MongoDB不支援事務操作,需要用到事務的應用建議不用MongoDB。

2)MongoDB目前不支援join操作,需要複雜查詢的應用也不建議使用MongoDB。

2、關系型資料庫和非關系型資料庫的應用場景對比

關系型資料庫适合存儲結構化資料,如使用者的帳号、位址:

1)這些資料通常需要做結構化查詢,比如join,這時候,關系型資料庫就要勝出一籌

2)這些資料的規模、增長的速度通常是可以預期的

3)事務性、一緻性

NoSQL适合存儲非結構化資料,如文章、評論:

1)這些資料通常用于模糊處理,如全文搜尋、機器學習

2)這些資料是海量的,而且增長的速度是難以預期的,

3)根據資料的特點,NoSQL資料庫通常具有無限(至少接近)伸縮性

4)按key擷取資料效率很高,但是對join或其他結構化查詢的支援就比較差