前言:今天测试部门的小梦找到我,委屈巴巴的说我写的接口有问题,因为她对这个接口进行压力测试时,发现系统的吞吐量一直上不去,并且 应用服务器 (部署接口项目的服务器) 的CPU、内存等资源的使用率也一直很低,导致一直无法测试出这个接口的压力峰值。

听小梦说完后,自己心想接口都测试了好几遍了,接口代码 绝对不可能有问题的,再说了,有问题也不能承认呀,看来得往别的地方上扯扯呀;然后我说道,接口应该是没问题的,可能是项目环境部署时有些参数没进行调优吧,例如:连接数大小设置、JVM参数设置、数据库参数优化等;

然后我接着说道,项目是谁给你部署配置的呀,小梦说是小王部署的,然后今天小王也没来上班;我说道,小王没来上班呀,没事,让我来,我这bug绝缘体质,任何问题遇到我都会退避三舍的。

上面的情景,我相信大家都可能会遇到过的;接下来我们就通过这次排查压测问题来聊聊一个 单体系统 的性能优化应该考虑哪些点,以及对这些点该怎么进行调优 。

本文主线如下图:

项目部署环境:在进行这次压测问题排查前,先通过下图了解下 接口项目的情况、项目部署的环境、JMeter测试脚本 的配置情况;

上图中的接口项目、Redis、MySql 都是单机安装部署的 。

注意: 再进行下文之前,我们还需要记住一个前提:本项目中的接口代码是不存在问题的,并且数据库查询SQL都是最优的,都是走索引查询的,本次压力测试问题不是由于代码导致的,而是由于各种参数未调优造成的;代码调优和SQL调优在编码阶段就已经完成了。

简单性能调优的点:在上文中的项目部署情况和测试脚本的配置情况下进行压力测试时,就出现了小梦说的系统吞吐量上不去,以及应用服务器(部署接口项目的服务器)的 CPU 等资源使用率都很低的情况;

查看 JMeter 测试时系统的吞吐量如下图:

查看应用服务器(部署接口项目的服务器)的CPU使用率很低:

按照测试脚本的50个并发以及接口中含有计算密集型操作(加解密和验签)的情况,CPU是不应该这么低的;哎!什么鬼嘛?

别急,下面我们就展开具体的排查过程,并在排查过程中逐步了解各个调优的点;

排查过程就是按照文章开头中的 本文主线 图片中 简单性能调优的点 展开的 。

排查Tomcat连接器参数配置:

Tomcat 连接器参数配置只需要考虑以下几个方面:Connector使用哪种 protocol 协议HTTP/1.1:默认值,使用的协议与Tomcat版本有关

建议使用 NIO2:org.apache.coyote.http11.Http11Nio2Protocol

除了NIO2协议外,还有 BIO、NIO、APR 协议,可以自行去查阅资料;

acceptCount:等待队列的长度;当等待队列中连接的个数达到acceptCount时,说明队列已满,再进来的请求一律被拒绝;默认值是100。

maxConnections:Tomcat 在任意时刻接收和处理的最大连接数;当连接数达到最大值maxConnections后,Tomcat会继续接收连接,直到accept等待队列填满。

如果最大连接数设置为-1,则表示禁用maxconnections功能,表示不限制tomcat容器的连接数;

最大连接数默认值与连接器使用的 protocol 协议有关:NIO的默认值是10000;

APR/native的默认值是8192;

BIO的默认值为maxThreads(如果配置了Executor,则默认值是Executor的maxThreads);

maxThreads:每一次HTTP请求到达 Tomcat,都会创建一个线程来处理该请求,那么最大线程数决定了Tomcat 可以同时处理多少个请求。maxThreads 默认200;

建议:maxThreads应该设置大些,以便能够充分利用CPU;当然,也不是越大越好,如果maxThreads过大,那么CPU会花费大量的时间用于线程的上下文切换,整体效率可能会降低;这需要根据自己项目的情况和服务器硬件配置情况配置合适的值即可;

下面就是本次压测时配置的Tomcat连接器参数:

port="8080"

protocol="org.apache.coyote.http11.Http11Nio2Protocol"

maxThreads="1000"

maxConnections="2000"

acceptCount="1000"

connectionTimeout="20000"

redirectPort="8443"

enableLookups="false"

maxPostSize="10485760"

compression="on"

disableUploadTimeout="true"

compressionMinSize="2048"

acceptorThreadCount="2"

compressableMimeType="text/html,text/xml,text/css,text/javascript"

URIEncoding="utf-8" />

上面连接器中配置参数:的连接器使用的 protocol 协议是 NIO2

最大线程数 maxThreads="1000"

最大连接数 maxConnections="2000"

等待队列大小 acceptCount="1000"

根据上面连接器配置参数,和压测脚本配置的并发请求才50个,确定压测问题应该不是由于连接器参数造成的。

其实在查看Tomcat配置文件 server.xml 中的连接器参数前,可以使用下面这个命令先直接统计出 JMeter与Tomcat建立的Http连接数: 注意 8080 指的是 Tomcat 端口号,使用前改成你的Tomcat配置的端口netstat -pan | grep 8080 | wc -l

如果统计出的连接数与测试脚本中配置的并发数的话差不多一致的话,说明当前连接器是可以满足连接请求处理的,初步可以判断不是由于连接器参数造成的本次压测问题;然后再可以去查看配置文件中的参数进行确认下。

排查 JVM 参数配置:JVM参数配置,一般并发不高的系统只需要配置下Heap堆内存的大小即可,其余使用默认配置即可。

注意:JVM 参数配置比较复杂,这块的参数调优需要根据具体项目情况、服务器硬件配置等进行合理配置。

查看当前压测的接口项目 JVM 配置参数:直接使用命令查看:ps -ef | grep tomcat

结果如下:

也可以直接去 catalina.sh 配置文件中查看:JAVA_OPTS=" -server -Xms6000m -Xmx6000m "也可以直接通过 jmap 命令查看 JVM 的堆的配置信息:

注意:下面命令中的 129761 是tomcat的 pid 进程号;jmap -heap 129761

结果如下:

看到这,应该会有人问,为什么你的初始堆大小和最大堆大小(-Xms6000m -Xmx6000m)设置为一样呢?

因为如果虚拟机启动时设置的初始堆内存比较小,这个时候又需要初始化很多对象数据,那么虚拟机就必须不断地扩大堆内存,这样也会产生一些消耗的。

排查下是否由于JVM参数配置的不合理导致:使用上面提到的 jmap 命令查看下当前堆内存的使用情况jmap -heap 129761

通过查看上面的堆内存的使用情况,发现还有很多空间使用呢,应该不是由于JVM参数不合理导致的压测问题;

但是咱别着急,咱再查看下JVM中垃圾回收GC的情况;使用命令 jstat 查看垃圾回收GC的情况:

注意:129761 为Tocamt的pid; 1000 表示间隔时间毫秒,10 表示输出10次GC情况jstat -gc 129761 1000 10

看了上面的GC情况,发现垃圾回收也没什么异常,FGC总共就3次,通过查看的堆使用情况和GC垃圾回收的情况可以确认压测的问题不是由于JVM的参数导致的。

看来这次压测的问题挺棘手呀,到现在还没有确认出问题原因呢!难道我这bug绝缘体质由于 今天吃的比较多,导致失效了吗? 皱眉 ing . . . . .

看来还得接着排查,咱直接导出当前接口服务应用进程的 线程堆栈信息 看看吧。使用命令jstack导出线程栈信息:

注意:129761 为Tomcat 的pid, /usr/local/test.log 为生成的线程堆栈文件 test.log 的存放地址jstack 129761 >> /usr/local/test.log

导出线程堆栈信息后,使用命令搜索出状态为 WAITING 的线程;

注意:找 State 为 WAITING 状态的线程;

命令如下:test.log 文件为刚刚导出的 线程堆栈信息文件cat test.log | grep -n20 " WAITING "

在命令执行后的搜索结果中发现了下图内容:

注意:

除了线程状态为 WAITING 的之外,还特别要注意 WAITING 状态线程的方法调用栈中存在项目业务代码的;上面图片中就展示了线程状态为 WAITING 等待的调用方法栈中有业务代码;

业务代码是去Redis中查询数据,上图中第二个圈中的内容就是业务代码,并且这行代码上方是去Redis连接池中获取连接,由此确定是由于Redis连接获取不到,导致线程处于 WAITING 等待状态;

由于接口服务系统中很多线程获取不到Redis连接导致阻塞,从而无法充分利用CPU;所以在压测时,服务器CPU的使用率也压不上去,CPU的使用率很低;至此,终于排查出了一处问题地方,不容易呀,感觉排查问题比写代码困难多了!

上面通过线程的堆栈信息排查出 Redis 连接不够用,应该是 Redis 连接池中的最大连接数配置的比较小,那接下来就确定下连接池的配置数据。

排查连接池参数配置:

上文中,在线程的堆栈信息中排查出存在很多线程由于获取不到Redis连接导致处于等待阻塞状态;

接下来,咱们就来具体统计下现在处于压测中的应用服务器(部署接口项目的服务器)与Redis建立的连接数,顺带一起再排查下项目中使用的MySql 的连接池配置是否也存在问题?使用命令查看当前压测中的应用服务器与Redis建立的连接数

注意:6379 为 redis的端口号netstat -pan | grep 6379 | wc -l

执行命令查询出与Redis建立的连接数为 10,这在测试脚本50个并发请求下是一定不够用的呀,应该是配置的Redis连接池的最大连接数比较小;

然后通过看接口代码中的配置文件发现,确实Redis连接池中的最大连接数配置是 10 个;最后修改了最大连接数为 300 个;注意:这个最大连接数需要根据项目情况和测试计划来设置,不用设置的太大。接着,使用命令顺带统计下当前处于压测中的应用服务器(部署接口项目的服务器)与MySql 建立的连接数

注意:3306 为MySql 的端口号netstat -pan | grep 3306 | wc -l

执行命令发现已经建立的MySql 连接数是 50,然后通过查看配置文件的连接池中最大的连接数为100,发现还没有达到最大连接数,说明 JDBC 连接够用,本次压测问题不是由于JDBC连接不够用导致的;并且在上文中查看线程的堆栈信息时,也没有发现调用 JDBC 操作的线程处于 WAITING 等待状态。

排查完了数据库连接池了,咱们就再排查下MySql 数据库是否进行了参数调优;

如果MySql 数据库没有进行调优的话,那在压测时就会出现数据库的读写性能比较差,也就是项目中在进行 JDBC 增删改查操作时会比较慢,进而导致存在JDBC操作的线程执行慢,无法充分利用CPU的并发计算能力,所以也会导致应用服务器的CPU使用率比较低,最终压测时整个接口应用系统的吞吐量也很低 。

排查MySql 数据库调优配置:接下来咱排查下MySql 数据库是否进行了参数调优;

排查前先聊一个由于之前MySql 数据库未进行优化,而导致的压测问题。

MySql 数据库未调优,引发的压测问题 简述:

之前压测时的场景还原:

在压测前所有该调优的地方都调了,就单独忘记对MySql 数据库进行调优了,最终导致对应用压测时,发现应用服务器(部署接口项目的服务器)的CPU的使用率一直浮动在60%左右,始终压不上去,即使加大压测时的并发请求数,发现还是不行;

最终通过查看MySql 服务器的磁盘IO的情况和MySql 数据库进程的CPU、内存等使用率发现MySql 没有被优化,所以导致MySql 数据库的读写能力被限制,进而导致应用并发处理能力下降,从而导致应用服务器的CPU使用率一直升不上去。使用命令统计下压测时 MySql 数据库所部署在的服务器的磁盘IO性能:

注意: 1 指的是 间隔时间1秒, 5 指的是统计5次 IO 的情况;iostat -xdk 1 5

结果如下:

只需要注意图中圈起来的地方;await 指的是 磁盘读写时的等待时间,这个值越小越好;%util 指的是磁盘整体的负载情况,值越大说明磁盘负载快达到极限了。使用命令查看MySql 进程的CPU、内存的使用率:

注意: 14208 是MySql 的pid;top -p 14208

结果如图:

注意:

当时就是通过这两条命令统计出的数据,发现数据库服务器磁盘IO的负载一直处于90%,快达到极限了;但是MySql 进程的CPU、内存的使用率却很低;

通过这两条数据可以初步确定MySql 没有进行优化;如果MySql 进行了调优,那么MySql 的进程在压测时的CPU、内存等使用率不可能这么低,并且磁盘 IO 的负载也不会达到了极限;

得出初步结论后,然后去查看MySql 数据库的配置文件 my.cnf, 发现确实没有进行一些参数的优化,只是简单配置了最大连接数为 500;注意,MySql 数据库默认的最大连接数是 100 个;

最后在 my.cnf 配置文件中简单配置了下 innodb 存储引擎缓冲池大小 等;这里就不具体描述调优的参数了,因为调优参数都是需要根据项目情况、服务器硬件配置等综合考虑配置的;大家可以自行网上查阅MySql 数据库调优的相关资料;

为什么配置下 innodb 存储引擎缓冲池大小 等参数就会极大的提升数据库的读写性能呢?

通过下面这张图片就会知道为什么了:

通过上图可以了解到进行数据库读写时,首先都在对内存中的innodb存储引擎的缓冲池中的数据进行操作,如果缓冲池中不存在操作的数据,则需要进行磁盘IO将数据读取到内存中的,所以这样读写速度就会慢很多;

所以如果缓冲池比较小的话,无法存放很多数据(数据页)的话,则需要进行磁盘IO(磁盘IO很耗时的),那么数据库读写性能会比较差,所以需要对MySql 的存储引擎的缓存池等参数进行调优配置。

配置好后,重启了MySql 数据库,然后重新进行压测,发现应用服务器(部署接口项目的服务器)的CPU使用率上去了,MySql 数据库进程的CPU、内存等使用率也升上去了,并且磁盘IO的负载也降下来了,最后整个应用系统的吞吐量也上去了,也支持更大的并发数了。说完了上面之前遇到的一个压测小场景,咱们接着按照上面的排查步骤排查这次压测的问题,发现MySql 数据库已经进行了调优,磁盘IO的读写速度也是OK的,所以说本次压测问题与MySql 数据库参数配置无关。

排查完了MySql 数据库后,咱接着排查下Linux服务器的参数是否进行过调优吧!

排查Linux服务器参数配置:服务器参数调优这块目前了解的不多,只知道配置下服务器的 文件句柄数 fd ;建议将服务器的文件句柄数设置的大些;为什么设置大些呢?

因为主流操作系统的设计是将 TCP/UDP 连接采用与文件一样的方式去管理,即一个连接对应于一个文件描述符(文件句柄);

主流的 Linux 服务器默认所支持最大 文件句柄数 数量为 1024,当并发连接数很大时很容易因为 文件句柄数 不足而出现 “open too many files” 错误,导致新的连接无法建立。

建议将 Linux 服务器所支持的最大句柄数调高数倍(具体与服务器的内存数量相关)。使用命令查看当前服务器的文件句柄数:ulimit -a

结果如图:

上图中的文件句柄数是已经修改过的;设置文件句柄数可以设置临时值,也可以设置永久值,建议设置成永久值,因为临时值遇到一些情况会失效的。

配置文件句柄数可以自行去网上查询,资料很多的,本文就不做过多描述了。聊完服务器参数调优配置后,咱最后再聊聊 JMeter 测试工具在压测时有没有该注意的点!

JMeter 分布式测试:

这里主要聊聊 JMeter 分布式测试的内容;什么时候需要进行分布式测试,当你的单机 JMeter 服务器由于硬件配置限制无法构建出足够的并发压力时,这是就需要进行分布式部署测试了;

怎么判断 单机的 JMeter 服务器 已经无法构建出足够的并发压力了呢?通过查看 JMeter 测试服务器的CPU的使用率情况,当 JMeter 测试服务器的CPU使用率达到 90% 多时,此时就可以初步确认CPU无法在提供足够的计算能力来构建并发压力了;

所以此时可以将单机的JMeter改为分布式JMeter进行测试,只有构建出足够的压力,才能将应用服务器(部署接口项目的服务器)的CPU、内存等资源的使用率压上去,从而测试出接口的压力峰值。所以,当单机 JMeter 压测时发现应用服务器(部署接口项目的服务器)CPU、内存等使用率压不上去的话,也可以去排查下是否是由于JMeter服务器硬件配置不足造成的;

本次压力问题,发现 JMeter 测试服务器在压测时 CPU 的使用率达到了 80%多,说明此台测试服务器由于硬件限制也是无法构建更大的并发压力了,所以建议将单机 JMeter 测试改为 分布式测试;

这里 JMeter 分布式测试网上教程很多,本文就不做过多描述了。

到这里,本人认为的所有该调优的点都排查完; 今啊老百姓真呀真呀真高兴!

本次排查总结:

排查完上面的几个点后,最终发现了导致本次压测问题的原因:Redis 连接池的最大连接数配置的偏小

JMeter 单机测试无法构造出足够的并发压力

正是由于上面的两个问题导致了本次压测出现了下面的问题:压测时应用系统的吞吐量偏低

并且应用服务器(部署接口项目的服务器)的CPU、内存等使用率偏低;将上面的两处问题修改过后,重新进行压测,发现一切正常了!

在此,再说明下本次压测项目就是一个简单的单体项目,项目中没有涉及到分库分表、各种中间件以及分布式等,所以排查起来还相对简单些 ,否则问题排查会更加困难的。

由于本人水平有限,如果有未提及到的调优的点,请评论留言呀!

扩展

在排查问题时,如果有一些 排查工具 的话,将极大的方便我们排查问题,从而使我们快速的定位到问题原因!

下面就介绍两个在排查问题非常好用的辅助工具:Arthas : 阿里开源的线上Java应用诊断工具

jvisualvm :JDK中自带的 JVM 运行状态监控工具

❤ 点赞 + 评论 + 转发 哟

如果本文对您有帮助的话,请挥动下您爱发财的小手点下赞呀,您的支持就是我不断创作的动力,谢谢!

您可以VX搜索【木子雷】公众号,大量Java学习干货文章,您可以来瞧一瞧哟!

压测导致mysql数据库CPU很高_排查压测问题引发的系统性能调优过程相关推荐

  1. MySQL占用CPU过高,排查原因及解决的多种方式法

    一.mysql中的wait_timeout坑 mysql> show variables like '%timeout%'; 首先你要明白: wait_timeout - 指的是mysql在关闭 ...

  2. json.tojsonstring 导致cpu飙高_阿里调试神器立功了!进程导致Kubernetes节点CPU飙高的排查与解决...

    来源:https://www.cnblogs.com/maxzhang1985/p/12673160.html 一.发现问题 在一次系统上线后,我们发现某几个节点在长时间运行后会出现CPU持续飙升的问 ...

  3. php木马导致服务器流出流量很高的排查及临时解决方法

    近段时间服务器上经常出现流出的流量达到百分之八九十左右,很是让人恼火. 对于服务器流量流出100%排查流程及方法: 症状:流出流量偶尔达到98%左右.并持续一段时间.停止iis或停掉80端口后就恢复正 ...

  4. mysql连接数thread_MySQL数据库负载很高连接数很多怎么处理

    MySQL数据库负载很高连接数很多怎么处理 在MySQL数据库连接数很多,而且大多属于活跃的状态时MySQL机器基本上负载很高,属于基本上快要死去的状态了. 这时怎么办呢? 一.可能有两个办法: 方法 ...

  5. linux mysql cpu 高,Linux系统中关于Mysql数据库导致CPU很高的问题解决

    Linux系统中关于Mysql数据库导致CPU很高的问题解决 发布时间:2007-11-19 00:01:12来源:红联作者:spworks 服务器环境 Liunx AS4 + PHP5 + Mysq ...

  6. mysql利用cpu率高_MySQL高CPU使用率

    首先,我想您可能要关闭持久性连接,因为它们几乎总是弊大于利. 其次,我想您要仔细检查您的MySQL用户,以确保任何人都无法从远程服务器进行连接.这也是要检查的主要安全事项. 第三,我想说你想打开MyS ...

  7. mysql利用cpu率高_MySQL CPU 使用率高的原因和解决方法

    用户在使用 MySQL 实例时,会遇到 CPU 使用率过高甚至达到 100% 的情况.本文将介绍造成该状况的常见原因以及解决方法,并通过 CPU 使用率为 100% 的典型场景,来分析引起该状况的原因 ...

  8. MySQL占用CPU过高

    服务器MySQL占用CPU过高时,应排查的因素包括: 进程列表 排除高并发因素先要找到导致CPU过高的SQL mysql> SHOW PROCESSLIST; 查找负荷最重的SQL语句,优化该S ...

  9. memcached 如果进程占用cpu很高

    memcached 如果进程占用cpu很高 一客户占用到了 25% 把mencache内存大小从32m 改成256m 后 memcached 基本占用cpu 是0 可能分配的内存不够用了  大量的新缓 ...

最新文章

  1. 梯度下降法 —— 经典的优化方法
  2. 路由器配置与管理完全手册(H3C篇)学习感想
  3. codevs 1082 线段树区间求和
  4. z-index的最大值、最小值
  5. 最新 MSDN Library for Visual Studio 2008 SP1
  6. 最牛逼的开源机器学习框架,你知道几个
  7. 前端学习(1477):计算属性文档分析
  8. 【Python】Python中常用的字符串处理函数
  9. “生而强悍” vivo iQOO官宣3月1日发布
  10. 计算机用三角函数时如何用弧度制,三角函数1任意角和弧度制.PPT
  11. 牛顿插值法C语言实现
  12. windows补丁修复
  13. Linux入侵之隐藏你的踪迹
  14. 【IDEA】idea插件的安装和删除
  15. Leetcode_116_Populating Next Right Pointers in Each Node
  16. java验证字符是否为字母_Java程序检查字符是否为字母
  17. python实现电子邮件附件指定时间段,批量下载以及C#小程序集成实现
  18. JMP指令寻址方式总结,JMP BX指令寻址方式是什么
  19. 计算机考博复试基础知识,考博复试笔试备考攻略
  20. 李炎恢《PHP第二季视频教程》之总结

热门文章

  1. ICITR 2021 | 排序算法中的用户公平性、item公平性和多样性
  2. 研发大佬组团带玩生成对抗网络(GAN),B站直播教学
  3. 超越谷歌BERT!依图推出预训练语言理解模型ConvBERT
  4. 综述:Image Caption 任务之语句多样性
  5. 超全总结:神经网络加速之量化模型 | 附带代码
  6. python数字转汉字-Python转换数字到中文大写格式
  7. java lambdamart库,LambdaMART 之 lambda(示例代码)
  8. 开正交时候卡顿_王者荣耀:不管用WiFi还是流量都是卡顿咋办!4个办法让你变流畅...
  9. spring-基于注解的aop开发(快速入门)
  10. 使用okhttp3执行post请求