使用Jmeter对接口进行压力测试
今天第一次使用Jmeter对系统进行了压力测试,测试了一下纯数据库方案以及添加了缓存的方案,结果惊人。
新建测试步骤
在测试计划中添加一个线程组

在新增的线程组中添加HTTP请求与查看结果树


在HTTP请求中添加聚合报告

容易踩坑的点:如果你的接口是POST请求,一定要多添加一个HTTP头管理器

在其中新增条目:Content-Type:Application/json
也就是以请求体以 json 的格式发送

如果接口需要登录,可以增加一个 cookie 管理器
完成这些之后,就可以将线程数设置为1,进行连接测试,连接正常后正式进入压力测试。
只使用MySQL处理请求
在设置并发量为每秒1000次的时候,可以看到MySQL的处理速度已经很慢了,平均响应时间达到了5235ms


使用Caffeine+Redis多级缓存方案
每秒1000次并发,对于缓存来说这么小的并发量只需略微出手,热身级别。平均响应时间2ms,相差2000+倍


继续增加并发数
2000并发测试:

3000并发测试:

4000并发测试:

5000并发测试:

6000并发测试:

可以看到,在6000并发时,虽然响应速度很快,但是异常值出现了波动,查看失败的请求,发现报错如下:
▼java复制代码java.net.ConnectException: Connection refused: connect at java.base/sun.nio.ch.Net.connect0(Native Method) at java.base/sun.nio.ch.Net.connect(Net.java:589) at java.base/sun.nio.ch.Net.connect(Net.java:578) at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:583) at java.base/java.net.Socket.connect(Socket.java:760) at java.base/java.net.Socket.connect(Socket.java:695) at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:183) at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:531) at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:636) at java.base/sun.net.www.http.HttpClient.<init>(HttpClient.java:280) at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:386) at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:408) at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1310) at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1243) at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1129) at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1058) at org.apache.jmeter.protocol.http.sampler.HTTPJavaImpl.sample(HTTPJavaImpl.java:536) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:66) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1311) at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1300) at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:651) at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:570) at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:501) at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:268) at java.base/java.lang.Thread.run(Thread.java:1575)
这是由于服务端无法接受新连接导致的
▼java复制代码tomcat: # 接受和处理连接的最大线程数 threads: max: 2000 min-spare: 100 # 最大连接数,超出后进入等待队列 max-connections: 10000 # 等待队列长度,当所有线程忙碌、连接数达max-connections时,新请求在此队列等待 accept-count: 5000 # 连接超时时间(毫秒) connection-timeout: 5000

通过调整Tomcat服务器的配置,降低了异常值
但并发数是由客户端与服务器端共同制约的,使用 HTTPJavaImpl 的方式发送HTTP请求时,无法通过勾选 Use KeepAlive 来复用连接(Java 内置实现默认行为有限),这会导致每次请求都建立新的 TCP 连接,在高并发时客户端端口耗尽或服务端连接队列打满。
同时服务端操作系统:Linux 内核参数也需要调优,由于我是在本地windows测试,就跳过了这一步骤
每秒10000次并发
MySQL近乎宕机,平均响应时间达到24秒是一个灾难性的故障信号,意味着服务已基本不可用,并随时可能引发系统性崩溃。

引入了多级缓存的情况下,响应时间依旧很快,完全没有达到上限,但是异常值达到了44%

所以多级缓存只是构建高并发系统的一个必要条件,想要构建一个稳定的支持高并发的系统,还需要具备多种能力:分布式架构、限流降级熔断、容器与线程模型调优、JVM与GC调优、监控与快速定位等综合能力。
