问答 压力测试遇上了一个奇怪的问题,请有经验的兄弟们帮忙看下。

徐旻 · 2018年08月26日 · 最后由 jackyin 回复于 2018年12月10日 · 3042 次阅读

本人现在要对一个API网关的性能做测试,在搭建环境的时候,遇上了一个让我百思不得其解的问题,想请各位帮忙看一下,能解决当然万分感激,当然能提供解决思路的也十分感谢。

前提

发压机: 云服务器 8核8G
被测机: 云服务器 2核4G

测试工具:基于python的locust。以下的测试我用docker容器起的locust 和 非docker容器起的locust 都尝试过了,数据还是一样的。
locust 运行模式 都是master-slave

测试接口1:
http://.../s/0ms/1k
测试接口2:
http://.../s/200ms/1k

为了方便的调试,用java的spring boot 框架写的测试接口。
测试接口1和测试接口2之间的不同就是接口测试2,我加了200ms的延迟,测试接口没有任何业务逻辑运算。

数据一

场景一

测试接口1:http://.../s/0ms/1k
slave数:1个
并发用户:1000个


这组数据我得到的信息是一个slave的时候,1000个用户并发下得到的TPS是600左右,并且是在linux服务器上一核满负荷的情况下。被测服务器的cpu使用率属于正常。

场景二

测试接口1:http://.../s/0ms/1k
slave数:8个
并发用户:1000个


当我把slave加到8个的时候,1000个用户并发下,TPS差不多要4400左右了,发压机现在是8核满负荷运行。被测服务器的cpu使用也从前面的低使用率上升到了快平均cpu使用率接近45%了。我想说的是1slave的极限tps数 * slave的数量 应该等于整体的 tps的数量。以前测的都是开发写的接口,所以这条规则我是用到现在的。

场景三

测试接口2:http://.../s/200ms/1k
slave数: 1个
并发用户: 1000个

测试接口2,因为有200ms的延迟,所以1个slave进行请求的时候,我得到的500左右tps。其他情况也正常。

场景四

测试接口2:http://.../s/200ms/1k
slave数: 8个
并发用户: 1000个

当我把slave加到8个的时候,问题出现了,就好像突然遇上了什么限制,TPS在1000的时候就到了一个稳定值,如果按照我以往的经验,一个slave的TPS在500,那么8个slave的TPS应该在4000左右才是比较正确的。在看一下负压机的cpu,竟然不是满负荷的,十分悠闲的分在8个cpu上,再看被测服务器这里的cpu和 一个slave进行压力测试数据差不多。

1.刚开始的时候我以为是因为我用容器启动locust的关系,然后在云主机上直接安装locust,发现结果没有改变。所以就排除了容器的问题。
2.本来我是没有做测试接口1的,因为我觉得测试接口2的数据和我想的不一样,会不会应该延迟的关系,所以我才加了测试接口1,但是加了以后,我发现测试接口1的数据和我预想的是一致的,那么在locust的使用上我没有出问题。
3.那么问题是出在哪里,还是我对压力测的概念没有理解透彻?
4.我现在在尝试用jmeter进行测试,这个非GUI的还真的要稍微花点时间,不知道在我能够在liunx上熟练使用jmeter的时候,是否有人能帮忙指点一下。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 13 条回复 时间 点赞

性能瓶颈了

小小测试 回复

昨天我看了下论坛里的帖子,感觉是被测服务器这里的问题,不知道老兄你说的性能瓶颈具体是指哪里的瓶颈和什么样的瓶颈。谢谢。

看下网关、Nginx 这些有吗限制
可能压力在服务器层面已经限制了,导致压力到不了被测服务器

有可能是服务器的连接数瓶颈,加了200ms等待。导致请求连接无法快速释放,出现服务器大量等待线程。

先看下各个机器的资源又没到到瓶颈,一般的CPU、内存、磁盘IO、带宽。
这些没问题,再看压测机和被测机上的TCP端口是否已经满了,最后看代码层面,比如java的看下jvm,还有就是数据库的连接数限制。

1、性能上不去无非两方面原因:压测服务器的性能问题、被压服务器的性能问题

(局域网环境,初步不考虑网络环境因素)

2、压测服务器性能分析:

初步分析得出结论1: 8slave测试接口1(http://.../s/0ms/1k)的时候,压力服务器CPU资源达到瓶颈,服务tps性能应该大于4794,可以增加压力服务器来测试服务器的真实性能;

分析过程如下:

8slave测试接口1(http://.../s/0ms/1k)的时候(算了一下,你的持续运行时间不到90s,大概75s):
测试接口1性能结果:tps可以达到4000,平均响应时间152ms;
服务器资源情况:被测服务器资源无异常,压力服务器8核CPU全部满载,初步推测,随着你加压时间的增加,cpu load会增加至一个稳定的数值;
接口1性能测试结论:

  • 被测服务器的单接口1(http://.../s/0ms/1k)可支持tps性能大于4794;
  • 压力服务器CPU资源出现瓶颈;

分析结论2:压力服务器可以达到每秒发送4000tps的性能。

3、被压服务器性能分析

8slave测试接口2(http://.../s/200ms/1k)的时候,tps上不去,初步认定为被压服务器的性能问题为:连接堵塞 + 响应时间过长。

压力服务器性能分析过程:根据第2部分可以看到,压力服务器最少可支持每秒发送4000tps的能力。
被压服务器连接数分析过程:

8slave测试接口1的时候,被测服务器每核cpu均不到50%,假设目前被测服务器的硬件资源没问题。
计算被测服务器支持的连接数:假设连接数为n,接口平均响应时间为t ms,
则每个连接数每秒可以处理的请求数为 x = 1000 / t;
tps = n * 1000 / t;
则,被测服务器的连接数 n = tps * t / 1000;

根据接口1测试结果,被压服务器连接数至少为:n = tps * t / 1000 = 4794 * 152 / 1000 >= 728;
8slave测试接口2的时候,平均响应时间达到了:999ms,根据上面的公式tps = n * 1000 / t,可以计算出理论上的tps应该>=728,但是实际测试结果tps为990,说明8slave测试接口1时,没有达到被压服务器的最大性能。8slave测试接口2的时候,达到了被压服务器的最大性能,原因是连接数过大或过小造成的请求连接堵塞 和 接口2响应时间过长;

真实连接数计算:8slave测试接口2的时候,平均响应时间999ms,tps990,根据公式: n = tps * t / 1000 = 990 * 999 / 1000 = 989,约等于1000连接数;

结论:

  • 结论1: 8slave测试接口1(http://.../s/0ms/1k)的时候,压力服务器CPU资源达到瓶颈,服务tps性能应该大于4794,可以增加压力服务器来测试服务器的真实性能;
  • 结论2: 8slave测试接口2(http://.../s/200ms/1k)的时候,tps上不去,初步认定为被压服务器的性能问题为:请求连接堵塞 + 响应时间过长。
  • 结论3:当前服务器连接数设置为1000

建议:

  • 建议1: 8slave测试接口1(http://.../s/0ms/1k)的时候,增加压测服务器资源测试,或更换测试工具locust为wrk(目前得知的硬件性能转化率最高的工具)
  • 建议2:8slave测试接口2(http://.../s/200ms/1k)的时候,tps上不去,可以上下调整连接数观察tps变化和响应时间变化,有可能因为连接堵塞导致的响应时间增大。

首先,谢谢大家给的意见和解决方案。太感谢。

楼主,弱弱的问下,你在一台机器上起了8个slave?

简单看了描述,我这里总结及猜测一下,应该8 9不离十。
楼主觉得奇怪的地方:
为什么相同的接口实现,仅仅是加了200ms的延时,为什么总TPS就涨不上去了?
为此,你先搞压力端,排除了压力端的原因。
你接着分析服务器端,发现CPU,内存,网络啥问题也没有,“基本排除”了服务器端的问题。
表示奇怪。
你还在搞Jmeter,打算换一种工具。可惜结果不会有变化。

其实不奇怪。
你200ms的延迟是加在了Java实现里,使用的是new Thread().sleep(200), 此方法及其耗费Java线程资源。因为你是spring boot 的自带启动,本身的线程总数就不多,还用了这么消耗线程资源的方式来实现延时,服务器性能会大大降低。
如果你能监控到JVM进程中的线程状态,会发现都是block 或者 wait。
说白了,服务器性能不行,不是因为硬件资源不行,而是被你的代码强制的暂停住了。

解决方式:

  1. 200ms 的延迟放到压力端去实现,不要放在服务器端。
  2. 如果还是要压力端实现,把spring boot 给换了,换成tomcat 等其他,但记得调优tomcat等其他。

查了一下Jmeter4的源码,其中的停止也是 TimeUnit.MILLISECONDS.sleep(pause); 本质也是Thread.sleep()。

后续楼主有没有得出结论?既然是测试接口应该很好搞。

一些排查原则

  1. 不管什么问题,首先怀疑是客户端的问题
  2. 排查顺序通常是:自己的脚本、设置、机器资源、网络带宽和设置、工具/框架选型本身
  3. 工具是 Locust 的跳过前2点,直接怀疑是它本身有问题,马上用另一款更高效的工具,类似的设置做对比。

这里不提服务端,因为我猜到这步就能结束了。

一个小实验

楼主如果有空可以写这么个简单的接口对比下各种测试工具:

  • 从收到第1个请求开始,前100秒正常响应,比如什么也不做,sleep 10*毫秒*返回
  • 第100秒~第200秒,sleep 50**返回,没看错是50秒
  • 之后又是100秒的正常响应,再接100秒50秒响应,如此反复

这就是识别 coordinated omission(CO)问题的典型方法,然后你看看各种工具的各个百分位数的统计结果,有多少能让你简单地发现这么明显的问题的,结果很可能会吓一跳。

除非你一下子就找到了某2款,通常不管开源还是商业还是自研都全军覆没。

(如果用这个作为首要选型标准,你就会像我一样把 JMeter、nGrinder、Locust、ab、siege 等等统统淘汰了 😆

Keith Mo 回复

大神,某2款是什么工具?你现在用啥工具?

你在用这个locust和jmeter的时候,有没有遇到过最终输出的结果tps和服务端的cpu相差特别大的时候, 我这边测试同一个的环境中的同一个登录接口。最终查看服务端java cpu使用率2000%,而用locust的时候 ,1个slave的时候100%左右,开了4个slave,也就在200%,按照这个比例,难道我要开N个slave,才能达到有效的cpu占用率吗。如果这么计算的话,我想问下,这个locust适合什么样的场景和平台进行测试呢?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册