面試中,我們經常會被問到,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進程模型
每一個請求到達,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 進程的概念。
啟動一個Master進程,初始化PHP代碼(僅在啟動時執行一次初始化),因為 swoole 需要通過cli的方式運行,所以初始化時,不會初始化 PHP 的全局變量,如 $_SERVER, $_POST, $_GET 等;執行 PHP 腳本,包括詞法、語法分析,變量、函數、類的初始化等,由Reactor線程監聽 Socket 句柄的事件變化(Master進入監聽狀態,但並不會結束進程),Reactor線程負責子多線程的均衡問題,Manager 進程管理Worker多進程,包括 TaskWorker 的進程。每一個Worker進程接收來自Reactor的請求,只需要執行回調函數部分的PHP代碼。
那麼這個進程模式為什麼能對性能加速呢?為什麼能比傳統的PHP運行模式高效呢?因為由Reactor線程(epoll的IO復用方式)負責監聽Socket句柄的事件變化,負責子進程均衡問題,減少高並發下的資源開銷。通過內存常駐的方式節省php代碼初始化的時間。小馬認為,其實主要還是協程的使用。
好了,整理就到這了,應該是比較清晰了。