V2EX › 问与答
有关 ab 压力测试的一个奇怪的现象
geew · 2016-09-26 18:33:06 +08:00 · 5393 次点击
这是一个创建于 1572 天前的主题,其中的信息可能已经有所发展或是发生改变。
我用 ab 200 个并发 60000 次请求 服务器没多大压力 结果如下:
Concurrency Level: 200
Time taken for tests: 14.812 seconds
Complete requests: 60000
Failed requests: 0
Total transferred: 42060000 bytes
HTML transferred: 28560000 bytes
Requests per second: 4050.64 [#/sec] (mean)
Time per request: 49.375 [ms] (mean)
Time per request: 0.247 [ms] (mean, across all concurrent requests)
Transfer rate: 2772.95 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.4 0 7
Processing: 4 47 112.2 34 3049
Waiting: 4 47 112.2 34 3049
Total: 8 47 112.2 34 3049
Percentage of the requests served within a certain time (ms)
50% 34
66% 36
75% 38
80% 40
90% 44
95% 49
98% 68
99% 1022
100% 3049 (longest request)
但是同事用 php 开了 30 个进程 同时请求 服务器会概率性报 502, 60000 个请求下来, 错误的请求非常多
错误日志:
2016/09/26 18:27:37 [crit] 21240#0: *1235685 connect() to 172.17.10.173:7007 failed (99: Cannot assign requested address) while connecting to upstream, client: 172.17.10.173, server: 172.17.10.173
看了 nginx 的访问日志, ab 测试的时候 每秒请求达到 4 千多次
但是同事的请求每秒才三千多 为啥同事的请求会有很多失败的呢? 谁能解答一下疑惑吗 不胜感激了
第 1 条附言 · 2016-09-26 20:10:36 +08:00
就这么简单的开20个进程来刷都会报错....用ab跑400个并发都没啥 是不是ab的并发是假的啊...
python
# coding: utf8
import requests
if __name__ == '__main__':
import sys
argv = sys.argv
c = argv[1]
for i in range(int(c)):
req = requests.get('http://172.17.10.173:7000/user/profile/?user_id=50')
print req.json()
bash脚本
#!/bin/bash
for((i=0; i<20; i++));
do
echo $i
python t.py 3000 &
done;
第 2 条附言 · 2016-09-26 21:02:49 +08:00
以上 python 脚本会导致服务器停止响应的问题应该是 过多的请求导致了 过多的 tcp time_wait 状态导致以后的请求无法绑定端口 然后就报错了....
实际看服务器上的 time_wait 也确实非常多
用 ab 测试就不会有这个问题 最多的 time_wait 也就一万多...
不知道为啥会这样, 估计是 ab 对并发请求做了优化吧
第 3 条附言 · 2016-09-26 21:12:53 +08:00
好吧 我想我知道原因了
是客户端的 TIME_WAIT 过多导致客户端无法建立连接了 是自己把自己刷死了 跟服务器没关系....
23333
第 4 条附言 · 2016-09-27 18:53:40 +08:00
总结一下吧
ab的并发测试没问题
只是我们在多次查询的时候的写法有问题, 导致了客户端产生过多的time-wait状态进而影响了新连接的建立, 最终的情况就是客户端建立不了连接无法请求
关于time-wait, 根据tcp的断开的四次握手, 主动断开方会产生time-wait的状态并保持两个msl(60秒)时间, 从而占用连接资源
客户端多次请求服务端的时候, 由于每次都是新建连接(没有复用之前的连接) 而且头部默认 Connection:keep-alive, 从而导致了主动断开连接的一方是客户端, 当请求过多(20*3000)的时候, 客户端会产生大量的time-wait, 然后就没有然后了. 这个解决方法很简单, 设置每次请求的 conneciton为close, 把关闭连接提交给服务端, 但是这样会导致服务端产生大量的time-wait从而影响服务端. 所以最终的解决方案两个端都要做相应的处理
客户端: 多次请求复用连接, 设置keep-alive, 比如python的话 可以用 requests.session() 新建一个会话, 每次使用该会话进行请求, 测试表明, 这种情况下不会产生过多的time-wait
服务端: 更改tcp的系统参数: (以下设置表明不重用tw的连接, 但是打开系统快速回收tw)
sysctl -w net.ipv4.tcp_tw_reuse=0
sysctl -w net.ipv4.tcp_tw_recycle=1
sysctl -w net.ipv4.tcp_timestamps=1
添加了这几个配置之后, 可以明显的看到服务端的tw状态连接数不会过大, 维持在一个可以接受的范围了.
参考:
http://huoding.com/2013/12/31/316
http://www.qmailer.net/archives/92.html
http://www.cnblogs.com/yjf512/p/5327886.html