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内存
测试代码
1$server = new Swoole\Http\Server('127.0.0.1', 9501, SWOOLE_BASE); 2 3$server->set(array('worker_num' => 1)); 4 5$server->on('Request', function($request, $response) { 6 7 $mysql = new Swoole\Coroutine\MySQL(); 8 $res = $mysql->connect(['host' => '127.0.0.1', 'user' => 'root', 'password' => 'root', 'database' => 'test']); 9 if ($res == false) { 10 $response->end("MySQL connect fail!"); 11 return; 12 } 13 $ret = $mysql->query('select sleep(1)'); 14 $response->end("swoole response is ok, result=".var_export($ret, true)); 15}); 16 17$server->start();
代码非常简单,使用BASE模式创建一个Http服务器,并且设置进程为1,收到Http请求后执行一条select sleep(1) 语句,这条SQL模拟了阻塞IO,MySQL的服务器在1秒后返回结果。传统的同步阻塞程序,启动1个进程,毫无疑问只能提供1QPS的处理能力。而Swoole2.0协程不同,它虽然使用同步阻塞方式编写代码,但是底层确是异步IO,即使SQL语言执行时间很长,也可以提供很大的并发能力。
启动程序
1php server.php 2ps aux|grep server.php 3htf 13142 0.6 0.2 328480 42268 pts/24 S+ 10:17 0:00 php server.php
并发100测试
1ab -c 100 -n 1000 http://127.0.0.1:9501/ 2This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 3Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 4Licensed to The Apache Software Foundation, http://www.apache.org/ 5 6Benchmarking 127.0.0.1 (be patient) 7Completed 100 requests 8Completed 200 requests 9Completed 300 requests 10Completed 400 requests 11Completed 500 requests 12Completed 600 requests 13Completed 700 requests 14Completed 800 requests 15Completed 900 requests 16Completed 1000 requests 17Finished 1000 requests 18 19 20Server Software: swoole-http-server 21Server Hostname: 127.0.0.1 22Server Port: 9501 23 24Document Path: / 25Document Length: 85 bytes 26 27Concurrency Level: 100 28Time taken for tests: 10.061 seconds 29Complete requests: 1000 30Failed requests: 0 31Total transferred: 233000 bytes 32HTML transferred: 85000 bytes 33Requests per second: 99.39 [#/sec] (mean) 34Time per request: 1006.092 [ms] (mean) 35Time per request: 10.061 [ms] (mean, across all concurrent requests) 36Transfer rate: 22.62 [Kbytes/sec] received 37 38Connection Times (ms) 39 min mean[+/-sd] median max 40Connect: 0 0 1.3 0 7 41Processing: 1000 1004 4.7 1002 1020 42Waiting: 1000 1004 4.7 1002 1020 43Total: 1000 1005 5.8 1003 1026 44 45Percentage of the requests served within a certain time (ms) 46 50% 1003 47 66% 1004 48 75% 1005 49 80% 1006 50 90% 1016 51 95% 1020 52 98% 1022 53 99% 1022 54 100% 1026 (longest request)
并发1000测试
1ab -c 1000 -n 2000 http://127.0.0.1:9501/ 2This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 3Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 4Licensed to The Apache Software Foundation, http://www.apache.org/ 5 6Benchmarking 127.0.0.1 (be patient) 7Completed 200 requests 8Completed 400 requests 9Completed 600 requests 10Completed 800 requests 11Completed 1000 requests 12Completed 1200 requests 13Completed 1400 requests 14Completed 1600 requests 15Completed 1800 requests 16Completed 2000 requests 17Finished 2000 requests 18 19 20Server Software: swoole-http-server 21Server Hostname: 127.0.0.1 22Server Port: 9501 23 24Document Path: / 25Document Length: 19 bytes 26 27Concurrency Level: 1000 28Time taken for tests: 2.025 seconds 29Complete requests: 2000 30Failed requests: 153 31 (Connect: 0, Receive: 0, Length: 153, Exceptions: 0) 32Total transferred: 344098 bytes 33HTML transferred: 48098 bytes 34Requests per second: 987.66 [#/sec] (mean) 35Time per request: 1012.493 [ms] (mean) 36Time per request: 1.012 [ms] (mean, across all concurrent requests) 37Transfer rate: 165.94 [Kbytes/sec] received 38 39Connection Times (ms) 40 min mean[+/-sd] median max 41Connect: 0 6 6.6 8 18 42Processing: 8 166 336.4 68 2006 43Waiting: 8 166 336.4 68 2006 44Total: 8 173 340.6 83 2022 45 46Percentage of the requests served within a certain time (ms) 47 50% 83 48 66% 87 49 75% 89 50 80% 90 51 90% 1021 52 95% 1087 53 98% 1092 54 99% 1093 55 100% 2022 (longest request)
Length: 153 错误是因为MySQL服务器已经无法支持这么大并发了,拒绝了swoole的连接,因此会抛出错误。
php-fpm测试
为了进行对比,本文还做了php-fpm的测试。同样使用PHP7,修改php-fpm.conf将php-fpm进程设置为1。测试的代码与Swoole的完全一致,也是执行同一个sleep的SQL语句。 因为php-fpm是真正的同步阻塞,耗时太长,因此只能使用并发10请求100的方式测试。
测试代码:
1$db = new mysqli; 2$db->connect('127.0.0.1', 'root', 'root', 'test'); 3$result = $db->query("select sleep(1)"); 4 5if ($result) 6{ 7 print_r($result->fetch_all()); 8} 9else die(sprintf("MySQLi Error: %s", mysqli_error($link))); 10 11 12ab -c 10 -n 100 http://127.0.0.1/mysql.php 13This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 14Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 15Licensed to The Apache Software Foundation, http://www.apache.org/ 16 17Benchmarking 127.0.0.1 (be patient).....done 18 19 20Server Software: nginx/1.10.0 21Server Hostname: 127.0.0.1 22Server Port: 80 23 24Document Path: /mysql.php 25Document Length: 69 bytes 26 27Concurrency Level: 10 28Time taken for tests: 100.086 seconds 29Complete requests: 100 30Failed requests: 0 31Total transferred: 24100 bytes 32HTML transferred: 6900 bytes 33Requests per second: 1.00 [#/sec] (mean) 34Time per request: 10008.594 [ms] (mean) 35Time per request: 1000.859 [ms] (mean, across all concurrent requests) 36Transfer rate: 0.24 [Kbytes/sec] received 37 38Connection Times (ms) 39 min mean[+/-sd] median max 40Connect: 0 0 0.1 0 0 41Processing: 1002 9558 1636.0 10008 10011 42Waiting: 1002 9558 1636.0 10008 10011 43Total: 1002 9558 1636.0 10008 10011 44 45Percentage of the requests served within a certain time (ms) 46 50% 10008 47 66% 10009 48 75% 10009 49 80% 10009 50 90% 10009 51 95% 10010 52 98% 10010 53 99% 10011 54 100% 10011 (longest request) 55
结果评价
可以看到Swoole服务器,即使SQL语句要执行1秒才返回结果,并发100的测试中也提供了100qps的能力,并发1000的测试中QPS为987,但MySQL服务器已经无法提供服务了。而同步阻塞的php-fpm处理并发10请求100的测试花费了100秒才完成,QPS为1。
Swoole2.0的内置协程未来可能会颠覆现代软件的开发模式。