基准测试(benchmark)是MySQL新手和专家都需要掌握的一项基本技能。简单地说,基准测试是针对系统设计的一种压力测试。通常的目标是为了掌握系统的行为。但也有其他原因,如重现某个系统状态,或者是做新硬件的可靠性测试。

2.1 为什么需要基准测试

因为基准测试是唯一方便有效的、可以学习系统在给定的工作负载下会发生什么的方法。基准测试可以观察系统在不同压力下的行为,评估系统的容量,掌握哪些是重要的变化,或者观察系统如何处理不同的数据。
基准测试可以完成以下工作,或者更多:

  • 验证基于系统的一些假设,确认这些假设是否符合实际情况。
  • 重现系统中的某些异常行为,以解决这些异常。
  • 测试系统当前的运行情况。
  • 模拟比当前系统更高的负载,以找出系统随着压力增加而可能遇到的扩展性瓶颈。
  • 规划未来的业务增长。
  • 测试应用适应可变环境的能力。
  • 证明新采购的设备是否配置正确。

    2.2 基准测试的策略

    基准测试有两种主要的策略:一是针对整个系统的整体测试,另外是单独测试MySQL。这两种策略也被称为集成式(full-stack)以及单组件式(single-component)基准测试。

    2.2.1 测试何种指标

    在开始执行甚至是在设计基准测试之前,需要先明确测试的目标。测试目标决定了选择什么样的测试工具和技术,以获得精确而有意义的测试结果。
  1. 吞吐量
  2. 响应时间或者延迟
  3. 并发性
  4. 可扩展性

    2.3 基准测试方法

    如何避免一些常见的错误,这些错误可能导致测试结果无用或者不精确:
  • 使用真实数据的子集而不是全集
  • 使用错误的数据分布
  • 在多用户场景中,只做单用户的测试
  • 在单服务器上测试分布式应用
  • 与真实用户行为不匹配
  • 忽略了系统预热(warm up)的过程
  • 使用默认的服务器配置
  • 测试时间太短

    2.3.1 设计和规划基准测试

    规划基准测试的第一步是提出问题并明确目标。然后决定是采用标准的基准测试,还是设计专用的测试。

    2.3.2 基准测试应该运行多长时间

    基准测试应该运行足够长的时间,这一点很重要。如果需要测试系统在稳定状态时的性能,那么当然需要在稳定状态下测试并观察。而如果系统有大量的数据和内存,要达到稳定状态可能需要非常长的时间

    2.3.3 获取系统性能和状态

    在执行基准测试时,需要尽可能多地收集被测试系统的信息。最好为基准测试建立一个目录,并且每执行一轮测试都创建单独的子目录,将测试结果、配置文件、测试指标、脚本和其他相关说明都保存在其中。
    下面是一个收集MySQL测试数据的shell脚本: ```shell

    !/bin/sh

INTERVAL=5 PREFIX=$INTERVAL-sec-status RUNFILE=/home/benchmarks/running mysql -e ‘SHOW GLOBAL VARIABLES’ >> mysql-variables while test -e $RUNFILE; do file=$(date +%F_%I) sleep=$(date +%s.%N | awk “{print $INTERVAL - (\$1 % $INTERVAL)}”) sleep $sleep ts=”$(date +”TS %s.%N %F %T”)” loadavg=”$(uptime)” echo “$ts $loadavg” >> $PREFIX-${file}-status mysql -e ‘SHOW GLOBAL STATUS’ >> $PREFIX-${file}-status & echo “$ts $loadavg” >> $PREFIX-${file}-innodbstatus mysql -e ‘SHOW ENGINE INNODB STATUS\G’ >> $PREFIX-${file}-innodbstatus & echo “$ts $loadavg” >> $PREFIX-${file}-processlist mysql -e ‘SHOW FULL PROCESSLIST\G’ >> $PREFIX-${file}-processlist & echo $ts done echo Exiting because $RUNFILE does not exist.

  1. <a name="odfQT"></a>
  2. ## 2.3.4 获得准确的测试结果
  3. <a name="z5wTY"></a>
  4. ## 2.3.5 运行基准测试并分析结果
  5. 下面是一个非常简单的shell脚本,演示了如何从前面的数据采集脚本采集到的数据中抽取时间维度信息
  6. ```shell
  7. #!/bin/sh
  8. # This script converts SHOW GLOBAL STATUS into a tabulated format, one line
  9. # per sample in the input, with the metrics divided by the time elapsed
  10. # between samples.
  11. awk '
  12. BEGIN {
  13. printf "#ts date time load QPS";
  14. fmt = " %.2f";
  15. }
  16. /^TS/ { # The timestamp lines begin with TS.
  17. ts = substr($2, 1, index($2, ".") - 1);
  18. load = NF - 2;
  19. diff = ts - prev_ts;
  20. prev_ts = ts;
  21. printf "\n%s %s %s %s", ts, $3, $4, substr($load, 1, length($load)-1);
  22. }
  23. /Queries/ {
  24. printf fmt, ($2-Queries)/diff;
  25. Queries=$2
  26. }
  27. ' "$@"

2.3.6 绘图的重要性

2.4 基准测试工具

2.4.1 集成式测试工具

  1. ab: 是一个Apache HTTP服务器基准测试工具。它可以测试HTTP服务器每秒最多可以处理多少请求。如果测试的是Web应用服务,这个结果可以转换成整个应用每秒可以满足多少请求。
  2. http_load: 这个工具概念上和ab类似,也被设计为对Web服务器进行测试,但比ab要更加灵活。
  3. JMeter: JMeter是一个Java应用程序,可以加载其他应用并测试其性能。它虽然是设计用来测试Web应用的,但也可以用于测试其他诸如FTP服务器,或者通过JDBC进行数据库查询测试。

    2.4.2 单组件式测试工具

  4. mysqlslap: 可以模拟服务器的负载,并输出计时信息。它包含在MySQL 5.1的发行包中,应该在MySQL 4.1或者更新的版本中都可以使用。测试时可以执行并发连接数,并指定SQL语句(可以在命令行上执行,也可以把SQL语句写入到参数文件中)。如果没有指定SQL语句,mysqlslap会自动生成查询schema的SELECT语句。

  5. MySQL Benchmark Suite(sql-bench): 在MySQL的发行包中也提供了一款自己的基准测试套件,可以用于在不同数据库服务器上进行比较测试。它是单线程的,主要用于测试服务器执行查询的速度。结果会显示哪种类型的操作在服务器上执行得更快。
  6. Super Smack: 是一款用于MySQL和PostgreSQL的基准测试工具,可以提供压力测试和负载生成。这是一个复杂而强大的工具,可以模拟多用户访问,可以加载测试数据到数据库,并支持使用随机数据填充测试表。
  7. Database Test Suite: 是由开源软件开发实验室(OSDL,Open Source Development Labs)设计的,发布在SourceForge网站(http://sourceforge.net/projects/osdldbt/)上,这是一款类似某些工业标准测试的测试工具集,例如由事务处理性能委员会(TPC,Transaction Processing Performance Council)制定的各种标准。
  8. Percona’s TPCC-MySQL Tool

在评估大压力下MySQL的一些行为时,我们经常会利用这个工具进行测试(简单的测试,一般会采用sysbench替代)。该工具的源代码可以在 https://launchpad.net/perconatools下载,在源码库中有一个简单的文档说明。

  1. sysbench: sysbench(https://launchpad.net/sysbench)是一款多线程系统压测工具。它可以根据影响数据库服务器性能的各种因素来评估系统的性能。
  2. MySQL的BENCHMARK()函数: MySQL有一个内置的BENCHMARK()函数,可以测试某些特定操作的执行速度。参数可以是需要执行的次数和表达式。表达式可以是任何的标量表达式,比如返回值是标量的子查询或者函数。

    2.5 基准测试案例

    2.5.1 http_load

    首先创建一个urls.txt文件,输入如下的URL:
    1. http://www.mysqlperformanceblog.com/
    2. http://www.mysqlperformanceblog.com/page/2/
    3. http://www.mysqlperformanceblog.com/mysql-patches/
    4. http://www.mysqlperformanceblog.com/mysql-performance-presentations/
    5. http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/
    http_load最简单的用法,就是循环请求给定的URL列表。测试程序将以最快的速度请求这些URL: ```shell $ http_load -parallel 1 -seconds 10 urls.txt 19 fetches, 1 max parallel, 837929 bytes, in 10.0003 seconds 44101.5 mean bytes/connection 1.89995 fetches/sec, 83790.7 bytes/sec msecs/connect: 41.6647 mean, 56.156 max, 38.21 min msecs/first-response: 320.207 mean, 508.958 max, 179.308 min HTTP response codes:
    1. code 200 - 19
  1. 下面是另外一个稍微复杂的测试,还是尽可能快地循环请求给定的URL列表,不过模拟同时有五个并发用户在进行请求:
  2. ```shell
  3. $ http_load -parallel 5 -seconds 10 urls.txt
  4. 94 fetches, 5 max parallel, 4.75565e+06 bytes, in 10.0005 seconds
  5. 50592 mean bytes/connection
  6. 9.39953 fetches/sec, 475541 bytes/sec
  7. msecs/connect: 65.1983 mean, 169.991 max, 38.189 min
  8. msecs/first-response: 245.014 mean, 993.059 max, 99.646 min
  9. HTTP response codes:
  10. code 200 - 94

除了测试最快的速度,也可以根据预估的访问请求率(比如每秒5次)来做压力模拟测试。

  1. $ http_load -rate 5 -seconds 10 urls.txt
  2. 48 fetches, 4 max parallel, 2.50104e+06 bytes, in 10 seconds
  3. 52105 mean bytes/connection
  4. 4.8 fetches/sec, 250104 bytes/sec
  5. msecs/connect: 42.5931 mean, 60.462 max, 38.117 min
  6. msecs/first-response: 246.811 mean, 546.203 max, 108.363 min
  7. HTTP response codes:
  8. code 200 - 48

还可以模拟更大的负载,可以将访问请求率提高到每秒20次请求。请注意,连接和请求响应时间都会随着负载的提高而增加。

  1. $ http_load -rate 20 -seconds 10 urls.txt
  2. 111 fetches, 89 max parallel, 5.91142e+06 bytes, in 10.0001 seconds
  3. 53256.1 mean bytes/connection
  4. 11.0998 fetches/sec, 591134 bytes/sec
  5. msecs/connect: 100.384 mean, 211.885 max, 38.214 min
  6. msecs/first-response: 2163.51 mean, 7862.77 max, 933.708 min
  7. HTTP response codes:
  8. code 200 -- 111

2.5.2 MySQL基准测试套件

MySQL基准测试套件(MySQL Benchmark Suite)由一组基于Perl开发的基准测试工具组成。在MySQL安装目录下的sql-bench子目录中包含了该工具。比如在Debian GNU/Linux系统上,默认的路径是/usr/share/mysql/sql-bench。
如果要运行全部测试,可以使用如下的命令:

  1. $ cd /usr/share/mysql/sql-bench/
  2. sql-bench$ ./run-all-tests --server=mysql --user=root --log --fast
  3. Test finished. You can find the result in:
  4. output/RUN-mysql_fast-Linux_2.4.18_686_smp_i686

除了运行全部测试集外,也可以选择单独执行其中的部分测试项。例如可以选择只执行
insert测试,这会比运行全部测试集所得到的汇总信息给出更多的详细信息:

  1. sql-bench$ ./test-insert
  2. Testing server 'MySQL 4.0.13 log' at 2003-05-18 11:02:39
  3. Testing the speed of inserting data into 1 table and do some selects on it.
  4. The tests are done with a table that has 100000 rows.
  5. Generating random keys
  6. Creating tables
  7. Inserting 100000 rows in order
  8. Inserting 100000 rows in reverse order
  9. Inserting 100000 rows in random order
  10. Time for insert (300000):
  11. 42 wallclock secs ( 7.91 usr 5.03 sys + 0.00 cusr 0.00 csys = 12.94 CPU)
  12. Testing insert of duplicates
  13. Time for insert_duplicates (100000):
  14. 16 wallclock secs ( 2.28 usr 1.89 sys + 0.00 cusr 0.00 csys = 4.17 CPU)

2.5.3 sysbench

sysbench可以执行多种类型的基准测试,它不仅设计用来测试数据库的性能,也可以测试运行数据库的服务器的性能。

sysbench的CPU基准测试

最典型的子系统测试就是CPU基准测试。该测试使用64位整数,测试计算素数直到某个最大值所需要的时间。下面的例子将比较两台不同的GNU/Linux服务器上的测试结果。第一台机器的CPU配置如下:

  1. [server1 ~]$ cat /proc/cpuinfo
  2. ...
  3. model name : AMD Opteron(tm) Processor 246
  4. stepping : 1
  5. cpu MHz : 1992.857
  6. cache size : 1024 KB

在这台服务器上运行如下的测试:

  1. [server1 ~]$ sysbench --test=cpu --cpu-max-prime=20000 run
  2. sysbench v0.4.8: multithreaded system evaluation benchmark
  3. ...
  4. Test execution summary: total time:121.7404s

第二台服务器配置了不同的CPU:

  1. [server2 ~]$ cat /proc/cpuinfo
  2. ...
  3. model name : Intel(R) Xeon(R) CPU 5130 @ 2.00GHz
  4. stepping : 6
  5. cpu MHz : 1995.005

测试结果如下:

  1. [server1 ~]$ sysbench --test=cpu --cpu-max-prime=20000 run
  2. sysbench v0.4.8: multithreaded system evaluation benchmark
  3. ...
  4. Test execution summary: total time:61.8596s

sysbench的文件I/O基准测试

文件I/O(fileio)基准测试可以测试系统在不同I/O负载下的性能。
首先通过下面的命令创建一个数据集:

  1. $ sysbench --test=fileio --file-total-size=150G prepare

第二步就是运行(run)阶段,针对不同的I/O类型有不同的测试选项:

  1. seqwr: 顺序写入。
  2. seqrewr: 顺序重写。
  3. seqrd: 顺序读取。
  4. rndrd: 随机读取。
  5. rndwr: 随机写入。
  6. rdnrw: 混合随机读/写。

下面的命令运行文件I/O混合随机读/写基准测试:

  1. $ sysbench --test=fileio --file-total-size=150G --file-test-mode=rndrw
  2. / --init-rng=on--max-time=300--max-requests=0 run
  3. sysbench v0.4.8: multithreaded system evaluation benchmark
  4. Running the test with following options:
  5. Number of threads: 1
  6. Initializing random number generator from timer.
  7. Extra file open flags: 0
  8. 128 files, 1.1719Gb each
  9. 150Gb total file size
  10. Block size 16Kb
  11. Number of random requests for random IO: 10000
  12. Read/Write ratio for combined random IO test: 1.50
  13. Periodic FSYNC enabled, calling fsync() each 100 requests.
  14. Calling fsync() at the end of test, Enabled.
  15. Using synchronous I/O mode
  16. Doing random r/w test
  17. Threads started!
  18. Time limit exceeded, exiting...
  19. Done.
  20. Operations performed: 40260 Read, 26840 Write, 85785 Other = 152885 Total
  21. Read 629.06Mb Written 419.38Mb Total transferred 1.0239Gb (3.4948Mb/sec)
  22. 223.67 Requests/sec executed
  23. Test execution summary:
  24. total time: 300.0004s
  25. total number of events: 67100
  26. total time taken by event execution: 254.4601
  27. per-request statistics:
  28. min: 0.0000s
  29. avg: 0.0038s
  30. max: 0.5628s
  31. approx. 95 percentile: 0.0099s
  32. Threads fairness:
  33. events (avg/stddev): 67100.0000/0.00
  34. execution time (avg/stddev): 254.4601/0.00

测试完成后,运行清除(cleanup)操作删除第一步生成的测试文件:

  1. $ sysbench --test=fileio --file-total-size=150G cleanup

sysbench的OLTP基准测试

OLTP基准测试模拟了一个简单的事务处理系统的工作负载。下面的例子使用的是一张超过百万行记录的表,第一步是先生成这张表:

  1. $ sysbench --test=oltp --oltp-table-size=1000000 --mysql-db=test
  2. / --mysql-user=root prepare
  3. sysbench v0.4.8: multithreaded system evaluation benchmark
  4. No DB drivers specified, using mysql
  5. Creating table 'sbtest'...
  6. Creating 1000000 records in table 'sbtest'...

接下来可以运行测试,这个例子采用了8个并发线程,只读模式,测试时长60秒:

  1. $ sysbench --test=oltp --oltp-table-size=1000000 --mysql-db=test --mysql-user=root
  2. / --max-time=60 --oltp-read-only=on --max-requests=0 --num-threads=8 run
  3. sysbench v0.4.8: multithreaded system evaluation benchmark
  4. No DB drivers specified, using mysql
  5. WARNING: Preparing of "BEGIN" is unsupported, using emulation
  6. (last message repeated 7 times)
  7. Running the test with following options:
  8. Number of threads: 8
  9. Doing OLTP test.
  10. Running mixed OLTP test
  11. Doing read-only test
  12. Using Special distribution (12 iterations, 1 pct of values are returned in 75 pct
  13. cases)
  14. Using "BEGIN" for starting transactions
  15. Using auto_inc on the id column
  16. Threads started!
  17. Time limit exceeded, exiting...
  18. (last message repeated 7 times)
  19. Done.
  20. OLTP test statistics:
  21. queries performed:
  22. read: 179606
  23. write: 0
  24. other: 25658
  25. total: 205264
  26. transactions: 12829 (213.07 per sec.)
  27. deadlocks: 0 (0.00 per sec.)
  28. read/write requests: 179606 (2982.92 per sec.)
  29. other operations: 25658 (426.13 per sec.)
  30. Test execution summary:
  31. total time: 60.2114s
  32. total number of events: 12829
  33. total time taken by event execution: 480.2086
  34. per-request statistics:
  35. min: 0.0030s
  36. avg: 0.0374s
  37. max: 1.9106s
  38. approx. 95 percentile: 0.1163s
  39. Threads fairness:
  40. events (avg/stddev): 1603.6250/70.66
  41. execution time (avg/stddev): 60.0261/0.06

2.5.4 数据库测试套件中的dbt2TPC-C测试

数据库测试套件(Database Test Suite)中的dbt2是一款免费的TPC-C测试工具。TPC-C是TPC组织发布的一个测试规范,用于模拟测试复杂的在线事务处理系统(OLTP)。它的测试结果包括每分钟事务数(tpmC),以及每事务的成本(Price/tpmC)。

  1. 准备测试数据。下面的命令会在指定的目录创建用于10个仓库的数据。每个仓库使用大约700MB磁盘空间,测试所需要的总的磁盘空间和仓库的数量成正比。因此,可以通过-w参数来调整仓库的个数以生成合适大小的数据集。 ```shell

    src/datagen -w 10 -d /mnt/data/dbt2-w10

    warehouses = 10 districts = 10 customers = 3000 items = 100000 orders = 3000 stock = 100000 new_orders = 900

    Output directory of data files: /mnt/data/dbt2-w10

    Generating data files for 10 warehouse(s)… Generating item table data… Finished item table data… Generating warehouse table data… Finished warehouse table data… Generating stock table data…

  1. 2. 加载数据到MySQL数据库。下面的命令创建一个名为dbt2w10的数据库,并且将上一步生成的测试数据加载到数据库中(-d参数指定数据库,-f参数指定测试数据所在的目录)。
  2. ```shell
  3. # scripts/mysql/mysql_load_db.sh -d dbt2w10 -f /mnt/data/dbt2-w10/-s /var/lib/mysql/mysql.sock
  1. 运行测试。

image.png