压测经历2 ——模拟真实情况

经历1里面只是对单台测试,后面我们想看看整个集群的qps。然后发现了很多问题。。。。

一.改为随机数测试

用户画像的数据大概有3亿,我想模拟真实访问情况,于是通过random函数随机取用户id,进行查询。测试数据如下:

并发数 响应时间 理论qps 实际qps
10 1.7ms 5.8k/s 3.2k/s
50 3.5ms 14.3k/s 8.6k/s
100 6.7ms 14.9k/s 9.6k/s

通过上面的数据可以发分析得出两个结果:

  • 理论qps和实际qps不匹配,且偏小,说明测试机器的响应时间比监控的时间要大,这里面主要有两个因素影响,网络传输和测试机器的处理能力。
  • 并发数增加,响应时间成倍增加,说明服务端也存在性能瓶颈。

发现问题,就开始解决问题,首先解决问题2。

二.性能瓶颈

发现性能问题后,首先想到的是CPU、内存、I/O和网络是否存在瓶颈。还好公司基本上所有的服务都接入了grafana(感谢运维大大们),打开网页看了一下除了在100个并发的时候cpu达到了50%,其他的资源利用率都很低。下图是我测试了一天的的效果图。

这时候只能从程序本身去找问题了,也是两个方向:

  • jvm是否正常,
  • review代码,看是否有特别耗时的地方。

(1)GC情况

之前的jvm的参数都是从别的地方拷贝过来,可以通过参数

-XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M -Xloggc:/data/bdi.profile/logs/gc_20171027_140757.log

打印gc运行日志,统计如下报表:

并发数 ygc 耗时 间隔
10 20ms 400ms
20 20ms 200ms
100 20ms 135ms

eden区的gc时间一直很稳定,但是间隔时间变短了。说明并发数上来,gc变的更频繁了。eden的分配的空间为64M,分配的比较小,因为我们的请求生成的对象大部分都是eden区就被gc了。不过空间太小,导致频繁gc,会增大请求响应时间,自然需要扩大新生代的大小了。而且从我们的日志观测来看,隔一段时间,响应时间会变的很大,主要原因是CMS在gc过程中会产生碎片,等达到一定阈值,会集中回收。

所以后续直接使用G1的方式回收,初始堆大小分配了8g。分配如下:

-Xms8g -Xmx8g -XX:+UseG1GC -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:G1RSetUpdatingPauseTimePercent=5 -XX:InitiatingHeapOccupancyPercent=70 -XX:ParallelGCThreads=5 -XX:ConcGCThreads=5 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M -Xloggc:/data/bdi.profile/logs/gc_20171027_140757.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/bdi.profile/tmp/heapdump_20171027_140757.hprof -Djava.io.tmpdir=/data/bdi.profile/tmp/ -Duser.dir=/data/bdi.profile -DTEAM=bdi -DAPPID=bdi.profile -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=18089 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -classpath /data/bdi.profile/conf:/data/bdi.profile/lib/*: me.ele.core.container.Container

本以为改完后,性能会有质的飞升,然而qps并没有上来很多多,jvm最多有20%的影响,当然是在我们并发数低的情况下。

(2)review代码

其实查询逻辑很简单,用户的请求来了,先校验权限,然后首先去缓存中查询,如果没命中就到ekv中查询。把所有可能出现耗时的地方都用日志打印了一遍。这个过程也是蛮痛苦的,因为数据量比较大,只能发布到线上才能测试。然后就这样一遍遍的查询,最后也并没有找到什么问题。。。。。最后都快放弃了,然后有一个同事跟我说你把log关了试试,其实我之前也考虑到日志会影响性能,虽然我的日志级别是info,但是之前代码中一行数据都没有写到file中。后来报的试试的态度,把日志级别的态度调到了erro,然后。。。qps就怎么上来了,大概达到4w的时候,cpu使用率快达到80%

至此总算压倒机器的性能瓶颈了。关于log的工具,是公司基于log4j封装的一个jar包,默认会记录很多其他信息,及时你不往文件里面,但是只要是info级别,它也会写很多信息。

results matching ""

    No results matching ""