三种 PHP 运行环境的性能对比

作者介绍:石仕海,14年校招入职腾讯互娱运营部运营开发岗位,参与腾讯游戏营销活动开发和营销平台建设,3年php开发经验。

nginx + swoole

swoole是一个异步、并行、高性能的网络通信引擎,使用纯C语言编写,提供了php语言的异步多线程服务器。swoole内置了http/websocket服务器端和客户端,http2.0服务器端,支持类似Go语言的协程,可以使用同步代码实现一步程序。

swoole采用I/O多路复用异步阻塞的Reactor模型,采用多线程Reactor+多线程Worker实现异步I/O。Reactor基于Epoll,每个Reactor可以处理无数个连接请求,因而可以轻松处理高并发。

Nginx+swoole模式下,nginx作为前端接入层转发机,swoole作为应用服务器构建高并发web服务。

nginx 请求转发swoole配置

server{
  listen 80;
  server_name swooledev.com www.swooledev.com
  location /{
    root /data/htdocs/swooledir;
    if(!-e $request_filename){
      proxy_pass http://127.0.0.1:9501;
    }
  }
}

9501是swoole服务器监听的端口。root设置为静态文件目录。如果请求静态文件则nginx直接处理,当请求动态文件时,则发送给swoole服务器来进行处理。

nginx + php-fpm

FastCGI是一个中立的技术标准,php-fpm是php语言的FastCGI进程管理器。

CGI的fork-and-execute模式有很多缺点,每接收一个请求就要fork一个进程处理,只能接收一个请求做出一个响应;每一个web请求PHP都必须重新解析php.ini文件,重新载入全部扩展并初始化全部数据结构。

FastCGI会事先启动起来,解析php.ini文件,载入扩展,初始化数据结构都只会在启动时完成,作为一个CGI管理服务器存在,使用进程/线程池预先启动一系列的子进程来等待处理。然后web服务器发过来请求,一旦FastCGI接收到请求就交给子进程处理,不需要在接收到请求后启动CGI,会快很多。Web服务器通过一个socket长连接请求FastCGI进程管理器。

FastCGI进程像是一个常驻CGI,在请求到达时,FastCGI进程管理器选择并连接一个PHP-CGI解释器去接收web服务器发送过来的环境变量和标准输入,请求处理完成后将标准输出或错误从同一连接返回给web服务器,该PHP-CGI解释器子进程等待处理来自FastCGI进程管理器的下一个连接。

nignx 进程参数配置

worker_porcesses 2;
worker_cpu_affinity 01 10;

测试服务器环境为2核CPU,配置nginx参数worker_processes为2,充分利用cpu性能;同时worker_cpu_affinity参数设为01和10是为了把2个nginx进程绑定到2个cpu上,减少多cpu核切换造成的寄存器等现场重建带来的性能消耗。

nginx 请求转发php-fpm配置

location ~\.php{
  root html
  fastcgi_pass 127.0.0.1:9000;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;
  include fastcgi_params;
}

9000是fast_cgi监听的端口,当有php请求过来时,nginx服务器会把请求转发到php-fpm进程管理器,php-fpm收到请求后就会交给一个子进程处理该请求。

apache + mod_php

mod_php模式运行php,意味着php是作为apache的一个模块来启动。只有在apache启动的时候会读取php.ini配置文件并加载扩展模块,在apache运行期间是不会再去读取和加载扩展模块的。Apache出于稳定性和安全性考虑,通常使用默认的prefork模式运行php程序。在prefork模式下,一个单独的控制进程负责产生子进程,这些子进程用于监听请求并作出应答。

Apache总是试图保持一些备用或空闲的子进程用于迎接即将到来的请求,这样客户端无需在得到服务前等候子进程的产生。但是,一旦连接数多了,apache必须要生成更多的进程来响应请求,CPU对于进程的切换就很频繁,很耗事件和资源,导致apache性能下降;同时,apache在同步阻塞I/O模型下,select遍历多个连接句柄才能知道句柄是否有事件通知,因此效率非常低。

使用命令httpd -l可以查看apache是运行在prefork模式还是在worker模式,查看结果如下:

compiled in modules:
core.c
prefork.c
http_codre.c
mod_so.c

可见当前服务器上配置的apache使用prefork模式运行,prefork模式的运行参数如下:

<IfModule prefork.c>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 256
MaxClients 256
MaxRequestsPerChild 4000
</IfModule>

服务器性能对比测试

运行环境说明:Thinkpad X1 Carbon,使用 VMWare开启2核cpu+1G内存虚拟机,CentOS6.7操作系统

ginx + swoolen:2个nginx woker process,1个swoole process,静态请求nginx直接处理,动态请求转发swoole处理;nginx版本为1.10.2,swoole版本为1.9.6。

nginx + php-fpm:2个nginx worker process,2个php-fpm process,静态请求nginx直接处理,动态请求转发php-fpm处理;nginx版本为1.01.2,php-fpm版本为7.1.2。

apache + mod_php:8个httpd进程,静态和动态请求都由apache处理;apache版本为2.4.25,mod_php版本为7.1.2。

压测参数:并发请求参数为100,压测请求总数为10000,使用apachebench作为压测工具;压测指令为

ab -c 100 -n 10000 http://www.hereisurl.com

每个压测指令执行10次,取10次qps(requests per second)值的平均值作为最后的统计数据。

纯文本输出

php代码

<?php
   echo "<h1>this is a test</h1>";

数据库访问

php代码

<?php
  $host = "127.0.0.1";
  $port = 3306;
  $user = "root";
  $pswd = "root";
  $db = "dbBenchmark_test";
  $conn = new mysqli($host,$user,$pswd,$db);
  $sql = "select * from tbPersonInfo";
  $result = $conn->query($sql);
  while($row = $result->fetch_assoc()){
    echo $row["sName"]."-".$row["sPhone"]."\n";
  }
  $conn->close();

斐波那契数列计算

php代码

<?php
  function fibonacci_seq($n){
    if($n<1){
      return -1;
    }
    $ret = array();
    $ret[1]=$ret[2]=1;
    for($i=3;$i<=$n;$i++){
      $ret[$i]=$ret[$i-1]+$ret[$i-2];
    }
    return $ret[$n];
  }
  fibonacci_seq(100);

静态文件读取

静态文件内容:rtx.js,公司的某个产品组件,文件大小521KB

分析总结

在前三组动态请求php处理程序中,在纯文本输出的压测样例里,nginx+swoole和nginx+php-fpm比性能差别不大。在数据库访问和斐波那契数列计算中,加入了TCP访问mysql的操作和相对复杂的逻辑运算,压测结果表明nginx+swoole的性能要优于nginx+php-fpm。这是因为在swoole中,客户端连接请求,mysql访问都是异步处理,比阻塞的php-fpm要高效。

在上述三组动态请求中,实验结果表明nginx+swoole和nginx+php-fpm都要比apache+mod_php要高效。这主要是因为nginx服务器,swoole服务器在处理请求时都是异步非阻塞机制,相对而言apache的同步阻塞机制要低效许多。

最后一组测试——静态文件读取,非常明显的展示出在I/O操作方面,nginx比apache要高效很多,nginx性能是apache的2倍以上。nginx的采用事件通知机制实现了异步非阻塞的I/O模型,用户进程注册了事件监听之后马上返回,直到内核进程通知事件完成后用户进程再继续执行。

2017-03-24 18:00更新

补充下swoole异步mysql访问的php代码。

<?php
$http = new swoole_http_server('127.0.0.1',9501);
$http->on('request',function($request,$response){
 $db = new swoole_mysql;
 $server = array(
  "host"=>"127.0.0.1",
  "user"=>"root",
  "password"=>"root",
 "database"=>"dbBenchmark_test",
 "charset"=>"utf8"
);
$db->connect($server,function($db,$r) use ($response){
   if($r === false){
        var_dump($db->connect_errno, $db->connect_error);
        die;
   }
   $sql = "select * from tbPersonInfo";
   $db->query($sql,function(swoole_mysql $db,$result) use ($response){
        $ret_str =  $result[0]["sName"]."-".$result[0]["sPhone"]."\n";                 
        $db->close();
        //echo $ret_str;
        $response->end($ret_str);
   });
});     
});
$http->start();

该代码通过浏览器访问时没有问题,能够正常返回;但是在用ab压测时会出现报错:”WARNING swManager_check_exit_status: worker#0 abnormal exit, status=0, signal=11”,后续解决了会提供ab压测数据。如您有解决方案,也可留言提供。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

石仕海的专栏

1 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏做全栈攻城狮

C#实现动态网站伪静态,使seo更友好

本教程将使用Visual Studio 2013手把手教你实现webform动态页面的伪静态。本教程配套的C#源码工程可通过我的github下载。地址:http...

934
来自专栏CodeSheep的技术分享

Elastic Search搜索引擎在SpringBoot中的实践

1845
来自专栏jeremy的技术点滴

云服务器上ssh服务安全加固

6376
来自专栏杨建荣的学习笔记

服务器进程异常的原因分析(第二篇)(r8笔记第16天)

最近看到一个报警,是显示某一个oracle的备库进程数达到了2000多个。 ZABBIX-监控系统: ----------------------------...

3057
来自专栏大内老A

谈谈分布式事务之二:基于DTC的分布式事务管理模型[上篇]

通过上一篇的介绍,我们知道了SOA真正需要的是一个能够协调服务操作直接(通过服务自身访问的资源)或者间接(通过被调用服务访问的资源)访问的所有资源的分布式事务管...

1947
来自专栏大内老A

谈谈分布式事务之二:基于DTC的分布式事务管理模型[上篇]

通过上一篇的介绍,我们知道了SOA真正需要的是一个能够协调服务操作直接(通过服务自身访问的资源)或者间接(通过被调用服务访问的资源)访问的所有资源的分布式事务管...

1727
来自专栏Linuxer的专栏

LEP 与负载均衡:以 PCDUINO 实际案例来使用 LEP 提高网络带宽

本案例演示 LEP 观察到负载不均衡情况下,PCDUINO 电路板 iperf 测试网络带宽发挥不出来,并实施负载均衡后,看到 PCDUINO 网络带宽重大提高...

1220
来自专栏Seebug漏洞平台

Discuz!X ≤3.4 任意文件删除漏洞分析

Discuz!X社区软件,是一个采用 PHP 和 MySQL 等其他多种数据库构建的性能优异、功能全面、安全稳定的社区论坛平台。

4118
来自专栏pangguoming

Comet:基于 HTTP 长连接的“服务器推”技术

基于客户端套接口的“服务器推”技术 Flash XMLSocket 如果 Web 应用的用户接受应用只有在安装了 Flash 播放器才能正常运行, 那么使用 ...

4047
来自专栏信安之路

同源策略与跨域请求

做前端开发经常会碰到各种跨域问题,通常情况下,前端除了 iframe 、script 、link、img、svg 等有限的标签可以支持跨域外(这也与这些标签的用...

920

扫码关注云+社区