Tpcc-MySQL测试详解
前言:

TPC-C规范概要
TPC-C是专门针对联机交易处理系统(OLTP系统)的,一般情况下我们也把这类系统称为业务处理系统。

TPC-C测试规范中模拟了一个比较复杂并具有代表意义的OLTP应用环境:

  假设有一个大型商品批发商,它拥有若干个分布在不同区域的商品库;每个仓库负责为10个销售点供货;每个销售点为3000个客户提供服务;每个客户平均一个订单有10项产品;所有订单中约1%的产品在其直接所属的仓库中没有存货,需要由其他区域的仓库来供货。同时,每个仓库都要维护公司销售的100000种商品的库存记录。

  该系统需要处理的交易为以下几种:

  New-Order:客户输入一笔新的订货交易;

  Payment:更新客户账户余额以反映其支付状况;

  Delivery:发货(模拟批处理交易);

  Order-Status:查询客户最近交易的状态;

  Stock-Level:查询仓库库存状况,以便能够及时补货。

  对于前四种类型的交易,要求响应时间在5秒以内;对于库存状况查询交易,要求响应时间在20秒以内。

TPC-C测试指标
TPC-C测试的结果主要有两个指标,即流量指标(Throughput,简称tpmC)和性价比(Price/Performance,简称Price/tpmC)。
流量指标(Throughput,简称tpmC):按照TPC组织的定义,流量指标描述了系统在执行支付操作、订单状态查询、发货和库存状态查询这4种交易的同时,每分钟可以处理多少个新订单交易。所有交易的响应时间必须满足TPC-C测试规范的要求,且各种交易数量所占的比例也应该满足TPC-C测试规范的要求。在这种情况下,流量指标值越大说明系统的联机事务处理能力越高。
性价比(Price/Performance,简称Price/tpmc):即测试系统的整体价格与流量指标的比值,在获得相同的tpmC值的情况下,价格越低越好。

一、安装

1、mysql8.0安装

  参考其他博文

2、tpcc-mysql安装

yum -y install bzr .

bzr branch lp:~percona-dev/perconatools/tpcc-mysql

cd tpcc-mysql/src

make

#然后会在上层目录生成 tpcc_load tpcc_start两个二进制程序。

在 tpcc-mysql文件中生成了tpcc_load及tpcc_start 文件,即表示tpcc完成安装

不建议下载 tpcc-mysql-master.zip 的源码包,当时找了好多源,安装后出问题,并且会sc=0的调不到数据的情况

二、使用

1、导表

  1)、数据库中创建数据库

    数据库名任意

  2)、导入数据表

    mysql -uroot -p123456 tpcc <./create_table.sql # tpcc是数据库名,可以任意起

    mysql -uroot -p123456 tpcc <./add_fkey_idx.sql # 导入外键
2、建模 #指创建仓库
   # ./tpcc_load -h localhost -d tpcc -u root -p "123456" -w 5

   命令格式:
  tpcc_load -h server_host -P port -d database_name -u mysql_user -p mysql_password -w warehouses -l part -m min_wh -n max_wh  
     
  ./tpcc_load --halp 查看帮助 #有的版本不需要加参数,建议使用之前先 --help
  参数含义:
  -h server_host: 服务器名 或 IP地址
  -P port : 端口号,默认为3306   #可省略
  -d database_name: 数据库名
  -u mysql_user : 用户名
  -p mysql_password : 密码
  -w warehouses: 仓库的数量

  选项warehouse意为指定测试库下的仓库数量
  选项[part]为只创建数据到[part]对应的表中 # 可省略
  选项[min_wh]、[max_wh]为min_wid max_wid # 可省略

真实测试场景中,仓库数一般不建议少于100个,视服务器硬件配置而定,如果是配备了SSD或者PCIE SSD这种高IOPS设备的话,建议最少不低于1000个。

3、测试
   # ./tpcc_start -hlocalhost -d tpcc -u root -p "123456" -w 5 -c 5 -r 120 -l 300 > tpcc-output-log

   命令格式:

   tpcc_start -h server_host -P port -d database_name -u mysql_user -p mysql_password -w warehouses -c connections -r warmup_time -l running_time -me report_interval -f report_file

   # ./tpcc_start --halp 查看帮助

   参数含义
    -h server_host: 服务器名
    -P port : 端口号,默认为3306
    -d database_name: 数据库名
    -u mysql_user : 用户名
    -p mysql_password : 密码
    -w warehouses: 仓库的数量
    -c connections : 线程数,默认为1
    -r warmup_time : 热身时间,单位:s,默认为10s ,热身是为了将数据加载到内存。
    -l running_time: 测试时间,单位:s,默认为20s
    -i report_interval: 指定生成报告间隔时长
    -f report_file: 测试结果输出文件

现在我们来开启一个测试案例:

./tpcc_start -h localhost -d tpcc1000 -u tpcc_user -p "tpcc_password" -w 1000 -c 32 -r 120 -l 3600 -f tpcc_mysql_20140921.log >> tpcc_caseX_20140921.log 2>&1

即:模拟 1000个仓库规模,并发 16个线程进行测试,热身时间为 60秒, 压测时间为 1小时。
真实测试场景中,建议预热时间不小于5分钟,持续压测时长不小于30分钟,否则测试数据可能不具参考意义;

查看进程: cat /proc/cupinfo

4、测试结果分析

  1)、发起测试

   ./tpcc_start -h 1.2.3.4 -P 3306 -d tpcc10 -u tpcc -p tpcc -w 10 -c 64 -r 30 -l 120 -f tpcclog_201409211538_64_THREADS.log >> tpcc_noaid_2_20140921_64.log 2>&1

  2)、测试结果输出如下:

    -- 本轮tpcc压测的一些基本信息


###easy### TPC-C Load Generator


option h wif value '1.2.3.4' -- 主机
option P wif value '3306' -- 端口
option d wif value 'tpcc10' -- 数据库
option u wif value 'tpcc' -- 账号
option p wif value 'tpcc' -- 密码
option w wif value '10' -- 仓库数
option c wif value '64' -- 并发线程数
option r wif value '30' -- 数据预热时长
option l wif value '120' -- 压测时长
option f wif value 'tpcclog_20140921_64_THREADS.res' -- 输出报告日志文件

RAMP-UP TIME.(30 sec.)

-- 预热结束,开始进行压测
MEASURING START.

-- 每10秒钟输出一次压测数据
10, 8376(0):2.744|3.211, 8374(0):0.523|1.626, 838(0):0.250|0.305, 837(0):3.241|3.518, 839(0):9.086|10.676
20, 8294(0):2.175|2.327, 8292(0):0.420|0.495, 829(0):0.206|0.243, 827(0):2.489|2.593, 827(0):7.214|7.646

110, 8800(0):2.149|2.458, 8792(0):0.424|0.710, 879(0):0.207|0.244, 878(0):2.461|2.556, 878(0):7.042|7.341
120, 8819(0):2.147|2.327, 8820(0):0.424|0.568, 882(0):0.208|0.237, 881(0):2.483|2.561, 883(0):7.025|7.405

解释

-- 以逗号分隔,共6列
-- 第一列,第N次10秒
-- 第二列,新订单成功执行压测的次数【8376】(推迟执行压测的次数【0】) : 90%事务的响应时间|本轮测试最大响应时间【2.744】| 新订单事务数也被认为是总有效事务数的指标【3.211】
-- 第三列,支付业务成功执行次数(推迟执行次数) : 90%事务的响应时间 | 本轮测试最大响应时间
-- 第四列,订单状态业务的结果,后面几个的意义同上
-- 第五列,物流发货业务的结果,后面几个的意义同上
-- 第六列,库存仓储业务的结果,后面几个的意义同上

-- 压测结束
STOPPING THREADS................................................................

(success,简写sc)次数,延迟(late,简写lt)次数,重试(retry,简写rt)次数,失败(failure,简写fl)次数

-- 第一次结果统计
[0] sc:100589 lt:0 rt:0 fl:0 -- New-Order,新订单业务成功
[1] sc:100552 lt:0 rt:0 fl:0 -- Payment,支付业务统计,其他同上
[2] sc:10059 lt:0 rt:0 fl:0 -- Order-Status,订单状态业务统计,其他同上
[3] sc:10057 lt:0 rt:0 fl:0 -- Delivery,发货业务统计,其他同上
[4] sc:10058 lt:0 rt:0 fl:0 -- Stock-Level,库存业务统计,其他同上
in 120 sec.

-- 第二次统计结果,其他同上

[0] sc:100590 lt:0 rt:0 fl:0
[1] sc:100582 lt:0 rt:0 fl:0
[2] sc:10059 lt:0 rt:0 fl:0
[3] sc:10057 lt:0 rt:0 fl:0
[4] sc:10059 lt:0 rt:0 fl:0

(all must be [OK]) -- 下面所有业务逻辑结果都必须为 OK 才行
[transaction percentage]
Payment: 43.47% (>=43.0%) [OK] -- 支付成功次数(上述统计结果中 sc + lt)必须大于43.0%,否则结果为NG,而不是OK
Order-Status: 4.35% (>= 4.0%) [OK] -- 订单状态,其他同上
Delivery: 4.35% (>= 4.0%) [OK] -- 发货,其他同上
Stock-Level: 4.35% (>= 4.0%) [OK] -- 库存,其他同上
[response time (at least 90% passed)] -- 响应耗时指标必须超过90%通过才行
New-Order: 100.00% [OK] -- 下面几个响应耗时指标全部 100% 通过
Payment: 100.00% [OK]
Order-Status: 100.00% [OK]
Delivery: 100.00% [OK]
Stock-Level: 100.00% [OK]

50294.500 TpmC -- TpmC结果值(每分钟事务数,该值是第一次统计结果中的新订单事务数除以总耗时分钟数,例如本例中是:100589/2 = 50294.500)

5、生成图片
待补充

错误信息汇总:

1、 进行 ./tpcc_start -h localhost -d tpcc1000 -u tpcc_user -p "tpcc_password" -w 1000 -c 32 -r 120 -l 3600 -f tpcc_mysql_20140921.log 报错

  2002, HY000. Can't connect to local MySQL server through socket Vvar. run/mysqld/mysqld.sock'

原因:

  tpcc-mysql存在2个bug,需要手动修改

  文件1: main.c

  源信息:

  char db_socket[DB_STRING_MAX] = " ";

   if(is_local==1){

   / exec sql connect :connect_string; /

  resp = mysql_real_connect(ctx[t_num], "localhost", db_user, db_password, db_string_full, port, db_socket, 0);

}else{

  / exec sql connect :connect_string USING :db_string; /

  resp = mysql_real_connect(ctx[t_num], connect_string, db_user, db_password, db_string_full, port, db_socket, 0);

}

  修改方法一:

  在char db_socket[DB_STRING_MAX] = " ",中写入mysql.sock路径,并在每个语句前加上 mysql_thread_init();

  完整语句:

  char db_socket[DB_STRING_MAX] = "/var/lib/mysql/mysql.sock";

   if(is_local==1){

   / exec sql connect :connect_string; /

  mysql_thread_init();

  resp = mysql_real_connect(ctx[t_num], "localhost", db_user, db_password, db_string_full, port, db_socket, 0);

}else{

  / exec sql connect :connect_string USING :db_string; /

  mysql_thread_init();

  resp = mysql_real_connect(ctx[t_num], connect_string, db_user, db_password, db_string_full, port, db_socket, 0);

}

  修改方法二:

  直接替换db_socket 为 "/var/lib/mysql/mysql.sock"

  完整语句:

  char db_socket[DB_STRING_MAX] = " ";

   if(is_local==1){

   / exec sql connect :connect_string; /

  mysql_thread_init();

  resp = mysql_real_connect(ctx[t_num], "localhost", db_user, db_password, db_string_full, port, "/var/lib/mysql/mysql.sock", 0);

}else{

  / exec sql connect :connect_string USING :db_string; /

  mysql_thread_init();

  resp = mysql_real_connect(ctx[t_num], connect_string, db_user, db_password, db_string_full, "/var/lib/mysql/mysql.sock", 0);

}

  文件二:load.c

  源文件:

    if(is_local==1){

        /* exec sql connect :connect_string; */

        resp = mysql_real_connect(mysql, "localhost", db_user, db_password, db_string, port, NULL, 0);

    }else{

        /* exec sql connect :connect_string USING :db_string; */

        resp = mysql_real_connect(mysql, connect_string, db_user, db_password, db_string, port, NULL, 0);

  修改方法:

  将语句中的 NULL替换为 "/var/lib/mysql/mysql.sock",并在每个语句前加上 mysql_thread_init();

  完整语句:

    if(is_local==1){

        /* exec sql connect :connect_string; */

    mysql_thread_init();

        resp = mysql_real_connect(mysql, "localhost", db_user, db_password, db_string, port, "/var/lib/mysql/mysql.sock", 0);

    }else{

        /* exec sql connect :connect_string USING :db_string; */

   mysql_thread_init();

        resp = mysql_real_connect(mysql, connect_string, db_user, db_password, db_string, port, "/var/lib/mysql/mysql.sock", 0);

2、tpcc_mysql找不到 mysql.sock文件

    tpcc 默认会读取 /var/lib/mysql/mysql.sock 这个socket 文件,如果你的 socket 文件不在相应路径的话,可以使用ln -s命令做个软连接

  

资料来源:https://mp.weixin.qq.com/s/Kv1rk6ybehbw8vBfPyxNsw

     https://blog.csdn.net/sincoqiu/article/details/70226268

     https://blog.csdn.net/jswangchang/article/details/81317741 (生成图片)
https://www.cnblogs.com/bulh/articles/11229473.html