性能测试必备知识(4)- 使用 stress 和 sysstat 分析平均负载过高的场景
stress 介绍
Linux 系统压力测试工具,这里通过异常进程模拟平均负载升高的场景
来看看 stress 命令行参数的讲解
字段 |
含义 |
---|---|
-?、--help |
帮助文档 |
--version、-v |
版本号 |
-q |
退出 |
-n |
显示已完成指令的情况 |
-t N、--timeout N |
运行 N 秒后停止 |
--backoff N |
等待 N 微秒后开始运行 |
-c N、--cpu N |
产生 N 个进程 每个进程反复的计算随机数的平方根 模拟 CPU 计算密集型场景 |
-i N、--io N |
产生 N 个进程 每个进程反复调用 sync() 模拟 I/O 密集型场景 |
-m N、--vm N |
产生 N 个进程 每个进程不断调用内存分配 malloc() 和内存释放 free() 函数 |
--vm-bytes B |
指定 malloc() 时内存的字节数,默认256MB |
--vm-hang N |
指定执行 free() 前等待的秒数 |
-d N、 --hdd N |
产生 N 个进程 每个进程执行 write() 和 unlink() 的进程 |
--hdd-bytes B |
每个 hdd worker 写入 B 字节(默认为1GB) |
- 产生 N 个进程
- 每个进程反复的计算随机数的平方根
- 模拟 CPU 计算密集型场景
-i N、--io N
- 产生 N 个进程
- 每个进程反复调用 sync()
- 模拟 I/O 密集型场景
-m N、--vm N
- 产生 N 个进程
- 每个进程不断调用内存分配 malloc() 和内存释放 free() 函数
--vm-bytes B 指定 malloc() 时内存的字节数,默认256MB --vm-hang N 指定执行 free() 前等待的秒数 -d N、 --hdd N
- 产生 N 个进程
- 每个进程执行 write() 和 unlink() 的进程
--hdd-bytes B 每个 hdd worker 写入 B 字节(默认为1GB)
Numbers may be suffixed with s,m,h,d,y (time) or B,K,M,G (size)
时间单位可以为秒 s,分m,小时h,天d,年y,文件大小单位可以为 K,M,G
sysstat 介绍
- 包含了常用的 Linux 性能工具,用来监控和分析系统的性能
- 接下来会用到 mpstat 和 pidstat 两个命令
- 后面用单独一篇详细讲解里面包含的所有命令
mpstat
- 常用的多核 CPU 性能分析工具
- 实时查看每个 CPU 的性能指标以及所有 CPU 的平均指标
pidstat
- 常用的进程性能分析工具
- 实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标
安装两个工具
提供百度云盘链接
链接:https://pan.baidu.com/s/1YENSYaGw7Ar1Z8hf8CXGqA
提取码:2tpc
放到 Linux 下的某个目录
解压
tar -zxvf sysstat-12.1.5.tar.gz
tar -zxvf stress-1.0.4.tar.gz
分别进入解压后的两个文件夹执行以下命令
./configure
make&&make install
平均负载和 CPU 使用率的实际栗子
前言
- 前面一篇文章也讲到了平均负载和 CPU 使用率的三个场景,接下来我们分别对这三个场景举例子
- 需要打开三个终端访问同一个 Linux 机器哦
- 我的 Linux 是虚拟机,2个cpu,2核
CPU 密集型进程
第一个终端
在第一个终端运行 stress 命令,模拟一个 CPU 使用率 100% 的场景
stress -c 1 -t 600
第二个终端
运行 uptime 查看系统平均负载情况,-d 参数表示高亮显示变化的区域
watch -d uptime
可以看到,1 分钟的平均负载会慢慢增加到 1.00
第三个终端
运行 mpstat 查看 CPU 使用率的变化情况
mpstat -P ALL 5
可以看出
- 仅有一个 CPU 的使用率接近 100%,但它的 iowait 只有 0
- 这说明,平均负载的升高正是由于 CPU 使用率为 100%
接下来,就要排查是哪个进程导致 CPU 的使用率这么高的
使用 pidstat 命令
间隔 5 秒后输出一组数据
pidstat -u 5 1
从这里可以明显看到,stress 进程的 CPU 使用接近 100%
I/O 密集型进程
第一个终端
运行 stress 命令,但这次模拟 I/O 压力,即不停地执行 sync()
第二个终端
运行 uptime 查看系统平均负载情况,-d 参数表示高亮显示变化的区域
watch -d uptime
可以看到,1 分钟的平均负载也会慢慢增加到 1.00
第三个终端
运行 mpstat 查看 CPU 使用率的变化情况
mpstat -P ALL 5 1
灵魂拷问
其实 iowait 并没有上去,反而还是系统态(%sys)升高了,这是怎么回事?难道是工具的问题?
回答
- iowait 无法升高是因为案例中 使用的是 sync() 系统调用,它的作用是刷新缓冲区内存到磁盘中
stress -i
- 对于新安装的虚拟机,缓冲区可能比较小,无法产生大的io压力
- 这样大部分都是系统调用的消耗了
- 所以,只看到系统 CPU 使用率升高
解决办法
使用 stress 的另一个参数 -d ,含义上面已经说了哦
stress --hdd 1 -t 600 --hdd-bytes 4G
再通过 mpstat 看看指标
mpstat -P ALL 5
可以看到
- iowait 是明显升高了,虽然我们的 CPU 使用率也较高
- 当做了几次尝试之后,包括启动了 2个、4个进程,发现 CPU 使用率仍然保持在 30%+,而 iowait 则不断升高,最高可达到40%+,而且平均负载也在不断升高
- 所以可以看出平均负载的升高,很大原因是因为 iowait 的不断升高
接下来,就要排查是哪个进程导致 iowait 这么高了
使用 pidstat 命令
间隔 5 秒后输出一组数据,收集 10 次,查看最后的平均值
pidstat -u 5 10
可以看到
kworker 写入字节的进程 和 stress 进程的 CPU 使用率都是偏高的
大量进程的场景
目的
当系统中运行进程超出 CPU 运行能力时,就会出现等待 CPU 的进程
第一个终端
这次模拟 8 个进程
stress -c 8 -t 600
第二个终端
运行 uptime 查看系统平均负载情况,-d 参数表示高亮显示变化的区域
watch -d uptime
我的系统只有 4 个 CPU,比 8 个进程少得多,CPU 处于严重的过载状态,平均负载已经超过 8 了
第三个终端
可以直接通过 pidstat 来查看进程的情况了,每隔 5s 收集一次,收集 5 次,看平均值
pidstat -u 5 5
可以看到
- 8 个进程在竞争 4 个 CPU
- 每隔进程等待 CPU 的时间(%wait)高达 50%
- 这些超出 CPU 计算能力的进程,导致 CPU 过载
对于平均负载的一个理解和总结
- 平均负载提供了一个快速查看系统整体性能的手段,反映了整的负载情况
- 但只看平均负载本身,我们并不能直接发现到底是哪里出现了瓶颈
平均负载过高的分析排查思路
- 有可能是 CPU 即密集型进程导致的
- 平均负载过高不代表 CPU 使用率高,也有可能是 I/O 更密集了
- 当发现平均负载过高时,可以通过 mpstat、pidstat 等工具,辅助分析负载的来源
通俗总结
平均负载过高是出现性能瓶颈的表现,分析瓶颈产生的源头和原因,需要通过各类工具
- 在统一的分析平台上构建复杂的数据管道
- 隐藏在注册表的恶意软件 – Poweliks
- 数千万WordPress和Drupal站点存在DDoS风险
- 利用基因突变和K均值预测地区种群
- 缓冲区溢出攻击初学者手册(更新版)
- 在Python机器学习中如何索引、切片和重塑NumPy数组
- HelloWorld,我的第一趟旅程出发点
- Android OpenGL开发实践 - GLSurfaceView对摄像头数据的再处理
- 走进科学:对七夕“超级病毒”XX神器的逆向分析
- 机器学习 - 朴素贝叶斯分类器的意见和文本挖掘
- 认知指纹:颠覆性的身份认证技术
- 跟我学姿势:极客教你如何科学的看电影
- Discuz 5.x/6.x/7.x投票SQL注入分析
- 论如何高效的挖掘漏洞
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 14-2常见软件包管理任务
- Pytest之skip、skipif、xfail
- 为什么spring不推荐@Autowired注入,提示:Field injection is not recommended
- 使用springboot发送复杂类型正文的邮件
- 业务视角谈谈Kafka(第三篇)
- 图文详解互联网根基之HTTP
- Jenkins部署异常:报错 TomcatManagerException: FAIL - Unable to delete
- Spring Boot打包的jar运行的时候提示:没有主清单属性
- 主流消息队列选型技术比较
- 深入浅出-网络七层模型
- 【警惕】K8S下Telnet失效陷阱
- nginx优化之keepalive
- 血泪教训,线程池引发的内存泄露
- RestTemplate设置转换类型
- 详解PROTOCOL BUFFERS