〇、经验总结:
创新互联公司2013年成立,是专业互联网技术服务公司,拥有项目网站设计制作、成都网站制作网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元天祝藏族自治做网站,已为上家服务,为天祝藏族自治各地企业和个人服务,联系电话:028-86922220一、背景说明
这周我们对项目里新增的几个接口进行了压力测试,期间遇到了一些之前没有遇到过的坑,走了一些弯路,在这里对这次压力测试经历进行总结复盘,同时也希望能给看到这篇文章的诸位提供一些浅显的思路。
首先介绍一下我们项目的结构。服务入口是一个网关模块,提供一个Grpc类型的接口,数据传输模式是一元数据模式。网关模块与其他业务模块之间通过Dubbo接口进行交互。
服务的架构概况图如下:
该业务接口部署的服务器配置和部署MySQL组件的服务器配置一致,都是4核8G,50G普通硬盘,并且处于同一个内网网段,我们预估的性能指标要达到300并发,600TPS。
在压力测试过程中,我们重点关注TPS、GC次数、CPU占用率和接口响应时间等指标。
二、测试过程
完成项目部署后,我们开始编辑jemeter测试脚本,设置压力测试的标准为300个并发线程,在10秒内全部启动,持续压测时间15分钟,接着开始启动jemeter脚本进行测试。
1、第一次压力测试
垃圾收集策略包括:老年代启用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)问题排查与解决
上述压测过程中出现的现象,可以细分为两类:
由于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
结果是:
2、第二次压力测试
经过第一次压力测试调整后,我们开始对调整效果进行测试验证。
(1)JVM配置
JVM配置没有改变
(2)性能指标监控
查看被压机器的GC情况和CPU使用情况,依然没有太大变化,但请求数量稍微有所提升,说明端口扩展有一定的效果,但是不明显。
继续查看施压机器的信息,接口调用的结果断言依然存在错误,虽然错误率有所降低(跟被压机器接收请求的数量上升有关系),错误信息还是连接异常。
从这个结果来看,解决问题的方向是对的,于是继续把施压机器的端口扩展放开,开始第三轮测试验证。
3、第三次压力测试
(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
配置好之后,重启被压测模块,查看进程的堆内存分配情况: