Swoole2.0是一个革命性的版本,它内置了协程的支持。与Go语言协程不同,Swoole协程完全不需要开发者添加任何额外的关键词,直接以过去最传统的同步阻塞模式编写代码,底层自动进行协程调度实现异步IO。使并发编程变得非常简单。
最新的版本中,内置协程已支持PHP7,同时兼具了性能和并发能力,Swoole的强大超乎想象。
本文基于Github最新的Swoole2.0.3版本进行了并发压力测试,来验证Swoole内置协程的并发能力。
操作系统:Ubuntu 16.04
软件版本:PHP-7.0.14 Swoole-2.0.3
硬件环境:酷睿I5+8G内存
$server = new Swoole\Http\Server('127.0.0.1', 9501, SWOOLE_BASE);
$server->set(array('worker_num' => 1));
$server->on('Request', function($request, $response) {
$mysql = new Swoole\Coroutine\MySQL();
$res = $mysql->connect(['host' => '127.0.0.1', 'user' => 'root', 'password' => 'root', 'database' => 'test']);
if ($res == false) {
$response->end("MySQL connect fail!");
return;
}
$ret = $mysql->query('select sleep(1)');
$response->end("swoole response is ok, result=".var_export($ret, true));
});
$server->start();
代码非常简单,使用BASE模式创建一个Http服务器,并且设置进程为1,收到Http请求后执行一条select sleep(1) 语句,这条SQL模拟了阻塞IO,MySQL的服务器在1秒后返回结果。传统的同步阻塞程序,启动1个进程,毫无疑问只能提供1QPS的处理能力。而Swoole2.0协程不同,它虽然使用同步阻塞方式编写代码,但是底层确是异步IO,即使SQL语言执行时间很长,也可以提供很大的并发能力。
php server.php
ps aux|grep server.php
htf 13142 0.6 0.2 328480 42268 pts/24 S+ 10:17 0:00 php server.php
ab -c 100 -n 1000 http://127.0.0.1:9501/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: swoole-http-server
Server Hostname: 127.0.0.1
Server Port: 9501
Document Path: /
Document Length: 85 bytes
Concurrency Level: 100
Time taken for tests: 10.061 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 233000 bytes
HTML transferred: 85000 bytes
Requests per second: 99.39 [#/sec] (mean)
Time per request: 1006.092 [ms] (mean)
Time per request: 10.061 [ms] (mean, across all concurrent requests)
Transfer rate: 22.62 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.3 0 7
Processing: 1000 1004 4.7 1002 1020
Waiting: 1000 1004 4.7 1002 1020
Total: 1000 1005 5.8 1003 1026
Percentage of the requests served within a certain time (ms)
50% 1003
66% 1004
75% 1005
80% 1006
90% 1016
95% 1020
98% 1022
99% 1022
100% 1026 (longest request)
ab -c 1000 -n 2000 http://127.0.0.1:9501/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests
Server Software: swoole-http-server
Server Hostname: 127.0.0.1
Server Port: 9501
Document Path: /
Document Length: 19 bytes
Concurrency Level: 1000
Time taken for tests: 2.025 seconds
Complete requests: 2000
Failed requests: 153
(Connect: 0, Receive: 0, Length: 153, Exceptions: 0)
Total transferred: 344098 bytes
HTML transferred: 48098 bytes
Requests per second: 987.66 [#/sec] (mean)
Time per request: 1012.493 [ms] (mean)
Time per request: 1.012 [ms] (mean, across all concurrent requests)
Transfer rate: 165.94 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 6 6.6 8 18
Processing: 8 166 336.4 68 2006
Waiting: 8 166 336.4 68 2006
Total: 8 173 340.6 83 2022
Percentage of the requests served within a certain time (ms)
50% 83
66% 87
75% 89
80% 90
90% 1021
95% 1087
98% 1092
99% 1093
100% 2022 (longest request)
Length: 153 错误是因为MySQL服务器已经无法支持这么大并发了,拒绝了swoole的连接,因此会抛出错误。
为了进行对比,本文还做了php-fpm的测试。同样使用PHP7,修改php-fpm.conf将php-fpm进程设置为1。测试的代码与Swoole的完全一致,也是执行同一个sleep的SQL语句。 因为php-fpm是真正的同步阻塞,耗时太长,因此只能使用并发10请求100的方式测试。
$db = new mysqli;
$db->connect('127.0.0.1', 'root', 'root', 'test');
$result = $db->query("select sleep(1)");
if ($result)
{
print_r($result->fetch_all());
}
else die(sprintf("MySQLi Error: %s", mysqli_error($link)));
ab -c 10 -n 100 http://127.0.0.1/mysql.php
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient).....done
Server Software: nginx/1.10.0
Server Hostname: 127.0.0.1
Server Port: 80
Document Path: /mysql.php
Document Length: 69 bytes
Concurrency Level: 10
Time taken for tests: 100.086 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 24100 bytes
HTML transferred: 6900 bytes
Requests per second: 1.00 [#/sec] (mean)
Time per request: 10008.594 [ms] (mean)
Time per request: 1000.859 [ms] (mean, across all concurrent requests)
Transfer rate: 0.24 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 0
Processing: 1002 9558 1636.0 10008 10011
Waiting: 1002 9558 1636.0 10008 10011
Total: 1002 9558 1636.0 10008 10011
Percentage of the requests served within a certain time (ms)
50% 10008
66% 10009
75% 10009
80% 10009
90% 10009
95% 10010
98% 10010
99% 10011
100% 10011 (longest request)
可以看到Swoole服务器,即使SQL语句要执行1秒才返回结果,并发100的测试中也提供了100qps的能力,并发1000的测试中QPS为987,但MySQL服务器已经无法提供服务了。而同步阻塞的php-fpm处理并发10请求100的测试花费了100秒才完成,QPS为1。
Swoole2.0的内置协程未来可能会颠覆现代软件的开发模式。