webman中,【workerman v5 http-client 协程】与【guzzlehttp/guzzle 异步并发请求】对比优势,似乎并不明显。
这几天研究workerman v5的http-client协程的,目的是提高程序中IO请求的性能。发现协程的方式并不能减少请求时间,而且对并发提升也不多。
安装http-client
php8.1 /usr/local/bin/composer require workerman/workerman v5.0.0-beta.5 revolt/event-loop ^1.0.0 workerman/http-client ^2.0.0
安装Http客户端
php8.1 /usr/local/bin/composer require yzh52521/easyhttp
app\controller\IndexController::demo1()
执行时间:163ms
$start = Carbon::now();
$http = new Client();
$response1 = $http->request('http://服务iP:8002/search', [
'method' => 'POST',
'headers' => [
'Content-Type' => 'application/json',
],
'data' => json_encode([
'query' => '我是谁',
'limit' => 5
])
]);
$response2 = $http->request('http://服务iP:8002/search', [
'method' => 'POST',
'headers' => [
'Content-Type' => 'application/json',
],
'data' => json_encode([
'query' => '我不知道',
'limit' => 5
])
]);
$response = array_merge(json_decode($response1->getBody(), true),
json_decode($response2->getBody(), true)
);
$runtime = Carbon::now()->diffInMilliseconds($start);
return json([
'runtime' => $runtime . 'ms',
'data' => $response
]);
压测结果
ab -n 1000 -c 50 http://192.168.10.10:5001/index/demo1
Server Software: workerman
Server Hostname: 192.168.10.10
Server Port: 5001
Document Path: /index/demo1
Document Length: 2867 bytes
Concurrency Level: 50
Time taken for tests: 33.856 seconds
Complete requests: 1000
Failed requests: 999
(Connect: 0, Receive: 0, Length: 999, Exceptions: 0)
Total transferred: 2983999 bytes
HTML transferred: 2867999 bytes
Requests per second: 29.54 [#/sec] (mean)
Time per request: 1692.787 [ms] (mean)
Time per request: 33.856 [ms] (mean, across all concurrent requests)
Transfer rate: 86.07 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.2 0 16
Processing: 987 1670 196.8 1689 2228
Waiting: 987 1670 196.8 1689 2228
Total: 991 1670 196.6 1690 2228
Percentage of the requests served within a certain time (ms)
50% 1690
66% 1756
75% 1777
80% 1801
90% 1900
95% 2033
98% 2082
99% 2104
100% 2228 (longest request)
app\controller\IndexController::demo2()
执行时间:168ms
$start = Carbon::now();
$response1 = Http::asJson()->post('http://服务iP:8002/search', [
'query' => '我不知道',
'limit' => 5
]);
$response2 = Http::asJson()->post('http://服务iP:8002/search', [
'query' => '我不知道',
'limit' => 5
]);
$response = array_merge($response1->json(), $response2->json());
$runtime = Carbon::now()->diffInMilliseconds($start);
return json([
'runtime' => $runtime . 'ms',
'data' => $response
]);
压测结果
ab -n 1000 -c 50 http://192.168.10.10:5001/index/demo2
Server Software: workerman
Server Hostname: 192.168.10.10
Server Port: 5001
Document Path: /index/demo2
Document Length: 3008 bytes
Concurrency Level: 50
Time taken for tests: 35.976 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 3124000 bytes
HTML transferred: 3008000 bytes
Requests per second: 27.80 [#/sec] (mean)
Time per request: 1798.794 [ms] (mean)
Time per request: 35.976 [ms] (mean, across all concurrent requests)
Transfer rate: 84.80 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.5 0 3
Processing: 189 1758 1414.9 1747 13011
Waiting: 189 1758 1414.9 1747 13011
Total: 192 1758 1415.1 1747 13012
Percentage of the requests served within a certain time (ms)
50% 1747
66% 1780
75% 1803
80% 1856
90% 1913
95% 1960
98% 7578
99% 10454
100% 13012 (longest request)
app\controller\IndexController::demo3()
执行时间:167ms
$aa = [];
$start = Carbon::now();
$promises = [
Http::asJson()->postAsync('http://服务iP:8002/search', [
'query' => '我不知道',
'limit' => 5
]),
Http::asJson()->postAsync('http://服务iP:8002/search', [
'query' => '我不知道',
'limit' => 5
])
];
$pool = Http::multiAsync($promises, function (Response $response, $index) use (&$aa) {
$aa[] = $response->json();
echo "发起第 $index 个异步请求" . PHP_EOL;
});
$pool->promise()->wait();
$runtime = Carbon::now()->diffInMilliseconds($start);
return json([
'runtime' => $runtime . 'ms',
'data' => $aa
]);
压测结果
ab -n 1000 -c 50 http://192.168.10.10:5001/index/demo3
Server Software: workerman
Server Hostname: 192.168.10.10
Server Port: 5001
Document Path: /index/demo3
Document Length: 3012 bytes
Concurrency Level: 50
Time taken for tests: 36.145 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 3128000 bytes
HTML transferred: 3012000 bytes
Requests per second: 27.67 [#/sec] (mean)
Time per request: 1807.252 [ms] (mean)
Time per request: 36.145 [ms] (mean, across all concurrent requests)
Transfer rate: 84.51 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.6 0 4
Processing: 170 1767 862.1 1775 9789
Waiting: 170 1767 862.1 1775 9789
Total: 174 1767 862.3 1776 9790
Percentage of the requests served within a certain time (ms)
50% 1776
66% 1800
75% 1816
80% 1834
90% 1871
95% 1912
98% 4249
99% 7172
100% 9790 (longest request)
使用http-client协程客户端的方式,相对比guzzlehttp同步、异步并发,似乎并不能提高多少性能,而且单次消耗时间是差不多的,是我用法有问题吗?
后面发现是因为第三方接口成为瓶颈,在第三方接口不是瓶颈的情况下,webman协程http-client方式性能提升非常明显
会不会 http://服务iP:8002/search 这个接口是瓶颈,只能支持这些并发?直接压测这个接口试下
直接压测服务ip:8002/search接口,Requests per second: 58.77 所以应该不是这个问题,理想情况下,我是想两次请求,消耗一次请求的时间
直接压测服务ip:8002/search接口,Requests per second: 58.77,所以它是瓶颈啊。
两次请求Requests per second就是29.x
原来是这么换算的,感谢,那针对这种第三方缓慢的接口,有什么好办法提高请求性能吗
win10系统,我测试优势很明显,协程主要是进程不阻塞,能够接受多个请求,使用guzzlehttp 不管同步和异步,对于当前进程来说是阻塞的,就是说请求照样排队,协程是能够接收多个请求,同时处理,所以并发很高,我这里有压测数据非常明显!![]这两个接口写法是一模一样的,就是一个用的协程,一个用的guzzlehttp同步 都是请求的第三方接口, 这是同步的压测, 这是协程的压测,性能差距很大
我的写法有问题么
我尝试按照你的压测参数,使用ab -n 100 -c 100,并且将程序中的请求由2个变为1个,得到的结果为http协程:57.50 [#/sec] 比较接近单独压测第三方xxx/_search接口。 guzzle同步的结果为: 23.11 [#/sec]。确实提高了很多
真的吗
测试1
尝试将代码中的2次请求改为1次,并将压测并发改为
使用http协程和guzzle同步的方式结果分为:
http协程:Requests per second: 58.89 [#/sec] ,基本上与直接压测第三方接口一样
guzzle同步:Requests per second: 54 [#/sec],稍微低一些
测试2
依旧是在请求中请求第三方接口两次,
ab -n 1000 -c 100 http://192.168.10.10:5001/index/demo1
ab -n 1000 -c 100 http://192.168.10.10:5001/index/demo2
将第三方接口,换为get百度接口,并压测
http协程:Requests per second: 114.55 [#/sec] (mean)
http同步:Requests per second: 69.84 [#/sec] (mean)
结论
协程请求可有有效的提高并发的性能,但是受第三方接口的影响,极端情况下,若第三方接口缓慢时,协程请求与同步请求几乎差不多
第三方吞吐量只有60QPS,同步和协程大概QPS都在50-60左右。
如果第三方吞吐量有1000QPS,同步可能QPS有可能还是60左右,但是协程可以达到1000左右。是这个区别。
感谢,这个表达的清晰了@six
协程是提高并发处理量,不是降低单个任务的处理时间
一条100m长的路,你多少速度跑都是要跑完100m,这是硬性资源
好吧,我原先理解的协程应该可以充分利用多核,可以近并发的处理多个IO请求,最终耗时是最长那条路的耗时。不知道golang中的协程,是否可以达到并行的请求。
还是以一条100m跑道举例,IO阻塞相当于当前选手受伤了,以前的做法是别人等他在跑道里处理完伤口后跑完全程,下一个选手才能继续跑,协程的做法是直接把受伤的抬出跑道处理伤口,这样可以空出跑道让下一个选手先跑,处理完伤口再把他抬回受伤的地方继续跑,实际上从头到尾只有一条跑道
你要弄清楚并发和并行的区别
并发是一个时间段内处理不同的事情,并行是一个时间点处理不同的事情(相当于我有N条100m的跑道)
golang我不了解
我再看了上面的问题,抱歉之前没细看,你这个请求第三方接口,那瓶颈永远取决于第三方,跟你系统没关系,你用c/cpp写都一样,不会因为你用了协程,第三方接口的请求时间就会从1s变成0.1s
跑道这个很形象
感谢
go 的 Goroutine