压力测试及其优化

# 压力测试及其优化 <font color="red">_**数据有点差的原因是, 带宽不足**_</font> ## 前提 > 首先明确, 业务整体的调用逻辑是, 发送请求给NGINX网关服务器, NGINX反向代理到到gateway微服务, 由微服务负载均衡与路由到指定的微服务, 微服务执行并逐层返回! ## 测试 ### 测试参数 - 默认方案: ![image.png](https://cos.easydoc.net/13568421/files/lkq7dyxs.png) - 方案1 ![image.png](https://cos.easydoc.net/13568421/files/lkqc0iih.png) ### JVM参数 - 默认方案 ```java -Xms100m -Xmx100m ``` - 标准方案 ```java -Xms1024m -Xmx1024m ``` <font color="green">**注意: 不同的方案测出来的性能指标不同, 因此需要控制变量**</font> |场景|JVM参数|压测参数|吞吐量/s|平均响应时间|90%响应时间|99%响应时间|类型|现象|影响因素|优化方案|总体指标| |--|--|--|--|--|--|--|--|--|--|--|--| |NGINX中间件|null|默认方案|4490|11ms|13ms|126ms|CPU密集型|CPU使用率100%以上|CPU|使用高性能CPU|good| |gateway微服务|默认方案|默认方案|3824|13ms|23ms|38ms|CPU密集型|Eden区垃圾收集时间达到2s<br/>_吞吐量较差的原因_|内存, CPU|提供更多的堆内存和更好的CPU|good| |简单请求|默认方案|默认方案|9606|0ms|1ms|1ms|IO密集型|/|/|/|good| |gateway微服务+简单请求|默认方案|默认方案|3068|20ms|37ms|86ms|/|吞吐量和响应时间性能都变差(附录1)|微服务调用过程|更好的带宽|soso| |NGINX+gateway微服务+简单请求|默认方案|默认方案|36|1.3s|1s|3.1s|/|性能大幅度损失|微服务调用过程|更好的带宽|bad bad |商城首页<br/>_(no cache have log)_|默认方案|默认方案|821|96ms|181ms|368ms|IO密集型|Eden区垃圾收集时间达到3s<br/>_吞吐量较差的原因_|db, thymeleaf, 内存| 数据库调优, 缓存, 更大内存|soso| |三级分类<br/>_(have log)_|默认方案|默认方案|207|457ms|564ms|1s|IO密集型|Eden区垃圾收集时间12s, FUllGC时间8s, 导致吞吐量极低|db, 内存(主要)|更大的内存, 数据库调优| bad bad| |分割行|/|/|/|/|/|/|/|/|/|/|/| |全量页面<br/>_(have log no cache no index)_|默认方案|方案1|23|348ms|497ms|579ms|IO密集型|整体GC的时间很长 吞吐量很差(详情附录2)|db, 静态资源(主要), 内存, thymeleaf|数据库调优, 动静分离, 更大的内存, 缓存|bad bad| |全量页面<br/>_(have log and cache no index)_|默认方案|方案1|25.8|321ms|486ms|563ms|IO密集型|指标好了一点点, 不明显|thymeleaf缓存不是性能损失的主导因素|/|soso| |全量页面<br/>_(no log have cache index)_|默认方案|方案1|25.1|312ms|424ms|468ms|IO密集型|指标好了一点, 不明显|至此, 索引和日志不是导致性能损失的主要原因|/|soso| |全量页面<br/>_(no log have cache index 动静分离)_|默认方案|方案1|38.1|177ms|256ms|292ms|IO密集型|指标好了很多|静态资源是性能损失的主要原因|/|better| |全量页面<br/>_(no log have cache index 动静分离)_|标准方案|方案1|40.2|163ms|234ms|293ms|IO密集型|指标好了一点, 因为这里测试的并发量不够大, 所以看起来只优化了一点|内存是性能损失的主要原因|/|better| |分割行|/|/|/|/|/|/|/|/|/|/|/| |三级分类<br/>_(have log)_|默认方案|默认方案|207|457ms|564ms|1s|IO密集型|Eden区垃圾收集时间12s, FUllGC时间8s, 导致吞吐量极低|db, 内存(主要)|更大的内存, 数据库调优| bad bad| |三级分类<br/>_(no log have cache)_|标准方案|默认方案|1322|66ms|81ms|84ms|IO密集型|指标非常好|内存和缓存可以大大提高性能|/|greater| # 附录 ## 附录1: 为什么微服务调用后, 响应时间和吞吐量两个指标都会变差? [答案](https://www.processon.com/embed/64c71b4772e1a448095cfb97) ### 结论 > **中间件越多, 性能越差** ## 附录2: 为什么静态资源的获取这么慢?会引发什么问题? > 静态资源获取这么慢的原因本质上是因为, 当我们访问首页的时候, 首先需要经过视图渲染, 将整个页面响应到浏览器, 然而, 这个页面又有很多静态资源, 这些静态资源都需要访问本微服务, 导致真正相应完全一个页面, 一级加二级请求可能由几十个请求组成, 微服务的线程被大量挤占 > 换而言之, 访问一个页面需要几十个线程, 且线程是有限的, 这导致了吞吐量降低, 吞吐量降低说明处理效率降低, 响应时间随之增多 > <font color="blue">**假设有100个线程, 一个请求真正需要消耗50个线程, 那么吞吐量就是2/s, 因此, 我们需要动静分离, 把剩下的49个静态资源的请求所占用的线程所释放出来**</font> ## 附录3: 为什么刚开始的时候吞吐量会比后续压测的吞吐量低? > 这了需要JVM知识中的类加载器, 类加载器中有执行器, 包括解释器和即时编译器, **刚开始的时候, 字节码指令并没有被编译器编译, 因此, JVM为了及时响应结果, 靠解释器解释执行, 解释器解释执行效率低, 因此, 吞吐量低, 后续, 即时编译器将编译的结果缓存起来, 后续都不需要解释器执行, 直接获取结果即可, 因此, 后续执行效率高, 吞吐量高** ## 附录4: Mybatis-plus缓存问题 > `Mybatis-plus`的一级缓存只有启动了事务的时候才开启, 这里没有使用事务, 不需要考虑一级缓存 > 而且二级缓存默认是不开启的, 因此, 不需要考虑这里的缓存问题 ## 附录5: 为什么GC时间长了, 吞吐量下降 > 由康师傅的JVM知识可知, GC时间越长, GC运行占总运行的占比变多, 用户线程执行的时间变少, 每秒的处理率变低, 吞吐量自然下降 ## 附录6: 为什么频繁查找数据库, 吞吐量下降 > 当我们查找数据库的时候, 需要创建连接, 因此需要一个专门的线程去接收数据, 这会导致浪费大量的线程, 导致吞吐量降低