关于性能瓶颈分析的一些小窍门

时间:2022-12-10 21:57:22

分析性能瓶颈需要了解系统部署架构,知道瓶颈可能会发生在哪些节点上,并熟悉查看各个节点指标数据的方法。

一、系统部署架构

一个典型的系统部署架构,有硬件服务器,包括应用系统所在的服务器、数据库服务器、负载均衡器等,还有Web服务器、App应用服务器、数据库等软件,性能瓶颈会散布在各个节点上。可以通过查看其性能指标来分析这些节点是否出现性能瓶颈。此外,有些项目使用的第三方工作流、ETL等工具,通常也会提供性能指标。

二、监控

一个好的监控系统可以快速获得节点的性能信息。当系统被部署在云端(例如阿里云)时,云服务商也会提供比较成熟的监控能力,监控对象包括CPU平均使用率、可用内存、平均读写磁盘数、网络输入输出字节数、数据库连接数、队列深度等指标。当我们需要自己构建监控系统时,可以使用Prometheus、Grafana、Spring Boot Actuator和AlertManager构建微服务监控系统。最后,如果没有监控系统,也可以手工去各节点收集需要的指标信息,当然效率相对较低。

除了监控系统提供的信息外,服务器端的日志文件也是分析性能瓶颈的重要依据,我们可以使用特殊关键字如OutOfMemory、SQLException、Error等进行搜索。

三、分析过程

首先要排除压测工具自己导致的瓶颈。例如用JMeter做压测,要确定单台机器允许启动的最大线程数。一般会使用两台配置相当的机器,一台部署JMeter,另一台部署Mock服务器(服务器返回简单的字符串即可),通过不断调整JMeter的并发线程,找到允许的最大并发数。

如何帮助JMeter提高并发线程数呢?

  • 修改JMeter启动文件,增加虚拟机允许的内存使用量。
  • 用命令行模式启动压测,而不是使用其界面模式。JMeter的界面模式只用于脚本的调试。
  • 正式压测时移除JMeter的监听器以提高性能。

如果需要更大的压测请求量,可以用多机并发压测(主从机模式),或者使用云压测平台。压测过程中,会碰到系统响应时间长、压测请求数上不去等情况,可以查看各个节点的性能指标去发现其性能瓶颈,主要关注如下指标。

  1. 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占用率,可以对过多的请求做限流处理。

  1. 内存

随着压测请求增加,通常内存使用量也会增加,我们需要注意当压测请求量消失一段时间后,内存有没有恢复到压测前的水平,如果没有恢复,则系统可能存在内存泄漏。

Java虚拟机中,如果代码创建了大量生命周期长的临时对象,会使内存使用率一直居高不下,高内存使用率会频繁触发垃圾回收机制,垃圾回收执行时会降低系统的响应能力。

  1. 磁盘I/O

当磁盘成为性能瓶颈时,一般会出现磁盘I/O繁忙,导致执行程序在I/O处等待。在Linux中,使用top命令查看wa数据,判断CPU是否长时间等待I/O。

用iostat -x命令查看磁盘工作时间,返回数据中的%util是磁盘读写操作的百分比时间,如果超过70%就说明磁盘比较繁忙了,返回的await数据是平均每次磁盘读写的等待时间。

用iostat -d可以查看磁盘的吞吐量信息,返回数据中的tps是每秒的读写次数,其他数据是磁盘的读写数据量统计。

  1. 网络带宽

一般在局域网做压测,网络带宽很少出现瓶颈。当传输大数据量,带宽同时被其他应用占用以及有网络限速等情况时,则带宽可能成为性能瓶颈。理论上,1000Mbit/s网卡的传输速度是125MB/s,100Mbit/s网卡是12.5MB/s,实际的传输速度会受如交换机、网卡等配套设备影响。在Linux服务器上查看网络流量的工具很多,有vnStat、NetHogs、iftop等。

  1. 数据库服务器

以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%';查看数据库的当前连接数。
  1. Web应用服务器

在Tomcat的管理界面,导航到/manager/status页面,查看JVM的内存使用、请求线程数据以及Tomcat的服务器信息。在/manager/html界面,通过Find leaks按钮对应用程序中的内存泄漏进行诊断。

  1. App应用服务器

以WebLogic为例,登录管理控制台界面能够看到的指标包括:

  • JVM的内存利用率统计信息,包括当前堆大小、当前空闲堆等;
  • JMS消息队列的连接统计数据,包括当前连接数、最大连接数等;
  • JDBC连接池的相关统计数据;
  • 当前应用服务器的线程活动信息,包括执行线程数、空闲线程数、吞吐量、完成的请求数等。

对整个系统的全链路压测,一般会选择专门的性能测试团队来操作。而测试人员在微服务项目中,更多是基于领域来进行测试工作的。