10分钟后性能测试瓶颈调优!想进大厂这个必须会

2022-06-22  本文已影响0人  Fightover

目录

引言:性能瓶颈调优

在实际的性能测试中,会遇到各种各样的问题,比如 TPS 压不上去等,导致这种现象的原因有很多,测试人员应配合开发人员进行分析,尽快找出瓶颈所在。

性能调优步骤

  1. 确定问题:根据性能监控的数据和性能分析的结果,确定性能存在的问题。
  2. 确定原因:确定问题之后,对问题进行分析,找出问题的原因。
  3. 确定解决方案(改服务器参数配置/增加硬件资源配置/修改代码)。
  4. 验证解决方案,分析调优结果。

注意:性能测试调优并不是一次完成的过程,针对同一个性能问题,上述步骤可能要经过多次循环才能最终完成性能调优的目标,即:测试发现问题 -> 找原因 -> 调整 -> 验证 -> 分析 -> 再测试 ...

性能瓶颈概率分布

60%:数据库瓶颈

25%:应用瓶颈

10%:压测工具瓶颈

5%:Linux 机器出现异常

系统资源


发现了瓶颈后,只要对症下药就可以了。简单来说无论哪个地方出现瓶颈,只需要降低压力或者增加这部分瓶颈资源(应用软件没有瓶颈或优化空间之后),即可缓解症状。

CPU

后台服务的所有指令和数据处理都是由 CPU 负责,服务对 CPU 的利用率对服务的性能起着决定性的作用。

top 参数详解

下面以 top 命令的输出例,对 CPU 各项主要指标进行说明:

性能分析思路

案例分析

现象:CPU 的 us 和 sy 不高,但 wa 很高。

如果被测服务是磁盘 I/O 密集型服务,wa 高属于正常现象。但如果不是此类服务,最可能导致 wa 高的原因有两个:

LOAD

Linux 的系统负载指在特定时间间隔内(一个 CPU 周期)运行队列中的平均进程数。

(注意:Linux 中的 Load 体现的是整体系统负载,即 CPU 负载 + 磁盘负载 + 网络负载 + 其余外设负载,并不能完全等同于 CPU 使用率。而在其余系统如 Unix,Load 还是只代表 CPU 复杂。)

从服务器负载的定义可以看出,服务器运行最理想的状态是所有 CPU 核心的运行队列都为 1,即所有活动进程都在运行,没有等待。这种状态下服务器运行在负载阈值下。

通常情况下,按照经验值,服务器的负载应位于阈值的 70%~80%,这样既能利用服务器大部分性能,又留有一定的性能冗余应对流量增长。

查看系统负载阈值的命令如下:


Linux 提供了很多查看系统负载的命令,最常用的是 top 和 uptime

top 和 uptime 针对负载的输出内容相同,都是系统最近 1 分钟、5 分钟、15 分钟的负载均值

这三个数值的使用方法和 CPU 核数相关,首先确认 CPU 物理总核数:

示例:

[root@localhost home]# cat /proc/cpuinfo |grep "physical id"
physical id     : 0
physical id     : 0
[root@localhost home]# cat /proc/cpuinfo |grep "cpu cores"
cpu cores       : 2
cpu cores       : 2

物理 CPU 个数为 0+1=1 个,每个 CPU 的核数为 2 个,所以总的物理核数为 2x1=2。

计算结果说明该机器的在单位时间内可以处理的进程数是 2 个,如果单位时间内进程数超过 2 个,就会出现拥堵的情况,load 就会持续增高,增高到一定程度,就会出现系统崩溃等异常情况。


在性能测试过程中,系统负载是评价整个系统运行状况最重要的指标之一。通常情况下:


机器针对突发情况的处理

内存

性能测试过程中对内存监控的主要目的是检查被测服务所占用内存的波动情况。

top 参数详解

在 Linux 系统中有多个命令可以获取指定进程的内存使用情况,最常用的是 top 命令,如下图所示:

从上面的解释可以看出,测试过程中主要监控 RES 和 VIRT,对于使用了共享内存的多进程架构服务,还需要监控 SHR。

free 参数详解

free 命令显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。如果加上 -h 选项(控制显示单位),输出的结果会友好很多:

有时我们需要持续的观察内存的状况,此时可以使用 -s 选项并指定间隔的秒数:如 free -h -s 3 表示每隔 3 秒输出一次内存的使用情况,直到按下 ctrl + c。


释放缓存内存

方式一:手动释放缓存内存

snyc
echo 3 > /proc/sys/vm/drop_caches
free -m

方式二:修改 linux 配置自动释放

/proc/sys/vm/drop_caches 这个值的 0 改为 1

磁盘 I/O

性能测试过程中,如果被测服务对磁盘读写过于频繁,会导致大量请求处于 I/O 等待的状态,系统负载升高,响应时间变长,吞吐量下降。

iostat 参数详解

Linux 下可以用 iostat 命令来监控磁盘状态。

iostat -d 2 10 表示每 2 秒统计一次基础数据,统计 10 次:

从 iostat -d 的输出中,能够获得系统运行最基本的统计数据。但对于性能测试来说,这些数据不能提供更多的信息。需要加上 -x 参数。

iostat -x 参数详解

如 iostat -x 2 10 表示每 2 秒统计一次更详细数据,统计 10 次:

iostat -x 完整参数如下:

- rrqm/s: 每秒进行 merge 的读操作数目。即 delta(rerge)/s 
- wrqm/s: 每秒进行 merge 的写操作数目。即 delta(wmerge)/s 
- t/s: 每秒完成的读 I/O 设备次数。即 delta(rioVs 
- w/s: 每秒完成的写 1/O 设备次数。即 delta(wio)/s 
- rsec/s: 每秒读扇区数。即 delta(rsect)/s 
- ws0c/s: 每秒写扇区数。即 deita(wsect)/s 
- rkB/s: 每秒读 K 字节数。是 rsect/s 的一半,因为每扇区大小为 512 字节。(需要计算) 
- wkB/s: 每秒写 K 字节数。是 wsect/s 的一半。(需要计算) 
- avgrq+sz: 平均每次设备 I/O 操作的数据大小(扇区)。delta(rsect+wsect)/delta(rio+wio) 
- avgqu-sz: 平均I/O队列长度,即delta(avea)/s/1000(因为 aveq 的单位为毫秒)。 
- await: 平均每次设备 I/O 操作的等待时间(毫秒)。即 delta(ruse+wuse)/delta(rio+wio) 
- svctm: 平均每次设备 I/O 操作的服务时间(毫秒)。即 delta(use)/delta(rio+wio) 
- %util:一秒中有百分之多少的时间用于 I/O 操作,或者说一秒中有多少时间 I/O 队列是非空的。即 delta(use)/s/1000(因为 use 的单位为毫秒)

网络

性能测试中网络监控主要包括网络流量、网络连接状态的监控。

网络流量监控

方法很多,网上有很多 shell 脚本。也可以使用 nethogs 命令。该命令与 top 类似,是一个实时交互的命令,运行界面如下:

在后台服务性能测试中,对于返回文本结果的服务,并不需要太多关注在流量方面。


理解带宽

针对一些特定的应用,比如直播或网盘(文件上传下载),带宽瓶颈也是一个出现频率较高的场景。

服务端的带宽分为上行(out)和下行(in)带宽(分别对应客户端的下载和上传)。

一个 Web 服务器如各类新闻网站通常需要更多的服务端上行(out)带宽;而邮件服务器、网盘服务器等则通常需要更多的服务端下行带宽(in)。

理解带宽速率公式

示例:5000 万像素手机拍一张照片,照片大小约 20MB,在下述带宽下需要耗时:


案例分析

现象:从监控图表可以看出,当前的网络流量已经基本将网络带宽占满,因此网络存在瓶颈。

解决方案:

网络连接状态监控

性能测试中对网络的监控主要是监控网络连接状态的变化和异常


Linux 自带的很多命令如 netstat、ss 都支持如上功能。

下图是 netstat 对指定 pid 进程的监控结果:

完整命令输出:

数据库

慢查询

更具体的慢 SQL 分析优化,可参见《MySQL 慢 SQL & 优化方案》。

如 MySQL 资源出现瓶颈,首先找慢查询(超过自定义的执行时间阈值的 SQL)。

1)通过 SQL 语句定位到慢查询日志的所在目录,然后查看日志。

show variables like "slow%";

2)慢查询日志在查询结束以后才纪录,所以在应用反映执行效率出现问题时,查询慢查询日志并不能定位问题。这时可以使用show processlist命令查看当前 MySQL 正在进行的线程状态,可以实时地查看 SQL 的执行情况。

示例:

mysql -uroot -p123456 -h127.0.0.1 -p3307 -e "show full processlist" |grep dbname |grep -v NULL

3)找到慢查询 SQL 后可以用执行计划(explain)进行分析(或反馈给 DBA 和开发处理)。推荐最简单的排查方式,步骤如下:

  1. 分析 SQL 是否加载了不必要的字段/数据。
  2. 分析 SQL 是否命中索引。
  3. 如果 SQL 很复杂,优化 SQL 结构。
  4. 如果表数据量太大,考虑分表。
  5. ……

连接数

数据库连接池的使用率

查看/设置最大连接数

-- 查看最大连接数
mysql> show variables like '%max_connection%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| extra_max_connections |       |
| max_connections       | 2512  |
+-----------------------+-------+
2 rows in set (0.00 sec)

-- 重新设置最大连接数
set global max_connections=1000;

在/etc/my.cnf 里面设置数据库的最大连接数

[mysqld]
max_connections = 1000

查看当前连接数

mysql> show status like  'Threads%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_cached    | 32    |
| Threads_connected | 10    |
| Threads_created   | 50    |
| Threads_rejected  | 0     |
| Threads_running   | 1     |
+-------------------+-------+
5 rows in set (0.00 sec)

查询服务器 thread_cache_size 的值

mysql> show variables like 'thread_cache_size';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| thread_cache_size | 100   |
+-------------------+-------+
1 row in set (0.00 sec)

详见《MySQL 事务和锁》。

缓存命中率

  1. 通常,SQL 查询是从磁盘中的数据库文件中读取数据。
  2. 若当某一个 SQL 查询语句之前执行过,则该 SQL 语句及查询结果都会被缓存下来,下次再查询相同的 SQL 语句时,就会直接从数据库缓存中读取。(注意,MySQL 8 开始已废弃查询缓存功能。)

监控点

案例分析

测试结果分析

结论:从目前的测试结果来看(如下图所示),性能存在问题。

现象:并发数达到 50 时的 TPS 为 52,此时虽然响应时间为 4.4s(小于需求的 5s),但是数据库服务器的 CPU 使用率非常高(接近 100%),因此需要重点关注数据库的调优分析。

排查过程

  1. 使用 top 命令观察,确定是 mysqld 导致还是其他原因。CPU 分为用户 CPU 和内核 CPU。综合其他的各项资源指标来分析,发现内存、磁盘IO、网络等指标无任何异常,因此判断此处不是内核 CPU 占用高,主要原因是用户进程占用的 CPU 高。确认目前 CPU 占用高的为 mysqld 进程。
  2. 分析数据库服务器 CPU 高的可能原因:慢 SQL、SQL 语句过多、连接数过多等。确认是否存在慢 SQL查看慢查询日志,看看是否有超过预期指标的 SQL 语句,并分析排查:看看执行计划是否准确、索引是否缺失、数据量是否太大等。目前案例经过慢查询日志的分析,未存在慢查询。确认是否 SQL 语句过多或连接数过多使用show full processlist查看当前数据库中正在执行的 SQL 语句及连接池的状态,发现大量 SQL 在等待执行。再结合操作过程中的系统日志进行分析,发现每进入一次商城首页,就需要在数据库中执行 19 条查询 SQL。

解决方案

JAVA 应用

JVM

JVM 简介

JVM(JAVA Virtual Machine):虚拟出来的空间,专门供 JAVA 程序运行。


JVM 内存

重点关注:堆区(动态变化)

所有的对象在初始化都会申请堆区的空间,如果已申请的空间在使用结束后没有及时地释放,那么该空间就会被占用,即内存泄漏。

监控点:因此在测试时,需要关注堆区的空间是否持续上升而没有下降。


案例分析

现象:堆内存使用是持续升高,无法降低到之前的水平。

解决方案:找到内存泄漏的代码,并优化代码。

垃圾回收机制

什么是垃圾回收机制

监控点


垃圾回收机制的运行步骤如下:

  1. 新程序执行时需要先申请内存空间,会先从年轻代中申请。
  2. 在年轻代满了以后,就会进行垃圾回收Young GC。
  3. 回收时检查年轻代中的内存,是否还在使用。还在使用的部分会移存到生存区 2 中;不使用的部分则释放,此时年轻代内存空间被清空。
  4. 新程序执行申请内存空间,再从年轻代申请。
  5. 年轻代又满了,就会进行垃圾回收Young GC。还在使用的内存移存到生存区 1 中,并把生存区 2 中的内存也都存到生存区 1 中。此时就会清空年轻代和生存区 2。
  6. 循环上述 1-5 步。
  7. 如果部分内存在生存区中存活很久(内存在生存区中移动了 10 次左右),则将这部分内存放入到老年代中。
  8. 循环上述 1-7 步,直到老年代内存空间全部占满,此时就要进行垃圾回收Full GC。
上一篇 下一篇

猜你喜欢

热点阅读