最近为了提升接口qps,想了很多办法,当接口在单机上qps已经达到了极限,很容易想到的就是部署多个api,通过nginx去转发,达到qps翻倍的目的。
但是qps真的能翻倍吗?我用nginx挂两个api,测试了多个接口,发现有的能翻倍,有的qps只能多百分之20,有的qps甚至下降了。
在网上搜索了很多,都说能翻倍,我当时就懵逼了。于是乎就做了以下实验。
实验目的
验证nginx挂两个api,aps真的能翻倍吗?
测试机器以及应用部署情况
内网8核16g(放wrk)
内网8核16g(放nginx)
内网8核16g (放api1)
内网8核心16g(放api2)
测试工具
wrk
测试脚本
./wrk -t16 -c400 -d30s -s test-nginx.lua --latency http://192.168.40.92:9000/test/testNginx
./wrk -t16 -c400 -d30s -s test-nginx.lua --latency http://192.168.40.93:9000/test/testNginx
./wrk -t16 -c400 -d30s -s test-nginx.lua --latency http://192.168.40.91/test/testNgin
备注:第一个和第二个是单独对两个api的测试。第三个是对nginx机器分发两台api的测试
test-nginx.lua
wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"
wrk.body = "{\"sleep\": 1000}"
nginx配置
upstream test-nginx {
server 192.168.40.92:9000 weight=1 ;
server 192.168.40.93:9000 weight=1;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://test-nginx;
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
测试代码
@RestController
@RequestMapping("/test/")
public class TestController {
@PostMapping("/testNginx")
public Response getTest(@Valid @RequestBody TestNginxReq req) {
try {
Thread.sleep(req.getSleep());
} catch (InterruptedException e) {
e.printStackTrace();
}
return Response.ok("test nginx");
}
}
请求示例
{
"sleep": 100
}
返回示例
{
"code": "200",
"msg": "OK",
"body": "test nginx"
}
接口说明:接口啥都没做,就是传入一个sleep参数,然后程序就sleep多长时间。目的是为了通过sleep参数能稳定控制住接口的qps。所以本次实验变量就是单个接口qps,然后讨论接口qps与nginx挂多个api是否能做到qps翻倍的问题。
实验结果
序号
sleep参数
api1的qps
qpi2的qps
通过nginx转两个api的qps
1
200
158.12/s
158.60/s
317.29/s
2
70
453.59/s
453.77/s
905.48/s
3
2
9367.26/s
9335.16/s
12294.76/s
4
0
18829.48/s
18776.76/s
12408.13/s
实验结果分析
1.首先看1,2,3,4实验,当参数相同的时候,api1和api2的qps是一致的,说明两台机器上的api比较稳定。
2.对比1,2号实验,发现当api的qps不高时,nginx转发两台qps翻倍了。
3.查看3号实验,单个qps是9000多,理论上转发两个是18000,但是nginx转2台是12294.76/s。查看实验四更离谱,单个api是18000/s,nginx转两台还是 12408.13/s,这里nginx转发两台api的qps甚至比单个api的性能还低。
分析一下,12000多大概是nginx的瓶颈,所以api如果继续增大qps,那么,转发两台还是12000多(对nginx做优化不在本次讨论范围)。
实验结论
当api比较慢的时候,qps比较低,使用nginx转发,的确能够达到翻倍的效果。这时候瓶颈在api。
当api很快的时候,nginx转发不能翻倍,甚至会下滑,因为瓶颈不在api,而在于nginx或者网络。(nginx转发是多了网络开销)
所以单个接口qps到达一个平衡值,通过nginx刚好能翻倍,然后单个api的qps继续增加,通过nginx转发就达不到翻倍效果了。
访问链路分析
首先看两张图
直接访问api流程.png
访问nginx流程.png
查看上面两张图,有以下已知的内容:
1.api的耗时两张图中是相等的
2.直接访问api两次网络请求,网络传输包中一次带请求参数(t1),一次带接口返回接口(t3),而访问nginx有4个网络请求,网络传输包中两次带请求参数(t1,t2),两次带返回参数(t6,t7)。所以,通过nginx访问的网络传输耗时是直接访问api的两倍(注意:网络耗时很短,这里两倍其实并不多)
3.除了两倍的网络以外,访问nginx还比直接访问api多了nginx处理的耗时。(nginx性能很高,这里时间也很短)
4.总结上面2和3,就是访问nginx比直接访问api多了两倍网络耗时和一次nginx处理耗时。
基于上面已知条件,有以下结论:
1.nginx挂单个api的qps肯定比单个api的qps要低。
2.当api很慢,主要耗时在于api处理耗时,nginx多的那些时间可以忽略不计,所以这时,挂多个api能翻倍。
当api处理耗时比较短,那么nginx多出来的两次网络传输时间和自身处理时间就不可以忽略了,就会出现,不能翻倍,只会达到增加20%,30%这种情况。
4.当api处理时间非常短,几乎和nginx处理耗时相当了,那么不管挂多少个api,都会多出那几次的网络请求耗时和nginx处理耗时,挂多个api的qps肯定也不如一个api的qps。