Java web应用性能分析之【CPU飙高分析之MySQL】-CSDN博客
Java web应用性能分析之【Linux服务器性能监控分析概叙】-CSDN博客
上面基本科普了一下基准测试,这里我们将从sysbench安装、sysbench使用、sysbench报告解读等方面来详细讲解sysbench完成基准测试。
一般情况下基准测试一定是有个对比。可以是相同硬件配置,不同品牌硬件服务器间的对比;也可以是在同一硬件服务器上,不同基准测试场景的对比。
sysbench简介
SysBench是一个跨平台的基准测试工具,用于评估计算机系统在不同负载条件下的性能。它模拟真实场景下的工作负载,提供了多种测试模式,包括CPU、内存、磁盘、线程、数据库等方面的测试。
主要包括以下几种测试:
- cpu性能
- 磁盘io性能
- 调度程序性能
- 内存分配及传输速度
- POSIX线程性能
- 数据库性能(OLTP基准测试)
sysbench安装
sysbench的github地址GitHub - akopytov/sysbench: Scriptable database and system performance benchmark
最新版本sysbench 1.0.20,下载地址:
Release Release 1.0.20 · akopytov/sysbench · GitHub
安装方式,官网已经给出了说明指导
需要重点注意的是这里,在./configure配置环境时,如果要测试mysql,需要指定"you can specify them explicitly with --with-mysql-includes
and --with-mysql-libs
options to ./configure
."这两个路径
我在ubuntu18上安装如下:
sysbench基本操作
基本语法:sysbench [options]... [testname] [command],执行sysbench --help,或者详见官网。
https://github.com/akopytov/sysbench?tab=readme-ov-file#general-syntax
command
command是sysbench要执行的命令,包括:prepare、run、cleanup。
顾名思义,prepare是为测试提前准备数据,run是执行正式的测试,cleanup是在测试完成后对数据库进行清理。后面我们的基准测试脚本也是按照这个来写的。
testname
testname 是一个可选的内置测试名称(如 fileio、memory、cpu等),或一个捆绑的 Lua 脚本名称(如 oltp_read_only),或一个自定义 Lua 脚本的路径。testname指定了要进行的测试,在老版本的sysbench中,可以通过--test参数指定测试的脚本;而在新版本中,--test参数已经声明为废弃,可以不使用--test,而是直接指定脚本。
例如,如下两种方法效果是一样的:
|-----|----------------------------------------------------------------------------------------------------|
| 1 2 | sysbench --test=./tests/include/oltp_legacy/oltp.lua sysbench ./tests/include/oltp_legacy/oltp.lua |
测试时使用的脚本为lua脚本,可以使用sysbench自带脚本,也可以自己开发。对于大多数应用,使用sysbench自带的脚本就足够了。不同版本的sysbench中,lua脚本的位置可能不同,可以自己在sysbench路径下使用find命令搜索oltp.lua。P.S.:大多数数据服务都是oltp类型的,如果你不了解什么是oltp,那么大概率你的数据服务就是oltp类型的。
options
sysbench的options参数有很多,options是一个包含0个或多个以"--"开头的命令行选项的列表。其中比较常用的包括:
MySQL 连接信息参数
-
--mysql-host:MySQL服务器主机名,默认localhost;如果在本机上使用localhost报错,提示无法连接MySQL服务器,改成本机的IP地址应该就可以了。
-
--mysql-port:MySQL服务器端口,默认3306
-
--mysql-user:用户名
-
--mysql-password:密码
-
--mysql-db 指定数据库 默认sbtest
-
--mysql-ssl 使用 ssl 连接 默认off
-
--mysql-ssl-cipher ssl 使用 specific cipher
-
--mysql-compression 如果客户端库中有压缩功能,则使用压缩功能 默认off
-
--mysql-debug 跟踪所有客户端库调用 默认off
-
--mysql-ignore-errors 忽略的错误 [1213,1020,1205]
-
--mysql-dry-run 模拟运行,假装所有 MySQL 客户端 API 调用都成功,但不执行它们 默认off
MySQL 执行参数
- --oltp-test-mode:执行模式,包括simple、nontrx和complex,默认是complex。simple模式下只测试简单的查询;nontrx不仅测试查询,还测试插入更新等,但是不使用事务;complex模式下测试最全面,会测试增删改查,而且会使用事务。可以根据自己的需要选择测试模式。
- --oltp-tables-count:测试的表数量,根据实际情况选择
- --oltp-table-size:测试的表的大小,根据实际情况选择
- --threads:客户端的并发连接数
- --time:测试执行的时间,单位是秒,该值不要太短,可以选择120
- --report-interval:生成报告的时间间隔,单位是秒,如10
压测的lua脚本
注:这些脚本均包含了oltp_common,所以调用这些脚本可以直接使用 oltp_common 脚本中的内容,oltp_common 脚本中编写了数据生成、数据清理等基础函数。
lua脚本参数
sysbench的基准测试场景
基准场景步骤
先确定单线程运行时的 TPS 值。
根据系统最大的预估容量设置场景中的线程数、递增参数等;如果不会预估容量,可以直接多加一些线程,然后在递增的过程中查看曲线的变化;
强调一下,如果你不会预估容量,可以直接多加一些线程,然后在递增的过程中查看曲线的变化;确定正式基准场景的压力参数。
基准场景的目的
获得单接口最大 TPS:如果单接口最大 TPS 没有超过容量场景中的要求,那就必须要调优
解决单接口基准场景中遇到的性能问题:也就是说,当我们在做单接口测试时,碰到了性能瓶颈一定要分析解决。
基准场景性能分析步骤
第一阶段:硬件资源用完。即在基准场景中,我们要把 CPU、内存、网络、IO 等资源中的任一个耗尽,因为在这种情况下,我们很容易从全局监控的性能计数器中看到现象,可以接着去跟踪分析。
第二阶段:优化到最高 TPS。即在基准场景中,我们要把单接口的 TPS 调到最高,以免成为容量场景中的瓶颈点。
主要测试方式
- cpu性能 :找范围内最大素数{时间越短越好}
- 磁盘io性能:不同场景下IOPS{越大越好}
- 调度程序性能 :线程并发执行,循环响应信号量花费的时间{越少越好}
- 内存分配及传输速度:以不同块大小传输一定数量的数据吞吐量大小{越大越好}
- POSIX线程性能 :并发线程同时申请互斥锁循环一定次数花费的时间{越少越好}
- 数据库性能(OLTP基准测试):qps、tps越高越好
服务器硬件环境:阿里云主机 2 核(vCPU) 4GiB内存 46GB磁盘 1 Mbps带宽。
这里我们以测试cpu为例,脚本和分析,都一样。
测试cpu
测试素数上限20万,线程1、2、4、6、8、10
bash
## 测试素数上限20万,线程2、4、8、10
root@zhouxx:~# sysbench cpu --cpu-max-prime=200000 --threads=1 run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 1 ##线程数
Initializing random number generator from current time
Prime numbers limit: 200000 ## 素数上限
Initializing worker threads...
Threads started!
CPU speed:
events per second: 17.24 #所有线程每秒完成的event数
General statistics:
total time: 10.0349s ##总耗时
total number of events: 173 ##总共完成的event数
Latency (ms):
min: 56.78 ##最少耗时
avg: 58.00 #平均耗时
max: 70.17 #最大耗时
95th percentile: 61.08 ##95%都在61.08秒内找到
sum: 10033.47
Threads fairness:
events (avg/stddev): 173.0000/0.00 完成了几轮的素数计算
execution time (avg/stddev): 10.0335/0.00 #每个线程平均耗时10秒,标准差为0
##event: 完成了几轮的素数计算
##stddev(标准差): 在相同时间内,多个线程分别完成的素数计算次数是否稳定,如果数值越低,则表示多个线程的结果越接近(即越稳定)。该参数对于单线程无意义。
root@zhouxx:~# sysbench cpu --cpu-max-prime=200000 --threads=2 run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 2
Initializing random number generator from current time
Prime numbers limit: 200000
Initializing worker threads...
Threads started!
CPU speed:
events per second: 33.95
General statistics:
total time: 10.0420s
total number of events: 341
Latency (ms):
min: 56.98
avg: 58.86
max: 116.24
95th percentile: 63.32
sum: 20072.61
Threads fairness:
events (avg/stddev): 170.5000/1.50
execution time (avg/stddev): 10.0363/0.00
root@zhouxx:~#
root@zhouxx:~# sysbench cpu --cpu-max-prime=200000 --threads=4 run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 4
Initializing random number generator from current time
Prime numbers limit: 200000
Initializing worker threads...
Threads started!
CPU speed:
events per second: 33.93
General statistics:
total time: 10.0781s
total number of events: 342
Latency (ms):
min: 57.78
avg: 117.53
max: 159.62
95th percentile: 123.28
sum: 40193.86
Threads fairness:
events (avg/stddev): 85.5000/1.12
execution time (avg/stddev): 10.0485/0.02
root@zhouxx:~# sysbench cpu --cpu-max-prime=200000 --threads=8 run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 8
Initializing random number generator from current time
Prime numbers limit: 200000
Initializing worker threads...
Threads started!
CPU speed:
events per second: 33.95
General statistics:
total time: 10.1018s
total number of events: 343
Latency (ms):
min: 155.71
avg: 234.83
max: 279.10
95th percentile: 267.41
sum: 80545.85
Threads fairness:
events (avg/stddev): 42.8750/1.05
execution time (avg/stddev): 10.0682/0.02
root@zhouxx:~# sysbench cpu --cpu-max-prime=200000 --threads=10 run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 10
Initializing random number generator from current time
Prime numbers limit: 200000
Initializing worker threads...
Threads started!
CPU speed:
events per second: 34.27
General statistics:
total time: 10.1246s
total number of events: 347
Latency (ms):
min: 190.21
avg: 290.45
max: 327.95
95th percentile: 308.84
sum: 100786.19
Threads fairness:
events (avg/stddev): 34.7000/0.46
execution time (avg/stddev): 10.0786/0.04
root@zhouxx:~#
结果分析
服务器进行CPU性能对比,当素数上限和线程数一致时:
-
相同时间,比较event
-
相同event,比较时间
-
时间和event都相同,比较stddev(标准差)
绘图
这里直接用echart的折线图
完整的测试过程,应该开着监控,观察服务器资源消耗情况。
测试内存
测试线程
测试io
测试mutex
测试OLTP
备注:--test=oltp 已经被弃用
sysbench测试cpu
sysbench测试内存
sysbench测试io
sysbench测试数据库
测试mysql数据库前的准备工作:创建数据库和登录账号。
sql
CREATE DATABASE sbtest CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'sbuser'@'%' IDENTIFIED BY "zhouxx1234";
grant all privileges on sbtest.* to 'sbuser'@'localhost' identified by 'zhouxx1234';
grant all privileges on sbtest.* to 'sbuser'@'%' identified by 'zhouxx1234';
grant all privileges on sbtest.* to 'sbuser'@'172.26.35.10' identified by 'zhouxx1234';
UPDATE mysql.user SET authentication_string=PASSWORD('zhouxx1234') WHERE User='sbuser';
flush privileges;
完整的sysbench基准测试脚本
测试oltp批量插入脚本
bash
#!/bin/bash
current_data=$(date "+%Y-%m-%d")
current_time=$(date "+%H:%M:%S")
#链接配置信息
dbhost="172.26.35.10"
dbport=3306
dbuser="sbuser"
dbpwd="zhouxx1234"
dbname=sbtest
#单表数据量
tbsize=3
#表数据量
tables=1
#选择引擎,默认innodb
testengine=innodb
# 压测使用的lua 脚本
luascript=bulk_insert.lua
# 线程数组
#threads=(1 5 10 15)
# 测试时间
sbtime=600
mkdir -p /usr/share/sysbench/sblog
sbtestlogdir=/usr/share/sysbench/sblog #存放log的地方,需要手动自己创建
path=/usr/sysbench/share/sysbench/ #存放sysbench脚本point_select.lua等其他脚本的地方
#for thread in ${threads[@]}
for thread in 1 5 10 15
do
#测试结果输出日志
sblogname=${sbtestlogdir}/sbtench_${testengine}_${luascript}_${thread}_$(date "+%Y%m%d%H%M%S").log
echo "============================压测开始! 当前日期:$(date "+%Y-%m-%d %H:%M:%S")======================================
压测地址:${dbhost},压测端口:${dbport},测试引擎对象:${testengine}压测数据量:${tables}张表每张表${tbsize}条数据量,压测时间:${sbtime} s,当前压测线程:${threads}
日志地址:${sbtestlogdir}
sysbench ${path}${luascript} --db-driver=mysql --mysql-host=${dbhost} \
--mysql-port=${dbport} --mysql-user=${dbuser} \
--mysql-password=${dbpwd} \
--mysql-db=${dbname} --table_size=${tbsize} \
--tables=${tables} --events=0 --time=${sbtime} \
--mysql_storage_engine=${testengine} \
--threads=${thread} --percentile=95 \
--range_selects=0 --skip-trx=1 --report-interval=5 prepare " >> ${sblogname}
sysbench ${path}${luascript} --db-driver=mysql --mysql-host=${dbhost} \
--mysql-port=${dbport} --mysql-user=${dbuser} \
--mysql-password=${dbpwd} \
--mysql-db=${dbname} --table_size=${tbsize} \
--tables=${tables} --events=0 --time=${sbtime} \
--mysql_storage_engine=${testengine} \
--threads=${thread} --percentile=95 \
--range_selects=0 --skip-trx=1 --report-interval=5 prepare >> ${sblogname}
sysbench ${path}${luascript} --db-driver=mysql --mysql-host=${dbhost} \
--mysql-port=${dbport} --mysql-user=${dbuser} \
--mysql-password=${dbpwd} \
--mysql-db=${dbname} --table_size=${tbsize} \
--tables=${tables} --events=0 --time=${sbtime} \
--mysql_storage_engine=${testengine} \
--threads=${thread} --percentile=95 \
--range_selects=0 --skip-trx=1 --report-interval=5 run >> ${sblogname}
sysbench ${path}${luascript} --db-driver=mysql --mysql-host=${dbhost} \
--mysql-port=${dbport} --mysql-user=${dbuser} \
--mysql-password=${dbpwd} \
--mysql-db=${dbname} --table_size=${tbsize} \
--tables=${tables} --events=0 --time=${sbtime} \
--mysql_storage_engine=${testengine} \
--threads=${thread} --percentile=95 \
--range_selects=0 --skip-trx=1 --report-interval=5 cleanup >> ${sblogname}
echo "============================压测结束! 当前时间:$(date "+%Y-%m-%d %H:%M:%S")====================================== " >> ${sblogname}
#sleep 10
#/etc/init.d/atomstore restart
done