1. 程式人生 > >MySQL VS MongoDB 你會如何選擇?

MySQL VS MongoDB 你會如何選擇?

1. 概述

1.1 背景

資料庫幾乎是線上業務架構裡的核心服務,在海量資料環境下,資料庫的讀寫效率直接影響著一款產品的體驗,因此從一開始選擇一款適合適的資料庫就顯得尤為重要。

目前主流的開源方案中,最火的莫過於是MySQL和MongoDB了。而長期以來在當今資料庫市場上,MySQL無疑是佔有一席之地,作為一個開源的關係型資料庫,MySQL被大量應用在各大網站後臺,哪怕是我們的主流遊戲生產環境中。而存在於另外一個世界的非關係型資料庫MongoDB,卻很不安分,混入了這場平靜,來一個“搶奪戰”。

相信大多數人都知道MongoDB是一種檔案導向的資料庫管理系統,屬於一種通稱為NoSQL的資料庫,是10gen公司旗下的開源產品,其內部資料儲存的方式與傳統的關係型資料有很大差別。它是一種新型的革命式的資料庫設計方式,不過它不是為了取代傳統的關係型資料庫而被設計的,它們分別代表了不同的資料庫設計思路。

那到底我們該選擇MySQL 還是 MongoDB呢?如果你的業務必須依賴事務關係的話,那選MySQL無疑了,但是有時候我們需要做一些複雜的聚合或需要靈活存取的場景,那麼選哪一個更好,則需要認真評估了。為了讓大家在一開始選擇資料庫時有個參考資料,我們對MongoDB 3.0.7和MySQL 5.5.40分別在大資料(百萬級~千萬級)環境下的平均時延、吞吐量進行了研究對比。

1.2 工具簡介

sysbench是一個模組化的、跨平臺、多執行緒基準測試工具,主要用於評估測試各種不同系統引數下的資料庫負載情況。而ycsb(Yahoo! Cloud Serving Benchmark)則是雅虎開源的一款通用的、針對各類NoSQL產品的效能測試工具。

接下來我們簡單的介紹一下用於本次研究對比的壓測工具:

資料庫壓測工具

2. 安裝說明

2.1 基礎環境

ycsb工程依賴Java、maven,有maven環境後就可以直接在ycsb根目錄下執行package任務。而sysbench編譯安裝需要automake,於是:

#yum -y install mysql-devel automake libtool git wget unzip python-setuptools java-devel
#easy_install argparse
#wget http://ftp.heanet.ie/mirrors/www.apache.org/dist/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz
#tar xf apache-maven-3.1.1-bin.tar.gz -C /usr/local/
#cd /usr/local && ln -s apache-maven-* maven
# echo “export PATH=/usr/local/maven/bin:\$PATH” >> /etc/profile
# source /etc/profile

2.2 下載並安裝

2.2.1 sysbench

我們選擇最新版的sysbench 0.5版本來測試資料庫效能,該版本優化了oltp的lua指令碼測試和實時顯示功能。sysbench預設支援MySQL,如果需要測試Oracle/PostgreSQL,則在configure時需要加上–with-oracle或者–with-pgsql引數。

# wget -O sysbench-0.5.zip https://codeload.github.com/akopytov/sysbench/zip/0.5
#unzip sysbench-0.5.zip
# cd sysbench-0.5
#chmod +x autogen.sh
#./autogen.sh
#./configure –prefix=/usr/local/sysbench –with-mysql –with-mysql-includes=/usr/local/mysql/include –with-mysql-libs=/usr/local/mysql/lib
#make && make install
# echo “export PATH=/usr/local/maven/bin:/usr/local/sysbench/bin:\$PATH” >> /etc/profile
# source /etc/profile

檢查是否安裝成功:

2.2.2 ycsb

我們同樣選擇最新版的ycsb來進行測試並使用mvn編譯安裝。

#cd /usr/local/ && git clone https://github.com/brianfrankcooper/YCSB.git
# ln -s YCSB ycsb
#cd ycsb && mvn -pl com.yahoo.ycsb:mongodb-binding -am clean package
#echo “export PATH=/usr/local/ycsb/bin:/usr/local/maven/bin:/usr/local/sysbench/bin:\$PATH” >> /etc/profile
#source /etc/profile

檢查是否安裝成功:

3. 使用說明

3.1 基礎環境
為了更好地理解後面的測試過程,我們先對sysbench和ycsb的使用引數進行詳細說明。

3.1.1 sysbench

#./bin/sysbench –test= [options]…

3.1.1 sysbench
(1) options引數

(2) command引數

3.1.1 ycsb

#./bin/ycsb command database [options]

(1) options引數

(2) command引數

4. 效能評估

4.1 測試目的

在大資料環境下,對比MySQL 5.5.40與MongoDB 3.0.7的只讀、只更新、只插入,混合模式(讀:寫=3:7)下的平均時延、吞吐量。

4.2 測試環境

  • Dell PowerEdge R410
  • RAM:64G
  • Kernel: 2.6.32
  • MongoDB:3.0.7
  • MySQL:5.5.40
  • Linux OS:CentOS release 6.5 x86_64
  • CPU:Intel(R) Xeon(R) CPU X5650 @2.67GHz / 24 cores

4.3 測試過程

測試的資料量變數名假定為size,分別取值為200w、400w、600w、800w、1000w。

每次使用單程序對單個表壓測,每個表均含有4個欄位,每次壓測時間不超過30分鐘。

為了讓資料更加符合我們想要的結果,每輪測試完成後,我們都重啟mysqld和mongodb例項,並且用下面的方法刪除系統cache,釋放swap。

#sync — 將髒資料重新整理到磁碟
#echo 3 > /proc/sys/vm/drop_caches — 清除OS Cache
#swapoff -a && swapon -a

4.3.1 sysbench

4.3.1.1 準備工作

(1) 建立測試庫

mysql> drop database if exists sysbench_test;
mysql> create database if not exists sysbench_test character set utf8 collate utf8_general_ci;

(2) 查看錶結構

`id` int(10) unsigned NOT NULL auto_increment,
`k` int(10) unsigned NOT NULL default ‘0’,
`c` char(120) NOT NULL default ”,
`pad` char(60) NOT NULL default ”,
PRIMARY KEY (`id`),
KEY `k` (`k`));

4.3.1.2 只讀測試

測試命令:

# ./bin/sysbench –db-driver=mysql –test=oltp.lua –num-threads=1 \
–oltp_tables_count=1 –oltp-table-size=${size} –report-interval=10 \
–oltp-dist-type=uniform –rand-init=on –max-requests=0 \
–oltp-test-mode=nontrx –oltp-nontrx-mode=select \
–oltp-read-only=on –oltp-skip-trx=on –mysql-table-engine=innodb \
–mysql-socket=/tmp/mysql.sock –mysql-user=root –mysql-host=localhost \
–mysql-password=`cat /data/save/mysql_root` –mysql-port=3306 \
–mysql-db=sysbench_test [ prepare | run | cleanup ]

4.3.1.3 只更新測試

測試命令:

#./bin/sysbench –db-driver=mysql –test=./share/sysbench/update_index.lua \
–num-threads=1 –oltp_tables_count=1 –oltp-table-size=${size} –report-interval=10 \
–oltp-dist-type=uniform –rand-init=on –max-requests=0 \
–oltp-read-only=off –mysql-table-engine=innodb –mysql-socket=/tmp/mysql.sock \
–mysql-user=root –mysql-host=localhost –mysql-password=`cat /data/save/mysql_root` \
–mysql-port=3306 –mysql-db=sysbench_test [ prepare | –max-time=1800 run | cleanup ]

4.3.1.4 只插入測試

測試命令:

#./bin/sysbench –db-driver=mysql –test=./share/sysbench/insert.lua –num-threads=1 \
–oltp_tables_count=1 –oltp-table-size=${size} –report-interval=10 \
–oltp-dist-type=uniform –rand-init=on –max-requests=0 –oltp-read-only=off \
–mysql-table-engine=innodb –mysql-socket=/tmp/mysql.sock –mysql-user=root \
–mysql-host=localhost –mysql-password=`cat /data/save/mysql_root` –mysql-port=3306 \
–mysql-db=sysbench_test [ prepare | –max-time=1800 run | cleanup ]

4.3.1.5 混合模式測試

測試命令:

#./bin/sysbench –test=./share/sysbench/oltp.lua –mysql-host=localhost –mysql-port=3306 \
–mysql-user=root –mysql-password=`cat /data/save/mysql_root` \
–mysql-db=sysbench_test –mysql-table-engine=innodb \
–oltp-table-size=${size} –report-interval=10 –rand-init=on –max-requests=0 \
–oltp-read-only=off –oltp-point-selects=$((size/3)) –oltp-point-inserts=$((size/3)) \
–oltp-index-updates=$((size/3)) –num-threads=1 –mysql-ignore-errors=all \
–oltp-skip-trx=off –oltp_tables_count=1 [ prepare | –max-time=1800 run | cleanup ]

引數含義請參考上面的使用說明章節。

4.3.2 ycsb

4.3.2.1 準備工作

編輯workload檔案,分別修改readproportion、updateproportion、insertproportion為相應的值並分別命名為workload_select、workload_update、workload_insert、workload_complex比如只讀測試workload_select檔案內容:

workload=com.yahoo.ycsb.workloads.CoreWorkload
recordcount=${size}
operationcount=${size}
insertstart=0
fieldcount=4
fieldlength=100
readallfields=true
writeallfields=false
fieldlengthdistribution=zipfian
readproportion=1
updateproportion=0
insertproportion=0
requestdistribution=zipfian
table=ycsb_test
maxexecutiontime=1800

4.3.2.2 只讀測試

測試命令:

./bin/ycsb load mongodb -s -threads 1 -P workloads/workload_select
./bin/ycsb run mongodb -s -threads 1 -P workloads/workload_select

4.3.2.3 只更新測試

測試命令:

./bin/ycsb load mongodb -s -threads 1 -P workloads/workload_update
./bin/ycsb run mongodb -s -threads 1 -P workloads/workload_update

4.3.2.4 只插入測試

測試命令:

./bin/ycsb load mongodb -s -threads 1 -P workloads/workload_insert
./bin/ycsb run mongodb -s -threads 1 -P workloads/workload_insert

4.3.2.5 混合模式測試

測試命令:

./bin/ycsb load mongodb -s -threads 1 -P workloads/workload_complex
./bin/ycsb run mongodb -s -threads 1 -P workloads/workload_complex

引數含義請參考上面的使用說明章節。

4.4 測試結果

圖4.1 《吞吐量:單位時間內的運算元》

圖4.2 《平均時延:每次操作所消耗的平均時間》

PS:MongoDB在讀取的場景有著天生的優勢,每秒的Select運算元遠遠超越MySQL。

圖4.3 《吞吐量:單位時間內的運算元》

圖4.4 《平均時延:每次操作所消耗的平均時間》

PS:上圖看出MongoDB在200W記錄的時候,效能較接近MySQL,但是隨著資料量越大效能劇降,而MySQL卻相對較為穩定。同時MySQL的效能要好於MongoDB 2倍。

圖4.5 《吞吐量:單位時間內的運算元》

圖4.6 《平均時延:每次操作所消耗的平均時間》

PS:上圖中MongoDB在300W記錄前效能要優於MySQL,但是隨著資料量越大效能急劇下降,到1000W記錄時已經無法與MySQL競爭了。這裡也反應出MySQL不愧是優秀的資料庫,非常穩定,而MongoDB很不穩定。另外,以上測試中MongoDB都是指定了_id插入的,其效率比不指定_id相差很遠。這是因為它的_id通過計算機特徵值、時間、程序ID與隨機數來確保生成的_id是唯一的,每次插入都需要檢查該_id是否存在,所以嚴重影響其效率。當然如果業務允許,你也可以不指定_id插入,提高效能。

圖4.7 《吞吐量:單位時間內的運算元》

圖4.8 《平均時延:每次操作所消耗的平均時間》

PS:以上混合模式是主要模擬了遊戲的實際場景(寫為主),結合前面的分步測試結果,這裡MongoDB比MySQL效能相差至少4倍,會不會感到理所當然?

5. 分析總結

通過以上測試發現MySQL和MongoDB各有優勢,因此我們給出如下建議作為參考,具體選擇哪款資料庫請根據自身業務場景來決定。

(1) 相比較MySQL,MongoDB資料庫更適合那些讀作業較重的任務模型。MongoDB能充分利用機器的記憶體資源。如果機器的記憶體資源豐富的話,MongoDB的查詢效率會快很多。

(2) 相比MongoDB,MySQL資料庫更適合插入、更新為主的任務模型,其效率相比於MongoDB優勢非常明顯。

(3) 在帶”_id”插入資料的時候,MongoDB的插入效率其實並不高。如果想充分利用MongoDB效能的話,推薦採取不帶”_id”的插入方式,然後對相關欄位作索引來查詢。

(4) MongoDB適合那些對資料庫具體資料格式不明確或者資料庫資料格式經常變化的需求模型,而且對開發者十分友好。

(5) 穩定性方面,MongoDB不如MySQL,MySQL不愧是一種非常穩定的資料庫,無論在指定主鍵還是在不指定主鍵插入的情況下,其效率都差不了太多, 其穩定性還是毋庸置疑。

(6) 事務支援方面,MySQL佔絕對優勢,MongoDB對事務關係支援薄弱,這也是所有NoSQL資料庫共同的缺陷,不過NoSQL並不是為了事務關係而設計的,具體應用還是很需求。

結合我們的遊戲業務場景來看,選用MySQL無疑是最理想的選擇。但是有時候我們的遊戲資料分析後臺需要做很大量的統計、展示,這對讀取效能要求較高,如果同時能夠結合MongoDB的來提升讀取效能可能更有利於業務的擴充套件性。主要是把使用者主資料寫到MySQL,使用者日誌類資料寫到MongoDB,然後遊戲資料分析後臺直接讀取MongoDB做統計分析工作。

6. 參考

1) https://github.com/brianfrankcooper/YCSB
2) http://seanlook.com/2016/03/28/mysql-sysbench

原文來自微信公眾號:運維軍團