1. TPC-C介绍
Transaction Processing Performance Council (TPC) 事务处理性能委员会,是一家非盈利IT组织,他们的目的是定义数据库基准并且向产业界推广可验证的数据库性能测试。而TPC-C最后一个C代表的是压测模型的版本,在这之前还有TPC-A、TPC-B。A / B 两个版本模拟的是银行转账业务,相对业务模型比较简单。TPC-C自92年初发布,在过去20多年,不管是在业界还是学术界都是应用最为广泛的OLTP压测工具。
TPC-C测试用到的模型是一个大型的商品批发销售公司,它拥有若干个分布在不同区域的商品仓库。当业务扩展的时候,公司将添加新的仓库。每个仓库负责为10个销售点供货,其中每个销售点为3000个客户提供服务,每个客户提交的订单中,平均每个订单有10项产品,所有订单中约1%的产品在其直接所属的仓库中没有存货,必须由其他区域的仓库来供货。同时,每个仓库都要维护公司销售的100000种商品的库存记录。
1.1 TPC-C表结构
TPC-C测试系统数据库由9张表组成,它们的关系如下图所示,表框里的数字表示该表将要存放多少条记录,仓库数W的调整在测试中能够体现数据库所能够支持的数据规模的能力:
- Warehouse(仓库表,W表示仓数,能够体现数据库所能够支持的数据规模)
- District(区域表,W*10表每个仓为10个销售点供货)
- Customer(用户表,W*30k表示每个供货点为3000个客户提供服务)
- Stock(库存表,W*100k表示每个仓库维护10w种商品库存记录)
- Order(订单表)
- New-Order(新订单表)
- Item(商品表,表固定大小为10w)
- Order-Line(订单行)
- History(历史表)
1.2 TPC-C事务模型
TPC-C需要处理的交易事务主要为以下几种:
- 新订单(New-Order,占比45%) :客户输入一笔新的订货交易;
- 支付操作(Payment,占比43%) :更新客户帐户余额以反映其支付状况;
- 发货(Delivery,占比4%) :发货(模拟批处理交易);
- 订单状态查询(Order-Status,占比4%) :查询客户最近交易的状态;
- 库存状态查询(Stock-Level,占比4%) :查询仓库库存状况,以便能够及时补货。
TPC-C五种交易类型中StockLevel和OrderStatus这两种交易属于只读事务,NewOrder 、Payment、Delivery属于读写事务,这五种请求是互相独立运行的,在交易组合中读写操作占92%,只读操作占8%。TPC-C通过tpmC值(Transactions per Minute)来衡量系统最大有效吞吐量(MQTh,Max Qualified Throughput),其中Transactions以NewOrder Transaction为准,即最终衡量单位为每分钟处理的新订单数,这就说明了:如果一台机器有 1000 tpmc (Transactions per Minute),那么它实际上处理的交易(请求)为 1000/45% = 2222。
2. BenchmarkSQL使用教程
目前做TPC-C压测的开源工具很多,如mysql-tpcc、HammerDB、Benchmarksql等。这三种是在做TPC-C压测使用最多的,也是资料比较丰富的工具。由于我们在工作使用的数据库种类会比较多,mysql-tpcc只能用在MySQL或者兼容MySQL的数据库。HammerDB使用方便,图形化界面可测DB2、PG、Oracle、MySQL等但是对于NewSQL类数据库兼容不是很友好。因为BenchmarkSQL支持多种TPC模型,并且支持不同的数据库类型(如Oracle, PG, MySQL), 本篇文章介绍BenchmarkSQL的使用教程。
2.1 安装BenchmarSQL
下载安装包:https://sourceforge.net/projects/benchmarksql/?source=typ_redirect
上传到服务器解压:
unzip benchmarksql-5.0.zip
安装编译工具ant:
apt install ant
使用ant编译BenchmarkSQL:
> cd benchmarksql-5.0
> ant
init:
[mkdir] Created dir: /root/code/benchmark/benchmarksql-5.0/build
compile:
[javac] Compiling 11 source files to /root/code/benchmark/benchmarksql-5.0/build
dist:
[mkdir] Created dir: /root/code/benchmark/benchmarksql-5.0/dist
[jar] Building jar: /root/code/benchmark/benchmarksql-5.0/dist/BenchmarkSQL-5.0.jar
BUILD SUCCESSFUL
Total time: 1 second
2.2 创建数据库
登录PG数据库:
su -u postgres
psql
创建数据库tpcc和用户root,并且把tpcc库的所有权限授权给root用户:
postgres=# create database tpcc;
CREATE DATABASE
postgres=# create user root with password 'xxx';
postgres=# grant all privileges on database tpcc to root;
修改PG数据库配置文件的认证方式,主要涉及两个文件,/etc/postgresql/14/main/postgresql.conf和 /etc/postgresql/14/main/pg_hba.conf:
# 修改postgresql.conf,修改监听地址
listen_addresses = '*'
# 修改pg_hba.conf,修改IPv4 local connections
host all all 0.0.0.0/0 trust
# 重启PG数据库
systemctl restart postgresql
修BenchmarkSQL的改配置文件:
cd benchmark/benchmarksql-5.0/run # 这里props.ora和props.pg是针对oracle和pg的配置文件
cp props.pg props.pg.bak # 将pg的配置文件进行备份
vim props.pg # 修改mysql的连接信息
参数 | 值 | 说明 |
db | postgres | 指定数据库类型,这里为postgres或者oracle |
driver | org.postgresql.Driver | 数据库的驱动类名称 |
conn | jdbc:postgresql://localhost:5432/tpcc | 连接字符串,tpcc为新创建的库名 |
user | root | 用户名,PG库的用户名需要和OS的用户一致 |
password | xxxxx | 用户密码 |
warehouses | 1 | 初始化加载数据时,需要创建多少仓库的数据。每仓库约80MB数据 |
loadWorkers | 8 | 表示加载数据时,开启加载数据的进程数。 |
terminals | 1 | 终端数量,指同时有多少终端并发执行,表示并发程度,压测时该值可以不断调整 |
runTxnsPerTerminal | 0 | 每分钟每个终端执行的事务数,0表示不限制 |
runMins | 10 | 执行多少分钟。 |
limitTxnsPerMin | 0 | 限制每分钟执行的事务总数。0表示不限制 |
terminalWarehouseFixed | true | 用于指定终端和仓库的绑定模式,设置为true时可以运行4.x兼容模式,意思为每个终端都有一个固定的仓库。设置为false时可以均匀的使用数据库整体配置。 |
注意:runMins和runTxnsPerTerminal这两个参数指定了两种运行方式,前者是按照指定运行时间执行,以时间为标准;后者以指定每个终端的事务数为标准执行。两者不能同时生效,必须有一个设定为0。
2.3 创建表并且加载数据
这里会创建并初始化表—共9张表(warehouse, Stock, Item, Order-Line, New-Order, History, District, Customer,Order),外加一个配置表。 同时会创建相应的索引、主外键参考。
cd run
./runDatabaseBuild.sh props.pg
# ------------------------------------------------------------
# Loading SQL file ./sql.common/tableCreates.sql
# ------------------------------------------------------------
create table bmsql_config (
cfg_name varchar(30) primary key,
cfg_value varchar(50)
);
create table bmsql_warehouse (
w_id integer not null,
w_ytd decimal(12,2),
w_tax decimal(4,4),
w_name varchar(10),
w_street_1 varchar(20),
w_street_2 varchar(20),
w_city varchar(20),
w_state char(2),
w_zip char(9)
);
create table bmsql_district (
d_w_id integer not null,
d_id integer not null,
d_ytd decimal(12,2),
d_tax decimal(4,4),
d_next_o_id integer,
d_name varchar(10),
d_street_1 varchar(20),
d_street_2 varchar(20),
d_city varchar(20),
d_state char(2),
d_zip char(9)
);
create table bmsql_customer (
c_w_id integer not null,
c_d_id integer not null,
c_id integer not null,
c_discount decimal(4,4),
c_credit char(2),
c_last varchar(16),
c_first varchar(16),
c_credit_lim decimal(12,2),
c_balance decimal(12,2),
c_ytd_payment decimal(12,2),
c_payment_cnt integer,
c_delivery_cnt integer,
c_street_1 varchar(20),
c_street_2 varchar(20),
c_city varchar(20),
c_state char(2),
c_zip char(9),
c_phone char(16),
c_since timestamp,
c_middle char(2),
c_data varchar(500)
);
create sequence bmsql_hist_id_seq;
create table bmsql_history (
hist_id integer,
h_c_id integer,
h_c_d_id integer,
h_c_w_id integer,
h_d_id integer,
h_w_id integer,
h_date timestamp,
h_amount decimal(6,2),
h_data varchar(24)
);
create table bmsql_new_order (
no_w_id integer not null,
no_d_id integer not null,
no_o_id integer not null
);
create table bmsql_oorder (
o_w_id integer not null,
o_d_id integer not null,
o_id integer not null,
o_c_id integer,
o_carrier_id integer,
o_ol_cnt integer,
o_all_local integer,
o_entry_d timestamp
);
create table bmsql_order_line (
ol_w_id integer not null,
ol_d_id integer not null,
ol_o_id integer not null,
ol_number integer not null,
ol_i_id integer not null,
ol_delivery_d timestamp,
ol_amount decimal(6,2),
ol_supply_w_id integer,
ol_quantity integer,
ol_dist_info char(24)
);
create table bmsql_item (
i_id integer not null,
i_name varchar(24),
i_price decimal(5,2),
i_data varchar(50),
i_im_id integer
);
create table bmsql_stock (
s_w_id integer not null,
s_i_id integer not null,
s_quantity integer,
s_ytd integer,
s_order_cnt integer,
s_remote_cnt integer,
s_data varchar(50),
s_dist_01 char(24),
s_dist_02 char(24),
s_dist_03 char(24),
s_dist_04 char(24),
s_dist_05 char(24),
s_dist_06 char(24),
s_dist_07 char(24),
s_dist_08 char(24),
s_dist_09 char(24),
s_dist_10 char(24)
);
2.4 开始压测
压测前先看看1仓数据每个表有多少行数据:
- bmsql_warehouse:1行,8192Byte
- bmsql_district:10行,8192Byte
- bmsql_customer:30000行,大小为18MB
- bmsql_oorder表:30000行,1936KB
- bmsql_history表:30000行,2592KB
- bmsql_new_order表:9000行, 392KB
- bmsql_order_line表:2999929行,29MB
- bmsql_item表:100000行,10MB
- bmsql_stock表:100000行,34MB
- bmsql_config表:4行,8192Byte
整个tpcc库大小为123MB,也就是说1仓数据总大小为123MB。如果改成100仓,则整个数据库的大小为10GB。
./runBenchmark.sh props.pg
执行结束后,取tpmC和tpmTOTAL作为测试指标。测试测试软硬件环境如下:
- CPU:16核,13th Gen Intel(R) Core(TM) i5-1340P,1.90 GHz
- 内存:7.6GB
- 硬盘:1TB SSD
- 操作系统:ubuntu 22.04.5 LTS
- 压测时间:10min
- 仓数大小:100仓,数据量大小为10GB
线程数 | tpmC (NewOrders) | tpmTOTAL |
1 | 12015 | 26690 |
2 | 22271 | 49611 |
4 | 29288 | 65130 |
8 | 35660 | 79185 |
2.5 删除数据库和数据
./runDatabaseDestroy.sh props.pg