[TOC]
## 1.理论知识:
### 1.1 定义
> 1. 基准测试是一种测量和评估软件性能指标的活动,用于建立某个时刻的性能基准,以便当系统发生软硬件变化时重新进行基准测试以评估变化对性能的影响
> 2. 基准测试是针对系统设置的一种压力测试,但是和压力测试还是有区别的
> 基准测试:直接、简单,易于比较,用于评估服务器的处理能力
> 基准测试:可能不关心业务逻辑,所使用的查询和业务的真实性可以和业务环境没有关系
> 压力测试:对真实的业务数据进行测试,获得真实系统所能承受的压力
> 压力测试:需要针对不同的应用场景,所使用的数据和查询也是真实用到的
### 1.2 测试步骤
选择sysbench为测试工具
1.安装sysbench
1)下载安装包
`wget https://github.com/akopytov/sysbench/archive/0.5.zip`
2)安装依赖工具
~~~
apt -y install make automake libtool pkg-config libaio-dev vim-common
# For MySQL support
apt -y install libmysqlclient-dev
# For PostgreSQL support
apt -y install libpq-dev
~~~
3)编译安装
~~~
unzip 0.5.zip
cd sysbench-0.5
./autogen.sh
# Add --with-pgsql to build with PostgreSQL support
./configure
make
make install
~~~
2. 准备测试
1) 创建测试库
~~~
create database sysbenchtest;
~~~
2) 创建测试用户
~~~
grant all privileges on sysbenchtest.* to sysbench@'localhost' identified by '4rfv$RFV';
flush privileges;
~~~
3) 准备测试数据:构建5张表,每张表10万条数据
~~~
sysbench --test=./sysbench/tests/db/oltp.lua --mysql-host=127.0.0.1 --mysql-db=sysbenchtest --mysql-user=sysbench \
--mysql-password='4rfv$RFV' --oltp-test-mode=complex --oltp-tables-count=5 --oltp-table-size=100000 --threads=10 --time=120 \
--rand-init=on --report-interval=10 --mysql-table-engine=innodb prepare
~~~
* 参数说明
~~~
mysql-db=dbtest1a:测试使用的目标数据库,这个库名要事先创建
--oltp-tables-count=10:产生表的数量
--oltp-table-size=500000:每个表产生的记录行数
--oltp-dist-type=uniform:指定随机取样类型,可选值有 uniform(均匀分布), Gaussian(高斯分布), special(空间分布)。默认是special
--oltp-read-only=off:表示不止产生只读SQL,也就是使用oltp.lua时会采用读写混合模式。默认 off,如果设置为on,则不会产生update,delete,insert的sql。
--oltp-test-mode=nontrx:执行模式,这里是非事务式的。可选值有simple,complex,nontrx。默认是complex
simple:简单查询,SELECT c FROM sbtest WHERE id=N
complex (advanced transactional):事务模式在开始和结束事务之前加上begin和commit, 一个事务里可以有多个语句,如点查询、范围查询、排序查询、更新、删除、插入等,并且为了不破坏测试表的数据,该模式下一条记录删除后会在同一个事务里添加一条相同的记录。
nontrx (non-transactional):与simple相似,但是可以进行update/insert等操作,所以如果做连续的对比压测,你可能需要重新cleanup,prepare。
--oltp-skip-trx=[on|off]:省略begin/commit语句。默认是off
--rand-init=on:是否随机初始化数据,如果不随机化那么初始好的数据每行内容除了主键不同外其他完全相同
--num-threads=12: 并发线程数,可以理解为模拟的客户端并发连接数
--report-interval=10:表示每10s输出一次测试进度报告
--max-requests=0:压力测试产生请求的总数,如果以下面的max-time来记,这个值设为0
--max-time=120:压力测试的持续时间,这里是2分钟。
注意,针对不同的选项取值就会有不同的子选项。比如oltp-dist-type=special,就有比如oltp-dist-pct=1、oltp-dist-res=50两个子选项,代表有50%的查询落在1%的行(即热点数据)上,另外50%均匀的(sample uniformly)落在另外99%的记录行上。
再比如oltp-test-mode=nontrx时, 就可以有oltp-nontrx-mode,可选值有select(默认), update_key, update_nokey, insert, delete,代表非事务式模式下使用的测试sql类型。
以上代表的是一个只读的例子,可以把num-threads依次递增(16,36,72,128,256,512),或者调整my.cnf参数,比较效果。另外需要注意的是,大部分mysql中间件对事务的处理,默认都是把sql发到主库执行,所以只读测试需要加上oltp-skip-trx=on来跳过测试中的显式事务。
ps1: 只读测试也可以使用share/tests/db/select.lua进行,但只是简单的point select。
ps2: 我在用sysbench压的时候,在mysql后端会话里有时看到大量的query cache lock,如果使用的是uniform取样,最好把查询缓存关掉。当然如果是做两组性能对比压测,因为都受这个因素影响,关心也不大。
~~~
3. 运行基准测试
1) 运行测试:混合操作测试
~~~
sysbench --test=./sysbench/tests/db/oltp.lua --mysql-table-engine=innodb --mysql-host=127.0.0.1 --mysql-db=sysbenchtest --mysql-user=sysbench \
--mysql-password='4rfv$RFV' --num-threads=8 --oltp-table-size=100000 --oltp_tables_count=5 --oltp-read-only=off --report-interval=10 \
--rand-type=uniform --max-time=300 --max-requests=0 --percentile=99 run >> ./log/sysbench.log
~~~
2) 如果多次测试清理记录
~~~
sysbench --test=./sysbench/tests/db/oltp.lua --mysql-table-engine=innodb --mysql-host=127.0.0.1 --mysql-db=sysbenchtest --num-threads=8 \
--oltp-table-size=100000 --oltp_tables_count=5 --oltp-read-only=off --report-interval=10 --rand-type=uniform --max-time=600 --max-requests=0 \
--mysql-user=test --mysql-password='4rfv$RFV' cleanup
~~~
* 参数说明
~~~
--num-threads=8 表示发起 8个并发连接
--oltp-read-only=off 表示不要进行只读测试,也就是会采用读写混合模式测试
--report-interval=10
表示每10秒输出一次测试进度报告 --rand-type=uniform
表示随机类型为固定模式,其他几个可选随机模式:uniform(固定),gaussian(高斯),special(特定的),pareto(帕累托)
--max-time=120 表示最大执行时长为 120秒,实际环境中建议30分钟
--max-requests=0 表示总请求数为 0,因为上面已经定义了总执行时长,所以总请求数可以设定为 0;也可以只设定总请求数,不设定最大执行时长
--percentile=99 表示设定采样比例,默认是 95%,即丢弃1%的长请求,在剩余的99%里取最大值
~~~
4. 分析调优效果:通过脚本控制测试,测试多次取平均值,运行脚本需要清空上一次的日志。
1) 参数分析
~~~
queries performed:
read: 938224 -- 读总数
write: 268064 -- 写总数
other: 134032 -- 其他操作总数(SELECT、INSERT、UPDATE、DELETE之外的操作,例如COMMIT等)
total: 1340320 -- 全部总数
transactions: 67016 (1116.83 per sec.) -- 总事务数(每秒事务数)
deadlocks: 0 (0.00 per sec.) -- 发生死锁总数
read/write requests: 1206288 (20103.01 per sec.) -- 读写总数(每秒读写次数)
other operations: 134032 (2233.67 per sec.) -- 其他操作总数(每秒其他操作次数)
General statistics: -- 一些统计结果
total time: 60.0053s -- 总耗时
total number of events: 67016 -- 共发生多少事务数
total time taken by event execution: 479.8171s -- 所有事务耗时相加(不考虑并行因素)
response time: -- 响应时长统计,主要参考指标
min: 4.27ms -- 最小耗时
avg: 7.16ms -- 平均耗时
max: 13.80ms -- 最长耗时
approx. 99 percentile: 9.88ms -- 超过99%平均耗时
Threads fairness:
events (avg/stddev): 8377.0000/44.33
execution time (avg/stddev): 59.9771/0.00
~~~
5. 测试分析脚本
analysis_mysql.py,控制多次测试,然后取平均值
~~~
#!/usr/bin/env python
import re
import os
import configparser
if (not os.path.exists("sysbench.log")):
os.mknod("sysbench.log")
else :
os.remove("sysbench.log")
os.mknod("sysbench.log")
if (not os.path.exists("analysis.log")):
os.mknod("analysis.log")
logFile = open('sysbench.log','r')
analysisFile = open('analysis.log','a+')
configFile = "sysbench.conf"
config = configparser.ConfigParser()
config.read(configFile)
host = config.get('config','dbhost')
database = config.get('config','database')
user = config.get('config','user')
password = config.get('config','password')
time = config.get('config','times')
print(host)
print(database)
print(user)
print(password)
tableCount = config.get('config','--oltp-tables-count')
tableSize = config.get('config','--oltp-table-size')
threadNum = config.get('config','--num-threads')
maxTime = config.get('config','--max-time')
oltp = config.get('config','oltp')
# 结果分析
def closeFile(file):
file.close()
def analysis():
print("开始分析...")
transacion = []
readeWrite = []
mintime = []
avgtime = []
maxtime = []
approxtime = []
# 读取文件数据
for line in logFile:
transacion_persec = re.search(r'transactions:.*\((\d+\.*\d*).*\).*',line)
readeWrite_persec = re.search(r'read/write requests:.*\((\d+\.*\d*).*\).*',line)
mintime_response = re.search(r'min:\s*(\d+\.?\d*).*',line)
avgtime_response = re.search(r'avg:\s*(\d+\.?\d*).*',line)
maxtime_response = re.search(r'max:\s*(\d+\.?\d*).*',line)
approxtime_response = re.search(r'approx.*?(\d+\.{1}\d*).*',line)
if transacion_persec:
transacion.append(transacion_persec.group(1))
elif readeWrite_persec:
readeWrite.append(readeWrite_persec.group(1))
elif mintime_response:
mintime.append(mintime_response.group(1))
elif avgtime_response:
avgtime.append(avgtime_response.group(1))
elif maxtime_response:
maxtime.append(maxtime_response.group(1))
elif approxtime_response:
approxtime.append(approxtime_response.group(1))
sum = 0.0
# 统计事务
for data in transacion:
sum += float(data)
avgtransaction = ('%.2f'%(sum / len(transacion)))
analysisFile.write("transacion每秒:" + str(avgtransaction) + "\n")
sum = 0.0
# 统计读写
for data in readeWrite:
sum += float(data)
read_write = ('%.2f'%(sum / len(readeWrite)))
analysisFile.write("read/write每秒:" + str(read_write) + "\n")
sum = 0.0
# 统计最小时间
for data in mintime:
sum += float(data)
if len(mintime) !=0:
min_time = ('%.2f'%(sum / len(mintime)))
analysisFile.write("min time:" + str(min_time) + "\n")
sum = 0.0
# 统计最大时间
for data in maxtime:
sum += float(data)
max_time = ('%.2f'%(sum / len(maxtime)))
analysisFile.write("max time:" + str(max_time) + "\n")
sum = 0.0
# 统计平均时间
for data in avgtime:
sum += float(data)
avg_time = ('%.2f'%(sum / len(avgtime)))
analysisFile.write("avg time:" + str(avg_time) + "\n")
analysisFile.write("="*20 + "\n")
print("分析完成...")
closeFile(analysisFile)
# 数据准备
def prepare():
print("准备数据...表数:%s,记录数:%s,测试线程数:%s,持续时间:%s"%(tableCount,tableSize,threadNum,maxTime))
os.system("sysbench --test=%s --mysql-host=%s --mysql-db=%s --mysql-user=%s --mysql-password='%s' --oltp-test-mode=complex --oltp-tables-count=%s --oltp-table-size=%s --threads=10 --ti
me=%s --rand-init=on --report-interval=10 --mysql-table-engine=innodb prepare"%(oltp,host,database,user,password,tableCount,tableSize,maxTime))
# 测试函数
def experiment():
print("测试数据...")
os.system("sysbench --test=%s --mysql-table-engine=innodb --mysql-host=%s --mysql-db=%s --mysql-user=%s --mysql-password='%s' --num-threads=%s --oltp-test-mode=complex --oltp-table-siz
e=%s --oltp_tables_count=%s --oltp-read-only=off --report-interval=10 --rand-type=uniform --max-time=%s --max-requests=0 --percentile=99 run >> ./sysbench.log"%(oltp,host,database,user,pass
word,threadNum,tableSize,tableCount,maxTime))
#
# # 清空数据
def clean():
print("清空测试数据库...")
os.system("sysbench --test=%s --mysql-table-engine=innodb --mysql-host=%s --mysql-db=%s --num-threads=8 --oltp-table-size=%s --oltp_tables_count=%s --oltp-read-only=off --report-interv
al=10 --rand-type=uniform --max-time=600 --max-requests=0 --mysql-user=%s --mysql-password='%s' cleanup"%(oltp,host,database,tableSize,tableCount,user,password))
if __name__ == '__main__':
for i in range(0,int(time)):
prepare()
experiment()
clean()
analysis()
~~~
* 配置文件
~~~
[config]
dbhost = 127.0.0.1
database = sysbenchtest
user = sysbench
password = 4rfv$RFV
# oltp测试脚本路径
oltp = /root/sysben/sysbench-0.5/sysbench/tests/db/oltp.lua
# 测试次数
times = 5
--oltp-tables-count=5
--oltp-table-size=1000000
--num-threads=30
--max-time=600
~~~
## 2. 测试用例
> 测试用例:
> 是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足特定需求
> 通俗的讲,测试用例是指导我们进行具体测试的描述。
![](https://box.kancloud.cn/4503334f9ca1bcfec42307285f2306da_1556x774.png)
![](https://box.kancloud.cn/52ffb0c062b1358b36904a4b326e34cc_1560x814.png)
- Docker
- 什么是docker
- Docker安装、组件启动
- docker网络
- docker命令
- docker swarm
- dockerfile
- mesos
- 运维
- Linux
- Linux基础
- Linux常用命令_1
- Linux常用命令_2
- ip命令
- 什么是Linux
- SELinux
- Linux GCC编译警告:Clock skew detected. 错误解决办法
- 文件描述符
- find
- 资源统计
- LVM
- Linux相关配置
- 服务自启动
- 服务器安全
- 字符集
- shell脚本
- shell命令
- 实用脚本
- shell 数组
- 循环与判断
- 系统级别进程开启和停止
- 函数
- java调用shell脚本
- 发送邮件
- Linux网络配置
- Ubuntu
- Ubuntu发送邮件
- 更换apt-get源
- centos
- 防火墙
- 虚拟机下配置网络
- yum重新安装
- 安装mysql5.7
- 配置本地yum源
- 安装telnet
- 忘记root密码
- rsync+ crontab
- Zabbix
- Zabbix监控
- Zabbix安装
- 自动报警
- 自动发现主机
- 监控MySQL
- 安装PHP常见错误
- 基于nginx安装zabbix
- 监控Tomcat
- 监控redis
- web监控
- 监控进程和端口号
- zabbix自定义监控
- 触发器函数
- zabbix监控mysql主从同步状态
- Jenkins
- 安装Jenkins
- jenkins+svn+maven
- jenkins执行shell脚本
- 参数化构建
- maven区分环境打包
- jenkins使用注意事项
- nginx
- nginx认证功能
- ubuntu下编译安装Nginx
- 编译安装
- Nginx搭建本地yum源
- 文件共享
- Haproxy
- 初识Haproxy
- haproxy安装
- haproxy配置
- virtualbox
- virtualbox 复制新的虚拟机
- ubuntu下vitrualbox安装redhat
- centos配置双网卡
- 配置存储
- Windows
- Windows安装curl
- VMware vSphere
- 磁盘管理
- 增加磁盘
- gitlab
- 安装
- tomcat
- Squid
- bigdata
- FastDFS
- FastFDS基础
- FastFDS安装及简单实用
- api介绍
- 数据存储
- FastDFS防盗链
- python脚本
- ELK
- logstash
- 安装使用
- kibana
- 安准配置
- elasticsearch
- elasticsearch基础_1
- elasticsearch基础_2
- 安装
- 操作
- java api
- 中文分词器
- term vector
- 并发控制
- 对text字段排序
- 倒排和正排索引
- 自定义分词器
- 自定义dynamic策略
- 进阶练习
- 共享锁和排它锁
- nested object
- 父子关系模型
- 高亮
- 搜索提示
- Redis
- redis部署
- redis基础
- redis运维
- redis-cluster的使用
- redis哨兵
- redis脚本备份还原
- rabbitMQ
- rabbitMQ安装使用
- rpc
- RocketMQ
- 架构概念
- 安装
- 实例
- 好文引用
- 知乎
- ACK
- postgresql
- 存储过程
- 编程语言
- 计算机网络
- 基础_01
- tcp/ip
- http转https
- Let's Encrypt免费ssl证书(基于haproxy负载)
- what's the http?
- 网关
- 网络IO
- http
- 无状态网络协议
- Python
- python基础
- 基础数据类型
- String
- List
- 遍历
- Python基础_01
- python基础_02
- python基础03
- python基础_04
- python基础_05
- 函数
- 网络编程
- 系统编程
- 类
- Python正则表达式
- pymysql
- java调用python脚本
- python操作fastdfs
- 模块导入和sys.path
- 编码
- 安装pip
- python进阶
- python之setup.py构建工具
- 模块动态导入
- 内置函数
- 内置变量
- path
- python模块
- 内置模块_01
- 内置模块_02
- log模块
- collections
- Twisted
- Twisted基础
- 异步编程初探与reactor模式
- yield-inlineCallbacks
- 系统编程
- 爬虫
- urllib
- xpath
- scrapy
- 爬虫基础
- 爬虫种类
- 入门基础
- Rules
- 反反爬虫策略
- 模拟登陆
- problem
- 分布式爬虫
- 快代理整站爬取
- 与es整合
- 爬取APP数据
- 爬虫部署
- collection for ban of web
- crawlstyle
- API
- 多次请求
- 向调度器发送请求
- 源码学习
- LinkExtractor源码分析
- 构建工具-setup.py
- selenium
- 基础01
- 与scrapy整合
- Django
- Django开发入门
- Django与MySQL
- java
- 设计模式
- 单例模式
- 工厂模式
- java基础
- java位移
- java反射
- base64
- java内部类
- java高级
- 多线程
- springmvc-restful
- pfx数字证书
- 生成二维码
- 项目中使用log4j
- 自定义注解
- java发送post请求
- Date时间操作
- spring
- 基础
- spring事务控制
- springMVC
- 注解
- 参数绑定
- springmvc+spring+mybatis+dubbo
- MVC模型
- SpringBoot
- java配置入门
- SpringBoot基础入门
- SpringBoot web
- 整合
- SpringBoot注解
- shiro权限控制
- CommandLineRunner
- mybatis
- 静态资源
- SSM整合
- Aware
- Spring API使用
- Aware接口
- mybatis
- 入门
- mybatis属性自动映射、扫描
- 问题
- @Param 注解在Mybatis中的使用 以及传递参数的三种方式
- mybatis-SQL
- 逆向生成dao、model层代码
- 反向工程中Example的使用
- 自增id回显
- SqlSessionDaoSupport
- invalid bound statement(not found)
- 脉络
- beetl
- beetl是什么
- 与SpringBoot整合
- shiro
- 什么是shiro
- springboot+shrio+mybatis
- 拦截url
- 枚举
- 图片操作
- restful
- java项目中日志处理
- JSON
- 文件工具类
- KeyTool生成证书
- 兼容性问题
- 开发规范
- 工具类开发规范
- 压缩图片
- 异常处理
- web
- JavaScript
- 基础语法
- 创建对象
- BOM
- window对象
- DOM
- 闭包
- form提交-文件上传
- td中内容过长
- 问题1
- js高级
- js文件操作
- 函数_01
- session
- jQuery
- 函数01
- data()
- siblings
- index()与eq()
- select2
- 动态样式
- bootstrap
- 表单验证
- 表格
- MUI
- HTML
- iframe
- label标签
- 规范编程
- layer
- sss
- 微信小程序
- 基础知识
- 实践
- 自定义组件
- 修改自定义组件的样式
- 基础概念
- appid
- 跳转
- 小程序发送ajax
- 微信小程序上下拉刷新
- if
- 工具
- idea
- Git
- maven
- svn
- Netty
- 基础概念
- Handler
- SimpleChannelInboundHandler 与 ChannelInboundHandler
- 网络编程
- 网络I/O
- database
- oracle
- 游标
- PLSQL Developer
- mysql
- MySQL基准测试
- mysql备份
- mysql主从不同步
- mysql安装
- mysql函数大全
- SQL语句
- 修改配置
- 关键字
- 主从搭建
- centos下用rpm包安装mysql
- 常用sql
- information_scheme数据库
- 值得学的博客
- mysql学习
- 运维
- mysql权限
- 配置信息
- 好文mark
- jsp
- jsp EL表达式
- C
- test