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.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.1 基础环境
为了更好地理解后面的测试过程,我们先对sysbench和ycsb的使用参数进行详细说明。
3.1.1 sysbench
#./bin/sysbench --test=<test-name> [options]... <command>
3.1.1 sysbench
(1) options参数
(2) command参数
3.1.1 ycsb
#./bin/ycsb command database [options]
(1) options参数
(2) command参数
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倍,会不会感到理所当然?
通过以上测试发现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做统计分析工作。
1) https://github.com/brianfrankcooper/YCSB
2) http://seanlook.com/2016/03/28/mysql-sysbench
END
全中国只有不到1% 的人关注了运维军团
你是个有眼光的人!
(由于交流群人数已超100人,需要进群的小伙伴可以添加运维小编的微信:qq834775039)
如果你喜欢我们的文章,请转发到朋友圈
公众号
ywjtshare
运维军团
专注运维技术与传承,分享丰富原创干货