1.1 相关概念
1.2 TPC
http://www.tpc.org
TPC(Transactionprocessing Performance Council,事务处理性能委员会);
由数十家会员公司创建的非盈利组织,总部设在美国;
TPC的成员主要是计算机软硬件厂家,而非计算机用户;
TPC基准都是为了比较计算机系统(硬件和软件在一起)而制定的;
目前有三种TPC基准规范:TPC-A,TPC-B和TPC-C;
TPC-C是理事会的最新基准,TPC-A是理事会的第一个基准;
其功能是制定商务应用基准程序的标准规范、性能和价格度量,并管理测试结果的发布。
1.3 TPC-A
TPC-A 测量在线事务处理应用程序中典型的更新密集型数据库环境中的性能。(已于 95 年 6 月 6 日废弃)
TPC-A 基准测试于 1989 年 11 月发布,用于测量在线事务处理 (OLTP) 应用程序中典型的更新密集型数据库环境中的性能。此类环境具有以下特点:
多个在线终端会话
显着的磁盘输入/输出
适中的系统和应用程序执行时间
交易完整性
该基准测试使用单个简单的更新密集型事务来加载测试的系统。因此,工作负载旨在反映 OLTP 应用程序,但并不反映整个范围的 OLTP 要求,这些要求通常以不同复杂性的多种事务类型为特征。单一事务类型提供简单、可重复的工作单元,旨在执行 OLTP 系统的关键组件。
TPC-A 基准测试衡量系统在从多个终端驱动时每秒可以执行多少事务。虽然 TPC-A 没有指定终端数量,但它确实要求公司根据吞吐量或 tps 等级来扩展(增加或减少)终端数量。TPC-A 可以在广域网或局域网配置中运行,其性能由两个指标“TPC-A 本地吞吐量”和“TPC-A 宽吞吐量”描述,以每秒事务数 (tps) 衡量。这两个指标是不同的,无法进行比较。TPC-A 基准规范要求所有公司充分披露其基准运行的详细信息、系统配置及其成本(包括 5 年维护成本)。
1.4 TPC-B
TPC-B根据系统每秒可执行的事务数来衡量吞吐量;1990年8月,TPC批准了第二个基准TPC-B;与TPC-A相比,TPC-B不是OLTP基准;不适用于前端OLTP测量,它用于后端数据库服务器测量;由于OLTP与数据库压力测试之间存在实质性差异,因此无法将TPC-B结果与TPC-A进行比较。
TPC-B可以看作是一个数据库压力测试,其特点是:
重要的磁盘输入/输出
适中的系统和应用程序执行时间
交易完整性
1.5 TPC-C
TPC-C 是一个在线事务处理基准
TPC 基准 C 于 1992 年 7 月获得批准,是一种在线事务处理 (OLTP) 基准。TPC-C 比之前的 OLTP 基准测试(例如 TPC-A)更复杂,因为它具有多种事务类型、更复杂的数据库和整体执行结构。TPC-C 涉及五个不同类型和复杂性的并发事务的混合,要么在线执行,要么排队等待延迟执行。该数据库由九种类型的表组成,具有广泛的记录和人口规模。TPC-C 以每分钟事务数 (tpmC) 来衡量。虽然基准描述了批发供应商的活动,但 TPC-C 并不限于任何特定业务部门的活动,而是代表任何必须管理、销售或分销产品或服务的行业。
1.6 服务器io测试工具-fio
fio
安装
下载 https://git.kernel.dk/cgit/fio/
解压、./configure、make、make install
./configure --prefix=/opt/fio328
适当安装插件:
#yum install libaio*
#yum install zilb*
可根据实际测试中缺少的插件补充安装
常用参数
filename=/dev/emcpowerb 支持文件系统或者裸设备,-filename=/dev/sda
direct=1 测试过程绕过机器自带的buffer,使测试结果更真实
rw=randwread 测试随机读的I/O
rw=randwrite 测试随机写的I/O
rw=randrw 测试随机混合写和读的I/O
rw=read 测试顺序读的I/O
rw=write 测试顺序写的I/O
rw=rw 测试顺序混合写和读的I/O
bs=4k 单次io的块文件大小为4k
bsrange=512-2048 同上,提定数据块的大小范围
常用参数
size=5g 本次的测试文件大小为5g,以每次4k的io进行测试
numjobs=30 本次的测试线程为30
runtime=1000 测试时间为1000秒,如果不写则一直将5g文件分4k每次写完为止
ioengine=psync io引擎使用pync方式,如果要使用libaio引擎 需要yum install libaio-devel包
rwmixwrite=30 在混合读写的模式下,写占30%
group_reporting 关于显示结果的,汇总每个进程的信息
lockmem=1g 只使用1g内存进行测试
测试场景:
随机写
fio -filename=/opt/test -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=2G -numjobs=30 -runtime=100 -group_reporting -name=mytest
顺序写
fio -filename=/opt/test -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=16k -size=2G -numjobs=30 -runtime=100 -group_reporting -name=mytest
顺序读
fio -filename=/dev/sda1 -direct=1 -iodepth=1 -rw=read -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=sqe_100read_4k
随机写
fio -filename=/opt/test -direct=1 -iodepth=1 -rw=randwrite -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=rand_100write_4k
70%随机读,30%随机写
fio -filename=/opt/test -direct=1 -iodepth= 1 -rw=randrw -rwmixread=70 -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=randrw_70read_4k
1.7 Pgbench
1.7.1 概要
pgbench是一种在PostgreSQL上运行基准测试的简单程序;
1、默认情况下,pgbench会测试一种基于 TPC-B 但是要更宽松的场景,其中在每个事务中涉及五 个SELECT、UPDATE以及INSERT命令。
2、用户可以通过编写自己的事务脚本文件很容易用来测 试其他情况。
我们先来看下pgbench默认的测试方法, 默认的类 TPC-B 事务测试要求预先设置好特定的表。可以使用-i(初始化)选项调用pgbench 来创建并且填充这些表(当你在测试一个自定义脚本时,你不需要这一步,但是需要按你自 己的测试需要做一些设置工作)。
它可能在并发的数据库会话中一遍一遍地运行相同序列的 SQL 命令,并且计算平均事务率(每秒的事务数);
默认情况下,pgbench会测试一种基于 TPC-B 但是要更宽松的场景,其中在每个事务中涉及五个SELECT、UPDATE以及INSERT命令。
通过编写自己的事务脚本文件很容易用来测试其他情况;
测试的目的是了解硬件的处理能力;通过调整参数优化数据库事务处理性能
1.7.2 初始化
pgbench -i [ other-options ] dbname
主要选项
-i:初始化模式
-s 插入的倍数,默认是1,即插入100000条;也就是执行多少次generate_series(1,100000)。
创建四个表,如果同名表已经存在会被先删除
pgbench_accounts #账户表
pgbench_branches#支行表
pgbench_history#历史信息表
pgbench_tellers #出纳表
在默认的情况下-s"比例因子"为 1,这些表初始包含的行数为:
table # of rows
pgbench_branches 1
pgbench_tellers 10
pgbench_accounts 100000
pgbench_history 0
1.7.3 测试小例
创建测试用户
create user csuser with password '123456';
创建测试库
create database csuser owner csuser;
初始化测试环境
pgbench -U csuser -i csuser
pgbench本身带有压测insert、update、select语句的脚本,可测试数据库的吞吐能力、并发能力
pgbench -c 50 -j 2 -T 60 -r csuser
-c 模拟客户端数
-T 执行时长
-r 报告每个命令的平均延迟
1.7.4 基准测试
pgbench [ options ] dbname
重要选项:
-c(客户端数量)
-t(事务数量)
-T(时间限制)
-j(工作者线程数量)
-f(指定一个自定义脚本文件)
1.8 在pgbench中执行的"事务"
pgbench执行从指定列表中随机选中的测试脚本
它们包括带有-b的内建脚本和带有-f的用户提供的自定义脚本
每一个脚本可以在其后用@指定一个相对权重,这样可以更改该脚本的抽取概率。
-b scriptname[@weight]
--builtin=scriptname[@weight]
把指定的内建脚本加入到要执行的脚本列表中。
@之后是一个可选的整数权重,它允许调节抽取该脚本的可能性。
如果没有指定,它会被设置为 1。
可用的内建脚本有:tpcb-like、simple-update和select-only。
默认的内建事务脚本
BEGIN;
--1
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
--2
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
--3
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
--4
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
--5
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;
如果选择simple-update内建脚本(选项 -N),第 3 和 4 步不会被包括在事务中。
如果选择select-only内建脚本(选项 -S),只会发出SELECT。
1.8.1 基准测试输出
pgbench的典型输出像这样:
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10 # 有四张表,这里是10,相当于每个表的数据*10(大概10倍,并不是准确的) -s
query mode: simple # 共三种查询方式:-M, --protocol=simple|extended|prepared
number of clients: 10 #并行客户端连接数 -c
number of threads: 1 # 工作线程数,多个客户端公用这些工作线程 -j
number of transactions per client: 1000
number of transactions actually processed: 10000/10000
tps = 85.184871 (including connections establishing)
tps = 85.296346 (excluding connections establishing)
前六行报告一些最重要的参数设置。
接下来的行报告完成的事务数以及预期的事务数(后者就是客户端数量与每个客户端事务数的乘积),除非运行在完成之前失败,这些值应该是相等的(在-T模式中,只有实际的事务数会被打印出来)。
最后两行报告每秒的事务数,分别代表包括和不包括开始数据库会话所花时间的情况。
默认的类 TPC-B 事务测试要求预先设置好特定的表。
可以使用-i(初始化)选项调用pgbench来创建并且填充这些表(当你在测试一个自定义脚本时,你不需要这一步,但是需要按你自己的测试需要做一些设置工作)。
1.8.2 使用建议
多运行几次测试是一个好主意,这样可以看看你的数字是不是可以重现;
注意自动清理进程autovacuum对测试的影响。
初始化的比例因子(-s)应该至少和你想要测试的最大客户端数量一样大(-c),否则你将主要在度量更新争夺;
因为在pgbench_branches表中只有-s行,并且每个事务都想更新其中之一,因此-c值超过-s将毫无疑问地导致大量事务被阻塞来等待其他事务。
pgbench的一个限制是在尝试测试大量客户端会话时,它自身可能成为瓶颈。
可以通过在数据库服务器之外的一台机器上运行pgbench来缓解,不过必须是具有低网络延迟的机器。
甚至可以在多个客户端机器上针对同一个数据库服务器并发地运行多个pgbench实例。
1.8.3 示例
create database pgbenchdb
pgbench -i -s 5 pgbenchdb--初始化,将在pgbench_accounts表中创建 500,000行。
pgbench -r -j2 -c4 -t60 pgbenchdb--基准测试1,并行工作线程数2,客户端数量4,每客户端事务数60
pgbench -r -j2 -c10 -T10 pgbenchdb--基准测试2,并行工作线程数2,客户端数量10,运行时间1分钟。
-r 在基准结束后,报告平均的每个命令的每语句等待时间(从客户端的角度来说是执行时间)。
-j pgbench中的工作者线程数量。在多 CPU 机器上使用多于一个线程会有用。客户端会尽可能均匀地分布到可用的线程上。默认为 1。
-c 模拟的客户端数量,也就是并发数据库会话数量。默认为 1。
-t 每个客户端运行的事务数量。默认为 10。
-T 运行测试这么多秒,而不是为每个客户端运行固定数量的事务。
注意: -t和-T是互斥的。
1.9 真实测试案例
1.9.1 目标
测试最大写入TPS数据量。
1.9.2 表结构
CREATE TABLE test( guid character varying(64), puc_id character varying(64), system_id character varying(16), device_id character varying(64), device_alias character varying(100), number_type integer, device_type integer, staff_code character varying(50), gps_datetime timestamp without time zone, gps_av character varying(1), long_we character varying(1), longitude numeric(20,16), lat_ns character varying(1), latitude numeric(20,16), speed numeric(20,16), direction numeric(20,16), state character varying(255), receive_datetime timestamp without time zone, tsc_id integer, channel_id smallint, rssi_up smallint, rssi_down smallint, power_mode smallint, electricity integer);
1.9.3 插入语句
INSERT INTO test (guid, puc_id, system_id, device_id, device_alias, number_type, device_type, staff_code, gps_datetime, gps_av, long_we, longitude, lat_ns, latitude, speed, direction, state, receive_datetime, tsc_id, channel_id, rssi_up, rssi_down, power_mode, electricity) VALUES ('0D34F308-D3C1-40E2-948B-58CCE1127F1F', '00001', '001', '100000001', '100000001', 0, 0, '', timestamp '2021-10-08 14:53:39', 'V', 'E', 126.524055, 'N', 45.797836, 0, 0, '0', timestamp '2021-10-08 14:52:58', 0, 0, 0, 0, 0, 4), ('AB45FEEB-FB27-4D52-9D8F-7E50B1A4F97C', '00001', '001', '100000002', '100000002', 0, 0, '', timestamp '2021-10-08 14:53:39', 'V', 'E', 126.524055, 'N', 45.797836, 0, 0, '0', timestamp '2021-10-08 14:52:59', 0, 0, 0, 0, 0, 4);
1.9.4 测试语句
1.9.4.1 修改参数pgbench -c 100 -n -f test_pgbench.sql -T 60 -h 127.0.0.1 -p 5432 >> client65.log
transaction type: test_pgbench.sql
scaling factor: 1
query mode: simple
number of clients: 100
number of threads: 1
duration: 60 s
number of transactions actually processed: 4062844
latency average = 1.506 ms
tps = 66392.824374 (including connections establishing)
tps = 66394.891052 (excluding connections establishing)
1.9.4.2 不修改参数
transaction type: test_pgbench.sql
scaling factor: 1
query mode: simple
number of clients: 100
number of threads: 1
duration: 60 s
number of transactions actually processed: 3804781
latency average = 1.583 ms
tps = 53181.608770 (including connections establishing)
tps = 53183.633298 (excluding connections establishing)
1.9.5 关注参数
src/backend/access/transam/xlog.c
/*
* Number of WAL insertion locks to use. A higher value allows more insertions
* to happen concurrently, but adds some CPU overhead to flushing the WAL,
* which needs to iterate all the locks.
*使用WAL插入锁的数量。较高的值允许更多的插入并发发生,但是会增加刷新WAL的CPU开销,这需要迭代所有的锁。
*/
#define NUM_XLOGINSERT_LOCKS (默认值8) (24)
commit_delay = 12
参数含义:事务提交后,日志写到wal_buffer上到wal_buffer写到磁盘的时间间隔。
参数优化:当有比较多的并发短事务时,可以适当增加该值,使日志缓冲区一次刷盘可以刷出较多的事务,减少IO次数,提高性能。需要和commit_sibling配合使用。
commit_siblings = 24
参数含义:触发commit_delay等待的并发事务数,即系统的并发活跃事务数达到了该值,事务才会等待commit_delay的时间后才将日志刷新到磁盘。
参数优化:若系统中并发活跃事务达不到该值,commit_delay将不起作用,为防止在系统并发压力较小的情况下事务提交后空等其他事务,不宜设置过大。
fsync
如果打开这个参数,PostgreSQL服务器将尝试确保更新被物理地写入到磁盘,做法是发出fsync()系统调用或者使用多种等价的方法(见wal_sync_method)。这保证了数据库集簇在一次操作系统或者硬件崩溃后能恢复到一个一致的状态。虽然关闭fsync常常可以得到性能上的收益,但当发生断电或系统崩溃时可能造成不可恢复的数据损坏。
full_page_writes 全页写