作者:凡勇

什么是压测

压测,即压力测验,是建立体系安稳性的一种测验办法,通常在体系正常运作范围之外进行,以考察其功用极限和和或许存在的危险。

压测首要用于检测服务器的接受才能,包括用户接受才能,即多少用户一起运用体系时根本不影响质量、流量接受等。别的,经过比方疲惫测验还能发现体系一些安稳性的问题,比方是否存在衔接池中的衔接被耗尽,内存被耗尽,线程池被耗尽,这些只能经过疲惫测验来进行发现定位。

为什么要压测

压测的意图便是经过模仿真有用户的行为,测算出机器的功用(单台机器的 QPS、TPS),然后推算出体系在接受指定用户数(100 W)时,需求多少机器能支撑得住。因此在进行压测时一定要事前设定压测方针值,这个值不能太小,也不能太大,依照目前事务预估的增长量来做一个合理的评价。压测是在上线前为了应对未来或许到达的用户数量的一次预估(提前演练),压测以后经过优化程序的功用或预备满足的机器,来确保用户的体会。压测还能勘探运用体系在呈现买卖洪峰时安稳性状况,以及或许呈现的一些问题,发现运用体系单薄一环,然后更有针对性地进行加强。

压测分类

Java 应用压测性能问题定位经验分享

这几种测验能够穿插进行,一般会在压力测验功用指标合格后,再安排耐久性测验。

压测名词解说

Java 应用压测性能问题定位经验分享

常见的压测东西

ab

ApacheBench 是 Apache 服务器自带的一个 web 压力测验东西,简称 ab。ab 又是一个指令行东西,对建议负载的本机要求很低,依据 ab 指令能够创立许多的并发拜访线程,模仿多个拜访者一起对某一 URL 地址进行拜访,因此能够用来测验方针服务器的负载压力。总的来说 ab 东西小巧简略,上手学习较快,能够供给需求的根本功用指标,可是没有图形化成果,不能监控。

Jmeter

Apache JMeter 是 Apache 组织开发的根据 Java 的压力测验东西。用于对软件做压力测验,它开端被规划用于 Web 运用测验,但后来扩展到其他测验范畴。

JMeter 能够对运用程序做功用/回归测验,经过创立带有断语的脚原本验证你的程序返回了你期望的成果。

JMeter 的功用过于强壮,这儿暂时不介绍用法,能够查询相关文档运用(参阅文献中有引荐的教程文档)

LoadRunner

LoadRunner 是 HP(Mercury)公司出品的一个功用测验东西,功用十分强壮,许多企业级客户都在运用,详细请参阅官网链接。

阿里云PTS

功用测验 PTS(Performance Testing Service)是一款功用测验东西。支撑按需建议压测使命,可供给百万并发、千万 TPS 流量建议才能,100% 兼容 JMeter。供给的场景编列、API 调试、流量定制、流量录制等功用,可快速创立事务压测脚本,精准模仿不同量级用户拜访事务体系,帮助事务快速提高体系功用和安稳性。

作为阿里内部运用多年的功用测验东西,PTS 具备如下特性:

  1. 免运维、开箱即用。SaaS化施压、最大支撑百万级并发、千万级TPS流量自助建议才能。
  2. 支撑多协议HTTP1.1/HTTP2/JDBC/MQTT/Kafka/RokectMq/Redis/Websocket/RMTP/HLS/TCP/UDP/SpringCloud/Dubbo/Grpc 等主流协议。
  3. 支撑流量定制。全球施压地域定制/运营商流量定制/IPv6 流量定制。
  4. 安稳、安全。阿里自研引擎、多年双十一场景打磨、支撑 VPC 网络压测。
  5. 功用压测一站式处理方案。** 0 编码构建杂乱压测场景,覆盖压测场景构建、压测模型设定、建议压力、剖析定位问题、出压测陈述完好的压测生命周期。
  6. 100% 兼容开源 JMeter。
  7. 供给安全、无侵入的生产环境写压测处理方案。

压测东西的比较

Java 应用压测性能问题定位经验分享

怎么挑选压测东西

这个世界上没有最好的东西,只需最合适的东西,东西千千万,挑选一款合适你的才是最重要的,在实践运用中有各种场景,读者能够结合压测进程来确认合适自己的东西:

  1. 确认功用压测方针:功用压测方针或许源于项目计划、事务方需求等
  2. 确认功用压测环境:为了尽或许发挥功用压测作用,功用压测环境应当尽或许同线上环境共同
  3. 确认功用压测经过规范:针对功用压测方针以及选取的功用压测环境,拟定功用压测经过规范,关于不同于线上环境的功用压测环境,经过规范也应当适度放宽
  4. 规划功用压测:编列压测链路,构造功用压测数据,尽或许模仿真实的恳求链路以及恳求负载
  5. 履行功用压测:凭仗功用压测东西,依照规划履行功用压测
  6. 剖析功用压测成果陈述:剖析解读功用压测成果陈述,判定功用压测是否到达预期方针,若不满意,要根据功用压测成果陈述剖析原因

由上述进程可知,一次成功的功用压测触及到多个环节,从场景规划到施压再到剖析,缺一不可。工欲善其事,必先利其器,而一款合适的功用东西意味着咱们能够在尽或许短的时刻内完结一次合理的功用压测,到达事半功倍的效果。

JAVA 运用功用问题排查指南

问题分类

问题五花八门,各种各样的问题都会有。对其进行笼统和分类是十分必要的。这儿将从两个维度来对功用问题进行分类。第一个维度是资源维度,第二个维度是频率维度。

资源维度类的问题:CPU 冲高,内存运用不妥,网络过载。

频率维度类的问题:买卖继续性缓慢,买卖偶发性缓慢。

关于每一类问题都有相应的处理办法,办法或许东西运用不妥,会导致不能快速而且精准地排查定位问题。

压测功用问题定位调优是一门需求多方面归纳才能结合的一种技能作业,需求凭仗个人的技能才能、阅历、有时分还需求一些直觉和灵感,还需求一定的沟通才能,因为有时分问题并不是由定位问题的人发现的,所以需求经过不断地沟通来发现一些蛛丝马迹。触及的技能知识面远不仅限于程序语言自身,还或许需求厚实的技能根本功,比方操作体系原理、网络、编译原理、JVM 等知识,决不仅仅简略的了解,而是真正的把握,比方 TCP/IP,有必要得深化把握。JVM 得深化把握内存组成,内存模型,深化把握 GC 的一些算法等。这也是一些初中级技能人员在一遇到功用问题就傻眼,彻底不知道怎么从哪里下手。假如拥有厚实的技能根本功,再加上一些实战阅历然后构成一套归于自己的打法,在遇到问题后才能心中不乱,快速拨开迷雾,终究找到问题的症结。

本文笔者还带来了实践作业中定位和排查出来的一些典型的功用问题的事例,每个事例都会介绍问题产生的相关布景,一线人员供给的问题现象和初步排查定位结论,且在笔者介入后看到的问题现象,再配合一些常用的问题定位东西,介绍发现和定位问题的整个进程,问题产生的根本原因等。

剖析思路结构

遇到一个功用问题,首要要从各种表象和一些简略东西将问题进行界说和分类,然后再做进一步的定位剖析,能够参阅一下图 1 作者总结出来的一个决策图,这张图是笔者从近几个金融职业 ToB 项目中做功用定位调优进程的一个总结提练,不一定合适一切的问题,但至少覆盖到了近几个项目中遇到的功用问题的排查进程。在接下来的大篇幅中将对每一类问题进行打开,并附上一些真实的经典事例,这些事例都是真真实实产生的,有一定的代表性,且许多都是客户定位了很长时刻都没发现问题根本原因的问题。其中 GC 类问题在此文不做过多剖析,关于 GC 这一类问题后续有空写一篇专门的文章来进行打开。

Java 应用压测性能问题定位经验分享

内存溢出

内存溢出问题依照问题产生频率又可进一步分为堆内存溢出、栈内存溢出、Metaspace 内存溢出以及 Native 内存溢出,下面临每种溢出状况进行详细剖析。

  • 堆内存溢出

相信这类问题大家多多少少都接触过,问题产生的根本原因便是运用申请的堆内存超过了 Xmx 参数设置的值,进而导致 JVM 根本处于一个不可用的状况。如图 2 所示,示例代码模仿了堆内存溢出,运转时设置堆巨细为 1MB,运转后成果如图3所示,抛出了一个 OutOfMemoryError 的过错反常,相应的 Message 是 Java heap space,代表溢出的部分是堆内存。

  • 栈内存溢出

这类问题首要是因为办法调用深度太深,或许不正确的递归办法调用,又或许是 Xss 参数设置不妥都会引发这个问题,如图 4 所示,一个简略的无限递归调用就会引发栈内存溢出,出错成果如图5所示,将会抛一个 StackOverflowError 的过错反常。Xss 参数能够设置每个线程栈内存最大巨细,JDK8 的默许巨细为 1MB,正常状况下一般不需求去修正该参数,假如遇到 StackOverflowError 的报错,那么就需求留心了,需求查验是程序的问题仍是参数设置的问题,假如确实是办法调用深度很深,默许的 1MB 不够用,那么就需求调高 Xss 参数。

  • Native内存溢出

这种溢出产生在 JVM 运用堆外内存时,且超过一个进程所支撑的最大的内存上限,或许堆外内存超过 MaxDirectMemorySize 参数指定的值时即会引发 Native 内存溢出。如图 6 所示,需求装备 MaxDirectMemorySize 参数,假如不装备这个参数估计很难模仿出这个问题,作者的机器的 64 位的机器,堆外内存的巨细可想而知了。运转该程序得到的运转成果如图 7 所示,抛出来的反常也是 OutOfMemoryError,这个跟堆内存反常相似,可是 Message 是 Direct buffer memory,这个跟堆内存溢出的 Message 是不一样的,请特别留心这条 Message,这对精准定位问题是十分重要的。

  • Metaspace内存溢出

Metaspace 是在 JDK8 中才呈现的,之前的版本中都叫 Perm 空间,大概用处都相差不大。模仿 Metaspace 溢出的办法很简略,如图 8 所示经过 cglib 不断动态创立类并加载到 JVM,这些类信息便是保存在 Metaspace 内存里面的,在这儿为了快速模仿出问题,将 MaxMetaspaceSize 设置为 10MB。履行成果如图 9 所示,仍然是抛出 OutOfMemoryError 的过错反常,可是 Message 变成了 Metaspace。

JVM 的内存溢出最常见的就这四种,假如能知道每一种内存溢出呈现的原因,那么就能快速而精准地进行定位。下面临一些遇到的真实的经典事例进行剖析。

  • 事例:堆外内存溢出

这种问题也比较好查,条件是在堆内存产生溢出时有必要自动转储堆内存到文件中,假如压测进程中经过 kill -3 或许 jmap 指令触发堆内存转储。然后经过一些堆内存剖析东西比方 IBM 的 Heap Analyzer 等东西找出是哪种目标占用内存最多,终究能够把问题原因揪出来。

假如需求在产生 OOM 时自动转储堆内存,那么需求在发动参数中加入如下参数:

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/usr/local/oom

假如需求手工获取线程转储或许内存转储,那么请运用 kill -3 指令,或许运用 jstack 和 jmap 指令。

jstack -l pid > stackinfo,这条指令能够把线程信息转储到文本文件,把文件下载到本地然后用比方 IBM Core file analyze 东西进行剖析。

jmap -dump:format=b,file=./jmap.hprof pid,这条指令能够把堆内存信息到当时目录的 jmap.hprof 文件中,下载到本地,然后用比方 IBM Heap Analyze 等堆内存剖析东西进行剖析,依据二八规律,找准最耗内存的目标就能够处理 80% 的问题。

图 10 便是一个真实产生的事例,该问题的产生现象是这样的,压测开端后,前十分钟一切正常,可是在阅历大约十分钟后,TPS 逐步下降,直到后边客户端的 TCP 衔接都建不上去,客户一度以为是服务端Linux的网络栈的参数设置有问题,导致 TCP 无法建连,给出的依据是,服务端存在很多的 TIME_WAIT 状况的衔接,然后要求调整Linux内核网络参数,削减 TIME_WAIT 状况的衔接数。什么是 TIME_WAIT?在这个时分就不得不祭出祖传 TCP 状况机的那张图了,如图 11 所示。对照这个图就能知道 TIME_WAIT 的来胧去脉了,TIME_WAIT 首要呈现在自动封闭衔接方,当然了,假如两边刚好一起封闭衔接的时分,那么两边都会呈现 TIME_WAIT 状况。在进行封闭衔接四路握手协议时,终究的 ACK 是由自动封闭端发出的,假如这个终究的 ACK 丢掉,服务器将重发终究的 FIN,因此客户端有必要维护状况信息以答应它重发终究的 ACK。假如不保持这个状况信息,那么客户端将呼应 RST 分节,服务器将此分节解说成一个过错(在 java 中会抛出 connection reset的SocketException)。因此,要完成 TCP 全双工衔接的正常停止,有必要处理停止序列四个分节中任何一个分节的丢掉状况,自动封闭的客户端有必要保持状况信息进入 TIME_WAIT 状况。

Java 应用压测性能问题定位经验分享

图 10 真实堆内存溢出事例一

Java 应用压测性能问题定位经验分享

图 11 TCP 状况机

顺着客户供给的这些信息,查了一下压测客户端,选用的是 HTTP 协议,keep-alive 为开,而且选用的是衔接池的办法与服务端进行交互,理论上在服务器端不应该呈现如此之多的 TIME_WAIT 衔接,猜想一种或许性是因为客户侧刚开端压测的时分 TPS 比较高,占用衔接数多,后续功用下来后,衔接数空闲且来不及跟服务端进行保活处理,导致衔接被服务端给自动封闭掉了,但这也仅限于是猜想了。

为了更精准地定位问题,决议去一线现场看下状况,在 TPS 严峻往下掉的时分,经过 top、vmstat 等指令进行初步勘探,发现 cpu 占比并不十分高,大约 70% 左右。可是 JVM 占用的内存现已快挨近 Xmx 参数装备的值了,然后用 jstat -gcutil -h10 pid 5s 100 指令看一下 GC 状况,不查不知道一查吓一跳,如图 12 所示,初看这便是一份不太正常的 GC 数据,首要老时代占比直逼 100%,然后 5 秒内竟然进行了 7 次 FullGC,eden 区占比 100%,因为老时代现已满了,年青代的 GC 都现已停滞了,这明显不正常,趁 JVM 还活着,赶忙履行 jmap -dump:format=b,file=./jmap.hprof pid,把整个堆文件快照拿下来,整整 5 个 G。取下来后经过 IBM 的 HeapAnalyzer 东西剖析堆文件,成果如图 10 所示,经过一番查找,发现某个目标占比特别大,占比达 98%,继续追寻持有目标,终究定位出问题,申请了某个资源,可是一向没有开释,修正后问题得到完美处理,后续再经过长达 8 个小时的耐久性测,没能再发现问题,TPS 一向十分安稳。

Java 应用压测性能问题定位经验分享

图 12 GC 状况统计剖析

再来看看为何会呈现那么多的 TIME_WAIT 衔接,跟开端的猜想是共同的,因为很多的搁置衔接被服务端自动封闭掉,所以才会呈现那么多的 TIME_WAIT 状况的衔接。

CPU高

  • 事例

某金融银行客户在压测进程中发现一个问题,导致 TPS 极低,买卖呼应时长甚至挨近惊人的 30S,严峻不达票,服务呼应时刻如图 23 所示,这是运用打的 tracer log,显示的耗时很不达观。运用选用 SOFA 构建,布置在专有云容器上面,容器规格为 4C8G,运用 OceanBase 数据库。买卖缓慢进程中客户在相应容器里面用 top、vmstat 指令获取 OS 信息,发现内存运用正常,可是 CPU 挨近 100%,经过 jstack 指令取线程转储文件,如图 22 所示,客户发现很多的线程都卡在了获取数据库衔接上面,再上运用日志中也报了很多的获取 DB 衔接失败的过错日志,这让客户以为是衔接池中的衔接数不够,所以不断继续加大 MaxActive 这个参数,DB 衔接池运用的是 Druid,在加大参数后,功用没有任何改善,且获取不到衔接的问题仍旧。客户在排查该问题大概两周且没有任何实质性发展后,开端向阿里 GTS 的同学求助。

笔者刚好在客户现场,介入该功用问题的定位作业。跟客户一番沟通,并查阅了了前史定位信息记录后,依据以往的阅历,这个问题肯定不是因为衔接池中的最大衔接数不够的原因导致的,因为这个时分客户现已把 MaxActive 的参数现已调到了恐惧的 500,但问题仍旧,在图 22 中还能看到一些有用的信息,比方正在 Waiting 的线程高达 908 个,Runnable 的线程高达 295 个,都是很恐惧的数字,很多的线程处于 Runnable 状况,CPU 忙着进行线程上下文的切换,CPU 呼呼地转,但实践并没有干多少有实践有意义的事。后经询问,客户将 SOFA 的事务处理线程数调到了 1000,默许是 200。

Java 应用压测性能问题定位经验分享

图 22 线程卡在获取 DB 衔接池中的衔接

Java 应用压测性能问题定位经验分享

图 23 买卖缓慢截图

查到这儿根本能够判定客户陷入了“头痛医头,脚痛医脚”,“治标不治本”的窘境,进一步跟客户沟通后,不出所料。刚开端的时分,是因为 SOFA 报了线程池满的过错,然后客户不断加码 SOFA 事务线程池中最大线程数,终究加到了 1000,功用提高不明显,然后报了一个获取不到数据库衔接的过错,客户又以为这是数据库衔接不够了,调高 Druid 的 MaxActive 参数,终究不管怎样调功用也都上不来,甚至到后边把内存都快要压爆了,如图 24 所示,内存中被一些事务 DO 目标给填满了,后边客户一度以为存在内存走漏。关于这类问题,只需像是呈现了数据库衔接池不够用、或许从衔接池中获取衔接超时,又或许是线程池耗尽这类问题,只需参数设置是在合理的范围,那么十有八九便是买卖自身处理太慢了。后边经过进一步的排查终究定位是某个 SQL 语句和内部的一些处理不妥导致的买卖缓慢。修正后,TPS 正常,终究把线程池最大巨细参数、DB 衔接池的参数都往回调成最佳实践中引荐的值,再次压测后,TPS 仍然保持正常水平,问题得到终究处理。

Java 应用压测性能问题定位经验分享

图 24 内存填满了事务范畴目标

这个事例一虽然是因为 CPU 冲高且买卖继续缓慢的这一类典型问题,但其实就这个事例所述的那样,在定位和调优的时分很简单陷进一种治标不治本的困境,很简单被一些表象所利诱。怎么拨开云雾见月明,笔者的看法是 5 分看阅历,1 分看灵感和命运,还有 4 分得靠不断剖析。假如没阅历怎样办?那就只能沉下心来剖析相关功用文件,不管是线程转储文件仍是 JFR,又或许其他采集东西采集到功用信息,横竖不要放过任何蛛丝马迹,终究真实没辙了再恳求阅历丰富的专家的协助排查处理。

  • 运用 JMC+JFR 定位问题

假如超长问题偶尔产生,这儿介绍一个比较简略且十分有用的办法,运用 JMC+JFR,能够参阅链接进行运用。可是运用前有必要敞开 JMX 和 JFR 特性,需求在发动修正发动参数,详细参数如下,该参数不要带入生产,别的假如将容器所属宿主机的端口也暴露成跟 jmxremote.port 一样的端口,如下示例为 32433,那么还能够运用 JConsole 或许 JVisualvm 东西实时观察虚拟机的状况,这儿不再做详细介绍。

-Dcom.sun.management.jmxremote.port=32433

-Dcom.sun.management.jmxremote.ssl=false

-Dcom.sun.management.jmxremote.

authenticate=false

-XX:+UnlockCommercialFeatures -XX:+FlightRecorder

下面以一个实践的 JFR 实例为例。

首要要敞开 JMX 和 JFR 功用,需求在发动参数中加 JMX 敞开参数和 JFR 敞开参数,如上面所述,然后在容器里面履行下述指令,履行后显示“Started recording pid. The result will be written to xxxx”,即表明现已开端录制,这个时分开端进行压测,下述指令中的 duration 是 90 秒,也就表明会录制 90S 后才会停止录制,录制完后将文件下载到本地,用 jmc 东西进行剖析,假如没有这个东西,也能够运用 IDEA 进行剖析。

jcmd pid JFR.start name=test duration=90s filename=output.jfr

Java 应用压测性能问题定位经验分享

经过剖析火焰图,详细怎样看火焰图请参阅链接。经过这个图能够看到首要的耗时是在哪个办法上面,给咱们剖析问题供给了很大的便当。

还能够检查 call tree,也能看出耗时首要产生在哪里。

Java 应用压测性能问题定位经验分享

JMC 东西下载地址:JDK Mission Control (JMC) 8 Downloads (oracle.com)

终究再介绍一款东西,阿里巴巴开源的 arthas,也是功用剖析和定位的一把利器,详细运用就不在这儿介绍了,能够参阅 arthas 官网。

  • 怎么定位 CPU 耗时过高的线程及办法

首要找到 JAVA 进程的 PID,然后履行 top -H -p pid,这样能够找到最耗时的线程,如下图所示。然后运用 printf “%x\n” 17880,将线程号转成 16 进制,终究经过这个 16 进制值去 jstack 线程转储文件中去查找是哪个线程占用 CPU 最高。

Java 应用压测性能问题定位经验分享

其他问题事例

这类问题在产生的时分,JVM 表现得静如止水,CPU 和内存的运用都在正常水位,可是买卖便是缓慢,关于这一类问题能够参阅 CPU 冲高类问题来进行处理,经过运用线程转储文件或许运用JFR来录制一段 JVM 运转记录。这类问题大概率的原因是因为大部分线程卡在某个 IO 或许被某个锁个 Block 住了,下面也带来一个真实的事例。

  • 事例一

某金融保险头部客户,反响某个买卖十分缓慢,经常呼应时刻在 10S 以上,运用布置在公有云的容器上,容器规格为 2C4G,数据库是 OceanBase。问题每次都能重现,经过分布式链路东西只能定位到在某个服务上面慢,并不能精确认是卡在哪个办法上面。在买卖缓慢期间,经过 top、vmstat 指令检查 OS 的状况,CPU 和内存资源都在正常水位。因此,需求看在买卖期间的线程的状况。在买卖履行缓慢期间,将买卖的线程给转储出来,如图 29 所示,能够定位相应的线程卡在哪个办法上面,事例中的线程卡在了履行 socket 读数据阶段,从堆栈能够判定是卡在了读数据库上面了。假如这个办法仍然不好用,那么还能够凭仗抓包办法来进行定位。

Java 应用压测性能问题定位经验分享

图 29 买卖被 hang 住示例图

  • 事例二

某金融银行客户压测进程中发现 TPS 上不去,10TPS 不到,呼应时刻更是高到令人发指,在经过一段时刻的训练赋能和磨合,该客户现已具备些功用定位的才能。给反馈的信息是 SQL 履行时刻、CPU 和内存运用一切正常,客户打了一份线程转储文件,发现大多数线程都卡在了运用 RedissionLock 的分布式锁上面,如图 30 所示,后经查是客户没有合理运用分布式锁导致的问题,处理后,TPS 翻了 20 倍。

Java 应用压测性能问题定位经验分享

图 30 分布式锁运用不妥导致的问题示例

这两个事例其实都不算杂乱,也很简单进行排查,放到这儿仅仅想重述一下排查这类问题的一个整体的思路和办法。假如买卖缓慢且资源运用都正常,能够经过剖析线程转储文件或许 JFR 文件来定位问题,这类问题一般是因为 IO 存在瓶颈,又或许被锁 Block 住的原因导致的。

总结

问题千千万,但只需修练了满足深沉的内功,构成一套归于自己的排查问题思路和打法,再加上一套支撑问题排查的东西,凭仗已有的阅历还有偶发到来的那一丝丝灵感,相信一切的问题都会迎刃而解。

更多沟通,欢迎进钉钉群沟通,PTS 用户沟通钉钉群号:11774967。

此外,PTS 近期对售卖办法做了全新升级,基础版价格直降 50%!5W 并发价格只需 199,免除自运维压测渠道烦恼!更有新用户 0.99 体会版、VPC 压测专属版,欢迎大家选购!

Java 应用压测性能问题定位经验分享

点击此处,前往官网检查更多!