常见性能瓶颈分析方法
分析性能瓶颈需要了解系统部署架构,知道瓶颈可能会发生在哪些节点上,并熟悉查看各个节点指标数据的方法。
一、系统部署架构
一个典型的系统部署架构,有硬件服务器,包括应用系统所在的服务器、数据库服务器、负载均衡器等,还有 Web 服务器、App 应用服务器、数据库等软件,性能瓶颈会散布在各个节点上。可以通过查看其性能指标来分析这些节点是否出现性能瓶颈。此外,有些项目使用的第三方工作流、ETL 等工具,通常也会提供性能指标。
二、监控
一个好的监控系统可以快速获得节点的性能信息。当系统被部署在云端(例如阿里云)时,云服务商也会提供比较成熟的监控能力,监控对象包括 CPU 平均使用率、可用内存、平均读写磁盘数、网络输入输出字节数、数据库连接数、队列深度等指标。当我们需要自己构建监控系统时,可以使用 Prometheus、Grafana、Spring Boot Actuator 和 AlertManager 构建微服务监控系统。最后,如果没有监控系统,也可以手工去各节点收集需要的指标信息,当然效率相对较低。
除了监控系统提供的信息外,服务器端的日志文件也是分析性能瓶颈的重要依据,我们可以使用特殊关键字如 OutOfMemory、SQLException、Error 等进行搜索。
三、分析过程
首先要排除压测工具自己导致的瓶颈。例如用 JMeter 做压测,要确定单台机器允许启动的最大线程数。一般会使用两台配置相当的机器,一台部署 JMeter,另一台部署 Mock 服务器(服务器返回简单的字符串即可),通过不断调整 JMeter 的并发线程,找到允许的最大并发数。
如何帮助 JMeter 提高并发线程数呢?
修改 JMeter 启动文件,增加虚拟机允许的内存使用量。
用命令行模式启动压测,而不是使用其界面模式。JMeter 的界面模式只用于脚本的调试。
正式压测时移除 JMeter 的监听器以提高性能。
如果需要更大的压测请求量,可以用多机并发压测(主从机模式),或者使用云压测平台。压测过程中,会碰到系统响应时间长、压测请求数上不去等情况,可以查看各个节点的性能指标去发现其性能瓶颈,主要关注如下指标。
CPU
通常服务器的 CPU 占用率在 75%以内是正常的,如果长期在 90%以上,就需要将其看作性能瓶颈进行排查。CPU 占用率高,原因通常如下。
代码问题。例如递归调用(当退出机制设计不合理时)、死循环、并发运行了大量线程。
物理内存不足。操作系统会使用虚拟内存,造成过多的页交换而引发 CPU 使用率高。
大量磁盘 I/O 操作。它会让系统频繁中断和切换,引发 CPU 占用率高。
执行计算密集型任务。
硬件损坏或出现病毒。
如果发现服务器 CPU 占用率很高,先检查请求线程数、内存、I/O 使用情况以及 JVM 内存垃圾回收频率等。多核 CPU 的服务器,有时会出现总体 CPU 占用率不高,但某个核的占用率达到 100%的情况(同一个线程会一直占用一个核),就会导致系统响应缓慢。
在 Linux 系统中,可以使用 top 命令查看进程的 CPU 负载,用 vmstat 命令查看系统的 CPU 负载。
vmstat -n 1 表示每秒刷新一次 CPU 负载信息,其返回数据的常见含义如下。
r:运行中的队列数,如果该数值长期大于 CPU 数,则出现 CPU 硬件的瓶颈。
us:用户进程执行时间百分比,简单来说,该数值高通常是由写的程序引起的。
sy:内核系统进程执行时间百分比。
wa:磁盘 I/O 等待时间百分比,数值较高时表明 I/O 等待较为严重。
id:空闲时间百分比。
在压测过程中,吞吐量较低、服务器 CPU 占用不高,可能是业务处理的线程出现了等待状态(例如锁等待)导致的,或者本应并发处理的任务被同步处理,减缓了处理速度。
吞吐量较低、服务器 CPU 占用率很高,则可能是因为服务端在执行 CPU 高消耗的业务,例如复杂算法、压缩/解压缩、序列化/反序列化等。
吞吐量高、服务器 CPU 占用率也高,则表明服务端处理能力强。如果需要降低 CPU 占用率,可以对过多的请求做限流处理。
内存
随着压测请求增加,通常内存使用量也会增加,我们需要注意当压测请求量消失一段时间后,内存有没有恢复到压测前的水平,如果没有恢复,则系统可能存在内存泄漏。
Java 虚拟机中,如果代码创建了大量生命周期长的临时对象,会使内存使用率一直居高不下,高内存使用率会频繁触发垃圾回收机制,垃圾回收执行时会降低系统的响应能力。
磁盘 I/O
当磁盘成为性能瓶颈时,一般会出现磁盘 I/O 繁忙,导致执行程序在 I/O 处等待。在 Linux 中,使用 top 命令查看 wa 数据,判断 CPU 是否长时间等待 I/O。
用 iostat -x 命令查看磁盘工作时间,返回数据中的 %util 是磁盘读写操作的百分比时间,如果超过 70%就说明磁盘比较繁忙了,返回的 await 数据是平均每次磁盘读写的等待时间。
用 iostat -d 可以查看磁盘的吞吐量信息,返回数据中的 tps 是每秒的读写次数,其他数据是磁盘的读写数据量统计。
网络带宽
一般在局域网做压测,网络带宽很少出现瓶颈。当传输大数据量,带宽同时被其他应用占用以及有网络限速等情况时,则带宽可能成为性能瓶颈。理论上,1000Mbit/s 网卡的传输速度是 125MB/s,100Mbit/s 网卡是 12.5MB/s,实际的传输速度会受如交换机、网卡等配套设备影响。在 Linux 服务器上查看网络流量的工具很多,有 vnStat、NetHogs、iftop 等。
数据库服务器
以 MySQL 数据库为例。
检查服务器的硬件资源 CPU、内存、磁盘等是否出现了瓶颈。
开启慢查询日志,使用 set global slow_query_log = 1 记录下超过指定时间的 SQL 语句,定位分析性能瓶颈。
使用 set global innodb_print_all_deadlocks = 1 记录死锁日志。
使用 show variables like '%max_connection%';查看数据库设置的最大连接数,使用 show status like 'Threads%';查看数据库的当前连接数。
Web 应用服务器
在 Tomcat 的管理界面,导航到/manager/status 页面,查看 JVM 的内存使用、请求线程数据以及 Tomcat 的服务器信息。在/manager/html 界面,通过 Find leaks 按钮对应用程序中的内存泄漏进行诊断。
App 应用服务器
以 WebLogic 为例,登录管理控制台界面能够看到的指标包括:
JVM 的内存利用率统计信息,包括当前堆大小、当前空闲堆等;
JMS 消息队列的连接统计数据,包括当前连接数、最大连接数等;
JDBC 连接池的相关统计数据;
当前应用服务器的线程活动信息,包括执行线程数、空闲线程数、吞吐量、完成的请求数等。
对整个系统的全链路压测,一般会选择专门的性能测试团队来操作。而测试人员在微服务项目中,更多是基于领域来进行测试工作的。
版权声明: 本文为 InfoQ 作者【穿过生命散发芬芳】的原创文章。
原文链接:【http://xie.infoq.cn/article/28b3cf40fa48d29ece1a6a544】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论