面试中,我们经常会被问到,PHP是怎么运行的,swoole为什么比nginx和php-fpm的组合效率高等等进程模式方向的内容。平时倒是多多少少有听过sapi,php-fpm,Master/Worker,但要是真回答起来,就开始模棱两可甚至概念都会有点模糊。因此特地整理总结了一下,也为大家理清一下思路。
Apache和LoadModule模式
Apache和LoadModule模式运行PHP应该是属于比较经典的了,小马初识PHP就是用的这个模式。是否还记得我们安装完apache和PHP后在 Apache的配置文件 httpd.conf中加上这样的配置:
# 加入以下2句
LoadModule php5_module E:/php/php5apache2_2.dllAddType application/x-httpd-php .php
# 修改如下内容<IfModule dir_module>
DirectoryIndex index.php index.html</IfModule>
所以,这种方式本质是用 LoadModule 来加载 php5_module,把php作为apache的一个子模块来运行。当通过web访问php文件时,apache就会调用php5_module来解析php代码。php5_module通过sapi将数据传给php解析器来解析php代码。如图。
apache调用php执行的过程如下:apache -> httpd -> php5_module(sapi) -> php
sapi(server api)其实就是一种协议,sapi提供了一个和外部通信的接口,使得PHP可以和其他应用(apache,nginx等)进行交互数据。常见的有如PHP提供给apache和nginx的php5_module、CGI、FastCGI,提供给IIS的ISAPI(记得小马曾经在.net团队中配置过IIS跑PHP),提供给Shell的CLI等协议。
Apache也有三种工作模式
每一个请求到达,apache都会去fork一个子进程来连接php通过sapi来处理请求,直到这个请求处理完毕,且apache处理请求是同步阻塞方式。一个客户端占用一个进程,所以进程的数量决定了并发处理的能力,对高并发并不是很友好。
Nginx和php-fpm组合
Nginx和php-fpm的组合是 Master主进程/Worker多进程模式,启动一个 Master 进程通过 FastCGI 协议监听来自 Nginx 传输的请求,再fork 多个Worker进程处理请求,但每个Worker进程只对应一个请求连接,用于执行完整的PHP代码。对于CGI来说,每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展,并重新初始化全部数据结构。而使用FastCGI,所有这些都只在进程启动时发生一次。
总结一下:进程模型apache与nginx两者的主要区别在于apache是同步多进程模型,一个连接对应一个进程;而nginx是异步的,多个连接可以对应一个进程(一个Master多个Worker)。(题外话:不过apache的rewrite比Nginx的rewrite强大。)
运行模式的“进化”所以,PHP WEB服务器目前最佳方式是Apache/Nginx + FastCGI + PHP-FPM(+PHP-CGI)不建议 Module加载或者CGI方式。
swoole进程模型
swoole是怎么做到那么优秀的呢?为什么就重新定义了PHP而使其能号称全宇宙最好的语言呢?我们看一下进程模型。
swoole也是Master主进程(由多个 Reactor 线程组成)和Worker多进程(或多线程)模式,不同的是,包含了Reactor 线程和Manager 进程的概念。
swoole进程模型启动一个Master进程,初始化PHP代码(仅在启动时执行一次初始化),因为 swoole 需要通过cli的方式运行,所以初始化时,不会初始化 PHP 的全局变量,如 $_SERVER, $_POST, $_GET 等;执行 PHP 脚本,包括词法、语法分析,变量、函数、类的初始化等,由Reactor线程监听 Socket 句柄的事件变化(Master进入监听状态,但并不会结束进程),Reactor线程负责子多线程的均衡问题,Manager 进程管理Worker多进程,包括 TaskWorker 的进程。每一个Worker进程接收来自Reactor的请求,只需要执行回调函数部分的PHP代码。
swoole进程 swoole运行流程图那么这个进程模式为什么能对性能加速呢?为什么能比传统的PHP运行模式高效呢?因为由Reactor线程(epoll的IO复用方式)负责监听Socket句柄的事件变化,负责子进程均衡问题,减少高并发下的资源开销。通过内存常驻的方式节省php代码初始化的时间。小马认为,其实主要还是协程的使用。
好了,整理就到这了,应该是比较清晰了。
网友评论