性能测试常见问题经验汇总

JVM分析神器:visualVM

一、内存泄漏

1、堆内存溢出

现象:

  (1)压测执行一段时间后,系统处理能力下降。这时用JConsole、JVisualVM等工具连上服务器查看GC情况,每次GC回收都不彻底并且可用堆内存越来越少。

  (2)压测持续下去,最终在日志中有报错信息:java.lang.OutOfMemoryError.Java heap space。

排查手段:

  (1)使用jmap -histo pid > test.txt命令将堆内存使用情况保存到test.txt文件中,打开文件查看排在前50的类中有没有熟悉的或者是公司标注的类名,如果有则高度怀疑内存泄漏是这个类导致的。

  (2)如果没有,则使用命令:jmap -dump:live,format=b,file=test.dump pid生成test.dump文件,然后使用MAT进行分析。

  (3)如果怀疑是内存泄漏,也可以使用JProfiler连上服务器在开始跑压测,运行一段时间后点击“Mark Current Values”,后续的运行就会显示增量,这时执行一下GC,观察哪个类没有彻底回收,基本就可以判断是这个类导致的内存泄漏。

解决方式:优化代码,对象使用完毕,需要置成null。

2、持久代溢出

现象:压测执行一段时间后,日志中有报错信息:java.lang.OutOfMemoryError: PermGen space。

产生原因:由于类、方法描述、字段描述、常量池、访问修饰符等一些静态变量太多,将持久代占满导致持久代溢出。

解决方法:修改JVM参数,将XX:MaxPermSize参数调大。尽量减少静态变量。

3、栈内存溢出

现象:压测执行一段时间后,日志中有报错信息:java.lang.StackOverflowError。

产生原因:线程请求的栈深度大于虚拟机所允许的最大深度,递归没返回,戒者循环调用造成。

解决方法:修改JVM参数,将Xss参数改大,增加栈内存。栈内存溢出一定是做批量操作引起的,减少批处理数据量。

4、系统内存溢出

现象:压测执行一段时间后,日志中有报错信息:java.lang.OutOfMemoryError: unable to create new native thread。

产生原因:操作系统没有足够的资源来产生返个线程造成的。系统创建线程时,除了要在Java堆中分配内存外,操作系统本身也需要分配资源来创建线程。因此,当线程数量大到一定程度以后,堆中或许还有空间,但是操作系统分配不出资源来了,就出现这个异常了。

解决方法:

  (1)减少堆内存

  (2)减少线程数量

  (3)如果线程数量不能减少,则减少每个线程的堆栈大小,通过-Xss减小单个线程大小,以便能生产更多的线程。

5、JAVA直接内存溢出

现象:压测执行一段时间后,日志中有报错信息:OutOfMemoryError

产生原因:

  (1)直接内存大多时候也被称为堆外内存,直接内存通过 native 方法可以分配堆外内存,通过 DirectByteBuffer 对象来操作。直接内存不属于 Java 堆,所以它不受堆内存大小限制,但是它受物理内存大小的限制。

  (2)可以通过 -XX:MaxDirectMemorySize 参数来设置最大可用直接内存,如果启动时未设置则默认为最大堆内存大小,即与 -Xmx 相同。即假如最大堆内存为1G,则默认直接内存也为1G,那么 JVM 最大需要的内存大小为2G多一些。当直接内存达到最大限制时就会触发GC,如果回收失败则会引起OutOfMemoryError。

  (3)直接内存在读和写的性能都优于堆内内存,但是内存申请速度却不如堆内内存。

解决方法:因此直接内存适用于需要大内存空间且频繁访问的场合,不适用于频繁申请释放内存的场合。在需要频繁申请的场景下不应该使用直接内存(DirectMemory),而应该使用堆内内存(HeapMemory)。

二、CPU过高

1、us cpu高

现象:压测过程中,使用top命令查看系统资源占用情况,us cpu过高,超过50%以上。

排查手段:

  (1)使用top命令是哪个进程消耗CPU高

  (2)再找到CPU消耗高的线程:top -H -p 进程号

  (3)把线程号转换成16进制:printf "%x\n" 线程号

  (4)再用jstack命令分析这个线程是在干什么:jstack 进程号 | grep 16进制的线程号

  (5)通过JProfiler的CPU Views视图的层层分析,可以清楚的找到造成CPU高的原因

2、sy cpu高

现象:压测过程中,使用top命令查看系统资源占用情况,sy cpu过高,超过50%以上。

排查手段:

  (1)首先查看磁盘繁忙程度、磁盘的队列(iostat、nmon)

  (2)如果磁盘没有问题,则使用strace查看系统内核调用情况

三、线程死锁

现象:

  (1)压测进行一段时间后,程序停顿,报超时错误。但这种现象并不一定就是线程死锁造成的,也可能是数据库/中间件连接池被占满、数据库死锁造成的。

  (2)能够打开页面,但获取不到数据

排查手段:

  (1)使用jstack命令查看Java进程下所有线程的情况:jstack -l 进程号

  (2)如果有Blocked状态的线程,说明有线程死锁的状况。如果大量线程都是Waiting状态,则需要去关注数据库和中间件,可能会有排队情况。

  (3)也可以使用JConsole、JVisualVM及JProfiler等工具直接查看所有线程的情况

四、数据库连接池不释放

现象:压测进行一段时间后,报连接超时的错误。

排查手段:

  (1)去数据库查看应用程序到数据库的连接有多少个:show full processlist。加入应用程序中配置的最大连接数为30,而通过命令show full processlist查看到的从应用服务器连接过来的连接数也为30,证明数据库连接池占满了。

  (2)将应用程序中的最大连接数改大一点(比如100),再重新进行压测,如果还是出现连接池被占满的情况,则证明是数据库连接池不释放造成的.

解决方法:排查代码,数据库连接部分应该是有创建连接但是没有关闭连接的情况。让开发修改代码即可。

五、数据库死锁

现象:

  (1)压测进行一段时间后,报连接超时的错误。

  (2)程序在执行的过程中,点击确定或保存按钮,程序没有响应,也没有出现报错。

排查手段:查看数据库日志,看有没有死锁的情况:show engine innodb status\G。

六、SQL使用不合理

现象:事物响应时间慢

排查手段:

  (1)打开数据库的慢查询

(2)通过命令找到执行比较久的SQL语句:mysqldumpslow

  (3)利用explain来优化这条SQL语句

七、TPS上不去

1、网络带宽

  在压力测试中,有时候要模拟大量的用户请求,如果单位时间内传递的数据包过大,超过了带宽的传输能力,那么就会造成网络资源竞争,间接导致服务端接收到的请求数达不到服务端的处理能力上限。

2、连接池

  最大连接数太少,造成请求等待。连接池一般分为服务器中间件连接池(比如Tomcat)和数据库连接池(或者理解为最大允许连接数也行)。

3、垃圾回收机制

  从常见的应用服务器来说,比如Tomcat,如果堆内存设置比较小,就会造成新生代的Eden区频繁的进行Young GC,老年代的Full GC也回收较频繁,那么对TPS也是有一定影响的,因为垃圾回收时通常会暂停所有线程的工作。

4、数据库

  高并发情况下,如果请求数据需要写入数据库,且需要写入多个表的时候,如果数据库的最大连接数不够,或者写入数据的SQL没有索引没有绑定变量,抑或没有主从分离、读写分离等,就会导致数据库事务处理过慢,影响到TPS。

5、硬件资源

包括CPU(配置、使用率等)、内存(占用率等)、磁盘(I/O、页交换等)。

6、压力机

  比如Jmeter和Loadrunner,单机负载能力有限,如果需要模拟的用户请求数超过其负载极限,也会间接影响TPS(这个时候就需要进行分布式压测来解决其单机负载的问题)。

7、业务逻辑

业务解耦度较低,较为复杂,整个事务处理线被拉长也会导致TPS上不去。

8、系统架构

比如是否有缓存服务,缓存服务器配置,缓存命中率、缓存穿透以及缓存过期等,都会影响到测试结果。

八、500或503错误

现象:压测过程中,服务器返回500或503错误

排查手段

  (1)通过浏览器访问网站,如果浏览器打不开,服务器可能挂了。可能的原因是:内存溢出、数据库连接池满了、线程死锁。

  (2)先看JVM内存是否满了:jstat -gcutil 2384 1000 5

  (3)看数据库连接池大小是否占满,把最大连接数改大,如果还是出现这种现象,证明是数据库连接池不释放。

  (4)最后看是否有线程死锁:jstack -l 进程号

九、性能问题分析流程

  1、查看服务器的CPU、内存 、负载等情况,包括应用服务器和数据库服务器

  2、查看数据库健康状态,数据库死锁、连接池不释放

  3、查看项目日志(查看无报错现象)

  4、查看jvm的gc等情况

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,107评论 1 32
  • 又是一年秋招季,哎呀妈呀我被虐的惨来~这不,前几阵失踪没更新博客,其实是我偷偷把时间用在复习课本了(雾 坚持在社区...
    tengshe789阅读 2,014评论 0 8
  • 开始性能测试前需要了解的内容: 1、项目具体需求。 2、指标:响应时间在多少以内,并发数多少,tps多少,总tps...
    H_5f9c阅读 601评论 0 1
  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 3,323评论 0 6
  • 我从小就和书有着不解之缘,记得第一次接触的书是 绘本 《小红帽》,那是在上学前班之前去父亲工作的地方玩,有一个小朋...
    雪山飞狐儿阅读 426评论 0 0