〇、经验总结:java
1、背景说明
这周咱们对项目里新增的几个接口进行了压力测试,期间遇到了一些以前没有遇到过的坑,走了一些弯路,在这里对此次压力测试经历进行总结复盘,同时也但愿能给看到这篇文章的诸位提供一些浅显的思路。
首先介绍一下咱们项目的结构。服务入口是一个网关模块,提供一个Grpc类型的接口,数据传输模式是一元数据模式。网关模块与其余业务模块之间经过Dubbo接口进行交互。
服务的架构概况图以下:算法
该业务接口部署的服务器配置和部署MySQL组件的服务器配置一致,都是4核8G,50G普通硬盘,而且处于同一个内网网段,咱们预估的性能指标要达到300并发,600TPS。
在压力测试过程当中,咱们重点关注TPS、GC次数、CPU占用率和接口响应时间等指标。服务器
2、测试过程
完成项目部署后,咱们开始编辑jemeter测试脚本,设置压力测试的标准为300个并发线程,在10秒内所有启动,持续压测时间15分钟,接着开始启动jemeter脚本进行测试。
一、第一次压力测试
垃圾收集策略包括:老年代启用CMS垃圾收集算法,新生代启用ParNew垃圾收集算法,新生代最大存活周期为15次minorGC,FullGC时使用CMS算法,并开启CMS中的并行标记。
根据前几回的压力测试经验,咱们将初始堆内存设置为2048MB,由于偏小的堆内存设置容易在压力测试时被撑爆。
JVM内存分配:最大/最小堆内存为2048MB,Eden和Survivor比例为8:2,新生代和老年代的比例为1:2。因为服务器安装的是JDK8版本,废弃了永久代的配置。
JVM配置参数以下:架构
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/$MODULE/gc.log -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=15 -XX:+ExplicitGCInvokesConcurrent -XX:+CMSParallelRemarkEnabled -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/$MODULE -Xmx2048m -Xms2048m -XX:SurvivorRatio=8
(2)性能指标监控
top命令观察java线程的CPU占用率(us表示用户进程,sy表示系统进程),并使用jstac -gcutil Pid 1000 命令,按期查看虚拟机的GC状况。
一切准备就绪后,咱们开始跑压测脚本,并查看性能监控指标。
可是咱们没有看到预期来临的压力,而是并发到达必定值时,好像忽然并发压力中断了,而后间隔1-2秒后压力又从新出现,这期间接口服务器各项指标均没有异常。很显然,并发存在问题!并发
(3)问题排查与解决
上述压测过程当中出现的现象,能够细分为两类:ide
因为Grpc接口须要在客户端与服务端创建RPC链接,那么两端都须要同时指定各自的一个端口进行数据通讯。基于这一点,咱们判断出现第一种现象的缘由可能有两个:性能
cat /proc/sys/net/ipv4/ip_local_port_range
结果是:测试
即仅放开了 32768——60999 之间的端口,数量大体也是3W左右。
而后咱们从新设置了被压机器的端口扩展列表,命令:线程
echo "10000 65535" > /proc/sys/net/ipv4/ip_local_port_range
结果是:3d
二、第二次压力测试
通过第一次压力测试调整后,咱们开始对调整效果进行测试验证。
(1)JVM配置
JVM配置没有改变
(2)性能指标监控
查看被压机器的GC状况和CPU使用状况,依然没有太大变化,但请求数量稍微有所提高,说明端口扩展有必定的效果,可是不明显。
继续查看施压机器的信息,接口调用的结果断言依然存在错误,虽然错误率有所下降(跟被压机器接收请求的数量上升有关系),错误信息仍是链接异常。
从这个结果来看,解决问题的方向是对的,因而继续把施压机器的端口扩展放开,开始第三轮测试验证。
三、第三次压力测试
(1)JVM配置
JVM配置没有改变
(2)性能指标监控
施压机器和被压机器的端口列表都放开后,grpc链接请求都正常了。在100并发和300并发两种状况下,持续2分钟发起的请求数相差不大,说明已经接近了两端服务器的处理极限了。
(3)新问题暴露
原本觉得这样就OK了,然而此时忽然发现被压机器的GC开始出现异常,即YGC次数开始不变更,可是FGC频繁。
压测一段时间后,FGC开始出现,频率为平均每秒2-3次。
一般出现FGC的缘由,无非就是老年代被占满了,因而查看线程的老年代堆内存状况:
jstat -gcold PID
个人天!老年代才64KB!这是把新生代内存塞满后,开始往可怜巴巴的老年代塞了,因而频繁触发FGC。
因而查看JVM参数配置,发现少了老年代的内存配置了。
老年代的堆内存配置能够经过 -XX:NewRatio=3 来设置,表示老生代:新生代的比值。即若是2GB堆内存的话,那么老年代是1.5GB,新生代是0.5GB。
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/$MODULE/gc.log -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=15 -XX:+ExplicitGCInvokesConcurrent -XX:+CMSParallelRemarkEnabled -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/$MODULE -Xmx2048m -Xms2048m -XX:SurvivorRatio=8 -XX:NewRatio=3
配置好以后,重启被压测模块,查看进程的堆内存分配状况: