压力测试

压力测试不同于功能测试,其目的是为了测试出系统在高并发,高数据量的情况下可能会出现的问题(内存泄露、并发、同步)

一种典型的内存泄漏就是对象在创建之后由很多用户进行调用,导致对象被不断新建但复用率很低,导致内存不足(内存泄露的典型问题)

有效的压力测试应用的关键条件:重复、并发、量级、随机变化

性能指标

  • 响应时间:客户端从发起一个请求开始,到接收到服务器的响应为止,整个过程所耗费的时间

  • TPS:系统每秒能够处理的事务数(Java中的事务,暨一系列不可中断的操作)

  • QPS:系统每秒处理的查询次数(次/秒)(一般指接口的查询次数)

    TPS、QPS、HPS都是衡量系统处理能力的非常重要的指标,越大越好,

    • 金融行业:1000 – 50000 TPS
    • 保险行业:100 – 100000 TPS 可能涉及到极其复杂的业务场景,这种情况下允许TPS降低
    • 制造行业:10 – 5000 TPS 使用并发量低,对高并发场景没有很高的要求
    • 互联网电子商务:10000 – 1000000 TPS
    • 互联网中型网站:1000 – 50000 TPS
    • 互联网小型网站:500 – 10000 TPS
  • 最大响应时间:用户发出请求到收到响应的最长时间

  • 最少响应时间:用户发出请求到收到响应的最短时间

  • 90%响应时间:所有用户的响应时间进行排序,第90%的响应时间

  • 此外,我们要看重的指标主要有:吞吐量(每秒钟系统可以处理的请求数、任务数)、响应时间:(服务处理一个请求或一个任务的耗时)、错误率:(一批请求中结果出错的请求所占的比例)

JMeter

压力测试工具有很多选择,这里我们选择JMeter进行压力测试,一般选择添加线程组、线程组下的HTTP请求、查看结果树、汇总报告、聚合报告、汇总图等信息用来检查结果,结果可以查看吞吐量、90%百分位、中位数等信息来判断系统性能

Windows下JMeter Address In Use错误的解决

由于我们使用JMeter时,每一次测试请求都需要占用一个windows端口,windows允许的对外端口是1024 – 5000 ,而Windows所需要的回收时间是4分钟,故我们在短时间进行测试时,会发生端口不够用的问题

在regedit注册表信息中添加:

计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

下新建DWORD值:MaxUserPort:65534、TCPTimedWaitDelay:30

使其端口最大允许65534、TCP回收时间为30S

性能优化思路

首先,我们要知道影响性能的因素,主要包括:数据库、应用程序、中间件、网络、操作系统等因素,再具体在其中进行对应的优化

其次,我们要知道我们的应用程序属于CPU密集型 还是 IO密集型,系统常见的是计算、排序、数据处理等操作一般是CPU密集型应用程序、常见的是进行数据读取,发送,存储的一般属于IO密集型应用程序,同时,我们也可以通过其实际上的运行情况进行判断我们目前更需要哪方面的优化(看CPU占用和IO占用情况)

JVM简述:

我们在存放一个新的对象时,会优先检查其是否能被存储在新生代的Eden区,若放不下,则会进行YoungGC,对新生代进行检测并清除,再检查是否能放下,若还放不下,则直接向老年区存储,若还是放不下,则进行Full GC,若还是放不下则会抛出OOM异常

同时,我们会尽量将Eden区的数据放到幸存者区,以保证我们在新增对象的时候可以直接存放,不进行GC,另外Full GC的速度是Y GC速度的10倍左右,高频的FullGC会导致系统性能极差

使用jvisualvm监控性能指标

我们常用的监控系统JVM性能指标的工具有jconsole、以及他的升级版jvisualvm,这里我们使用升级版的工具jvisualvm进行性能监控:

注意,高版本JDK已经不再自动集成jvisualvm,需要我们自己安装

jvisualvm的作用:监控内存泄漏、跟踪垃圾回收、执行时内存、CPU分析、线程分析…

运行:正在运行的线程

休眠:sleep中的线程

等待:wait的线程

驻留:线程池中的空闲线程

监视:阻塞的线程(正在等待锁的线程)

安装Visual GC

tools -> Plugins 在settings中打开网址(io结尾)在download中选择左边的Visual GC下载,不要被网上的教程从右边下载欺骗,下载安装之后我们就可以查看对应的Java线程的GC信息

实际使用压力测试进行简单优化

在Linux中,我们可以使用docker status来对Linux中的线程进行监控,从而做出进一步的判断,创建单测,进行一定的测试:

压测内容压测线程数吞吐量/s90%响应时间99%响应时间
Nginx509755822
Gateway503472725
简单接口502426636
Gateway + 简单接口5055001745
Nginx + Gateway + 简单接口5021003053
首页接口(单独)50230341543
三级分类接口(嵌套循环查询)501(2,加索引后)(8,业务优化后)3430038400
首页全量数据(包括静态资源渲染)(无Thymeleaf缓存)50689471529
首页全量数据(包括静态资源渲染)(有Thymeleaf缓存)50728191007
首页全量数据(包括静态资源渲染)(有Thymeleaf缓存、数据库加索引、关日志)501007311232
首页全量数据(不包括静态资源渲染)(有Thymeleaf缓存、数据库加索引、关日志)50310286423
首页全量数据(包括静态资源渲染)(动静分离)502032284778
首页全量数据(包括静态资源渲染)(动静分离 + 增加内存,增加新生代使用内存(-Xmx1024m -Xms1024m -Xmn512m)(最大内存,初始内存,新生代内存))5025

我们可以直观的看出来:单独Gateway和单独简单接口都有较高的吞吐量,而两者结合就会使性能大幅下降,故:中间件越多,系统性能损耗越大(主要损失在网络IO上)

注意,此处的压力测试是通过本机测本机的结果,这种结果不太具有参考价值,因为压测的线程会和实际运行的线程发生竞争,使得结果偏差

在单独的首页中:主要的性能影响因素是DB操作以及Thymeleaf渲染

在三级分类接口中:主要的性能影响因素就是死亡一般的嵌套查询操作以及DB操作