Swoole2.0内置协程并发测试

原创
2016/12/15 10:28
阅读数 5.6K

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

并发100测试

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)

并发1000测试

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测试

为了进行对比,本文还做了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的内置协程未来可能会颠覆现代软件的开发模式。

展开阅读全文
打赏
14
18 收藏
分享
加载中
评论精彩
2017/06/24 12:01
回复
举报
$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)');

这段mysql操作已经支持连接池了吗?不需要close吗?
2017/04/18 11:51
回复
举报
评论很精彩👍✨
2017/02/27 12:49
回复
举报
天峰同学很有耐心啊,龟壳兄可能不太了解情况,异步能力在别的语言里并不稀缺,而对PHP是最大的功能缺陷,已有的libev,libevent只能实现基础的异步能力,但真正有实用价值的异步能力必须有mysql,redis等服务的异步驱动,swoole现在已经把PHP的异步能力基本补全了,但是C的实现是个性能的优势,但又让几乎所有的PHP程序员难以参与进来了
2017/01/12 10:44
回复
举报
我觉得评论比正文好看😄:bowtie:
2016/12/29 23:51
回复
举报
评论很精彩👍✨
2016/12/16 16:46
回复
举报

引用来自“乌龟壳”的评论

引用来自“乌龟壳”的评论

python的gevent配合mysql官方的纯python的驱动,打上monkey_patch补丁后,很早就实现了mysql驱动的协程化。

但是基于c的堆栈级协程性能损失还是比较大的。这也是为什么python的gevent一直不痛不痒的原因,要高性能只能写异步c代码一条路。

引用来自“matyhtf”的评论

swoole的所有驱动都是用C实现的,没有性能问题。只有业务逻辑才用PHP。

引用来自“乌龟壳”的评论

swoole把做高性能网络开发,不适合php做的部分都用c实现了,php对它来说更像一个具有逻辑功能的配置文件。

这个结构一般是没啥问题,反正关键的代码都用c写好了,主要是php太慢,稍微复杂点的协议就要拿c写扩展。所以一直都觉得你这样做和php没什么关系。不仅没什么关系,还把这种对性能比较敏感的程序开发,拉到php这种不合适的语言里,一遇到复杂点的处理又没有现成的库就要写c扩展,和直接用c做区别不大。但是浪费你做php包装的时间。

再说精简点,就是nginx这种模式我觉得才正常。

引用来自“matyhtf”的评论

Swoole只提供最常用的几种协议支持,其他类型的网络协议客户端完全可以基于Swoole的TCP、UDP客户端用PHP代码去实现。现在PHP7已经做了大量性能优化,近期还会加入JIT。性能不是问题。
PHP语言发展了20几年,有丰富的标准库和第三方库支持,不是Nginx能比的。

引用来自“乌龟壳”的评论

你能举出一个php库和【异步高性能IO程序开发场景】有关的,但是nginx缺失的吗?这种场景一般逻辑都很简单,大部分只是做一个浅层转换就抛到下一个环节了。这样更没有什么库不库的意义了。

我举个例子——GD,确实php有而nginx没有,但是图像处理和swoole的场景有什么关系呢?gd一次至少几十毫秒,一秒也就几十次了不得了,用不用swoole都没所谓。

你用swoole做了一个好东西,并且也在某些项目上取得了好的效果。但是我觉得你这库大部分都是c的东西,比如http解析部分等,实际好用的是swoole本身,php对于它来说只是绑定了一门具有逻辑描述能力的配置,显然php在swoole的成功中扮演得并不是那么重要的角色。我并非说swoole做的不好,只是觉得和php扯那么紧感觉不值。

你有php情怀也没什么好说对与不对,只是觉得这样浪费了很多不该浪费的精力而已。nginx并非不能绑定php,只是它的重心是nginx本身,php在任何角度,在【高性能IO场景】都是它的附属,可以集成php也可以集成lua,也可以集成python。功能上不一定有大的不同。

引用来自“徐长龙”的评论

这么说很有问题啊,至少我觉得你对php的运行模式不是很理解,目前来说PHP多数使用php-fpm方式工作的,但是这个方式有一定的缺点:当请求过来的时候fpm接收到一个请求一个进程只能同时处理一个请求。

而一台服务器平时只能跑128个进程相对来说性能较好。

经过我们的分析发现很多业务逻辑代码实际时间耗费在mysql、redis等服务的通讯上60%以上时间都在阻塞等待这些数据服务提供服务。

这些导致了一定cpu资源的浪费,所以我们利用驱动协程实际将IO等待时间去执行其他非IO操作的请求操作。如果一个逻辑处理1秒,1秒QPS只有128个。您不觉得浪费么?

这就是这次协程改进的意义。它可以让swoole作为fpm 从128个并发增长更多。

另外您没做过分布式的服务吗?通讯是分布式的基础。Swoole做的只是降低了进程管理和通讯以及多机配合的难度。没有你说的这些问题。

至于你掌握多少个语言我倒是不在意,任何一家公司多个语言一起协同合作都是存在成本的。有一个低门槛快速实现业务降低维护成本都是功德无量的事情。

重复造轮子什么的都是乱说,您听过奔驰车的轮子用飞机的轮子么~都不是一样领域……为什么强求呢
你说的场景swoole确实有帮助,而且如果用swoole代替了fpm,那基本上只要开cpu核心个数个swoole进程即可,除非还有些io等导致进程挂起的操作是swoole没异步化的才要加进程数。

不过我讨论的主要是大量长连接推送的情况。这类场景本来由c实现的swoole是很合适的,但是拉上php就不一定了。至于我说的语言什么的,只是为了表达swoole配什么语言不重要。

你倒是提醒了我,之前一直盯着【高并发】这块,实际例如几百上千个小并发,也是适合swoole的场景的。而这一块确实php以前没有。谢谢。

回复@乌龟壳 : 原来PHP自带的通讯直有Socket很多底层坑都没有修,很多人用很闹心啊,长链接还好了,一些场景减少握手次数很有用~但不是万能的~
2016/12/16 16:42
回复
举报

引用来自“乌龟壳”的评论

python的gevent配合mysql官方的纯python的驱动,打上monkey_patch补丁后,很早就实现了mysql驱动的协程化。

但是基于c的堆栈级协程性能损失还是比较大的。这也是为什么python的gevent一直不痛不痒的原因,要高性能只能写异步c代码一条路。

引用来自“matyhtf”的评论

swoole的所有驱动都是用C实现的,没有性能问题。只有业务逻辑才用PHP。

引用来自“乌龟壳”的评论

swoole把做高性能网络开发,不适合php做的部分都用c实现了,php对它来说更像一个具有逻辑功能的配置文件。

这个结构一般是没啥问题,反正关键的代码都用c写好了,主要是php太慢,稍微复杂点的协议就要拿c写扩展。所以一直都觉得你这样做和php没什么关系。不仅没什么关系,还把这种对性能比较敏感的程序开发,拉到php这种不合适的语言里,一遇到复杂点的处理又没有现成的库就要写c扩展,和直接用c做区别不大。但是浪费你做php包装的时间。

再说精简点,就是nginx这种模式我觉得才正常。

引用来自“matyhtf”的评论

Swoole只提供最常用的几种协议支持,其他类型的网络协议客户端完全可以基于Swoole的TCP、UDP客户端用PHP代码去实现。现在PHP7已经做了大量性能优化,近期还会加入JIT。性能不是问题。
PHP语言发展了20几年,有丰富的标准库和第三方库支持,不是Nginx能比的。

引用来自“乌龟壳”的评论

你能举出一个php库和【异步高性能IO程序开发场景】有关的,但是nginx缺失的吗?这种场景一般逻辑都很简单,大部分只是做一个浅层转换就抛到下一个环节了。这样更没有什么库不库的意义了。

我举个例子——GD,确实php有而nginx没有,但是图像处理和swoole的场景有什么关系呢?gd一次至少几十毫秒,一秒也就几十次了不得了,用不用swoole都没所谓。

你用swoole做了一个好东西,并且也在某些项目上取得了好的效果。但是我觉得你这库大部分都是c的东西,比如http解析部分等,实际好用的是swoole本身,php对于它来说只是绑定了一门具有逻辑描述能力的配置,显然php在swoole的成功中扮演得并不是那么重要的角色。我并非说swoole做的不好,只是觉得和php扯那么紧感觉不值。

你有php情怀也没什么好说对与不对,只是觉得这样浪费了很多不该浪费的精力而已。nginx并非不能绑定php,只是它的重心是nginx本身,php在任何角度,在【高性能IO场景】都是它的附属,可以集成php也可以集成lua,也可以集成python。功能上不一定有大的不同。

引用来自“徐长龙”的评论

这么说很有问题啊,至少我觉得你对php的运行模式不是很理解,目前来说PHP多数使用php-fpm方式工作的,但是这个方式有一定的缺点:当请求过来的时候fpm接收到一个请求一个进程只能同时处理一个请求。

而一台服务器平时只能跑128个进程相对来说性能较好。

经过我们的分析发现很多业务逻辑代码实际时间耗费在mysql、redis等服务的通讯上60%以上时间都在阻塞等待这些数据服务提供服务。

这些导致了一定cpu资源的浪费,所以我们利用驱动协程实际将IO等待时间去执行其他非IO操作的请求操作。如果一个逻辑处理1秒,1秒QPS只有128个。您不觉得浪费么?

这就是这次协程改进的意义。它可以让swoole作为fpm 从128个并发增长更多。

另外您没做过分布式的服务吗?通讯是分布式的基础。Swoole做的只是降低了进程管理和通讯以及多机配合的难度。没有你说的这些问题。

至于你掌握多少个语言我倒是不在意,任何一家公司多个语言一起协同合作都是存在成本的。有一个低门槛快速实现业务降低维护成本都是功德无量的事情。

重复造轮子什么的都是乱说,您听过奔驰车的轮子用飞机的轮子么~都不是一样领域……为什么强求呢
你说的场景swoole确实有帮助,而且如果用swoole代替了fpm,那基本上只要开cpu核心个数个swoole进程即可,除非还有些io等导致进程挂起的操作是swoole没异步化的才要加进程数。

不过我讨论的主要是大量长连接推送的情况。这类场景本来由c实现的swoole是很合适的,但是拉上php就不一定了。至于我说的语言什么的,只是为了表达swoole配什么语言不重要。

你倒是提醒了我,之前一直盯着【高并发】这块,实际例如几百上千个小并发,也是适合swoole的场景的。而这一块确实php以前没有。谢谢。
2016/12/16 15:21
回复
举报

引用来自“乌龟壳”的评论

python的gevent配合mysql官方的纯python的驱动,打上monkey_patch补丁后,很早就实现了mysql驱动的协程化。

但是基于c的堆栈级协程性能损失还是比较大的。这也是为什么python的gevent一直不痛不痒的原因,要高性能只能写异步c代码一条路。

引用来自“matyhtf”的评论

swoole的所有驱动都是用C实现的,没有性能问题。只有业务逻辑才用PHP。

引用来自“乌龟壳”的评论

swoole把做高性能网络开发,不适合php做的部分都用c实现了,php对它来说更像一个具有逻辑功能的配置文件。

这个结构一般是没啥问题,反正关键的代码都用c写好了,主要是php太慢,稍微复杂点的协议就要拿c写扩展。所以一直都觉得你这样做和php没什么关系。不仅没什么关系,还把这种对性能比较敏感的程序开发,拉到php这种不合适的语言里,一遇到复杂点的处理又没有现成的库就要写c扩展,和直接用c做区别不大。但是浪费你做php包装的时间。

再说精简点,就是nginx这种模式我觉得才正常。

引用来自“matyhtf”的评论

Swoole只提供最常用的几种协议支持,其他类型的网络协议客户端完全可以基于Swoole的TCP、UDP客户端用PHP代码去实现。现在PHP7已经做了大量性能优化,近期还会加入JIT。性能不是问题。
PHP语言发展了20几年,有丰富的标准库和第三方库支持,不是Nginx能比的。

引用来自“乌龟壳”的评论

你能举出一个php库和【异步高性能IO程序开发场景】有关的,但是nginx缺失的吗?这种场景一般逻辑都很简单,大部分只是做一个浅层转换就抛到下一个环节了。这样更没有什么库不库的意义了。

我举个例子——GD,确实php有而nginx没有,但是图像处理和swoole的场景有什么关系呢?gd一次至少几十毫秒,一秒也就几十次了不得了,用不用swoole都没所谓。

你用swoole做了一个好东西,并且也在某些项目上取得了好的效果。但是我觉得你这库大部分都是c的东西,比如http解析部分等,实际好用的是swoole本身,php对于它来说只是绑定了一门具有逻辑描述能力的配置,显然php在swoole的成功中扮演得并不是那么重要的角色。我并非说swoole做的不好,只是觉得和php扯那么紧感觉不值。

你有php情怀也没什么好说对与不对,只是觉得这样浪费了很多不该浪费的精力而已。nginx并非不能绑定php,只是它的重心是nginx本身,php在任何角度,在【高性能IO场景】都是它的附属,可以集成php也可以集成lua,也可以集成python。功能上不一定有大的不同。
这么说很有问题啊,至少我觉得你对php的运行模式不是很理解,目前来说PHP多数使用php-fpm方式工作的,但是这个方式有一定的缺点:当请求过来的时候fpm接收到一个请求一个进程只能同时处理一个请求。

而一台服务器平时只能跑128个进程相对来说性能较好。

经过我们的分析发现很多业务逻辑代码实际时间耗费在mysql、redis等服务的通讯上60%以上时间都在阻塞等待这些数据服务提供服务。

这些导致了一定cpu资源的浪费,所以我们利用驱动协程实际将IO等待时间去执行其他非IO操作的请求操作。如果一个逻辑处理1秒,1秒QPS只有128个。您不觉得浪费么?

这就是这次协程改进的意义。它可以让swoole作为fpm 从128个并发增长更多。

另外您没做过分布式的服务吗?通讯是分布式的基础。Swoole做的只是降低了进程管理和通讯以及多机配合的难度。没有你说的这些问题。

至于你掌握多少个语言我倒是不在意,任何一家公司多个语言一起协同合作都是存在成本的。有一个低门槛快速实现业务降低维护成本都是功德无量的事情。

重复造轮子什么的都是乱说,您听过奔驰车的轮子用飞机的轮子么~都不是一样领域……为什么强求呢
2016/12/16 14:41
回复
举报

引用来自“ddonng”的评论

我用Dora-rpc,感谢鸟哥天峰徐蓝总!🐂🐂🐂
😄
2016/12/16 14:27
回复
举报
更多评论
打赏
36 评论
18 收藏
14
分享
返回顶部
顶部