Swoole生命周期

PHP底層工作原理

PHP體系架構(gòu)

PHP的相關(guān)進(jìn)程是隨著Web服務(wù)器如Apache、Nginx等的啟動(dòng)而運(yùn)行的,這里以Apache為例簡(jiǎn)要梳理下流程:

PHP中客戶端和服務(wù)器的交互
  1. PHP通過mod_php.so擴(kuò)展和Apache建立聯(lián)系,具體來說是SAPI服務(wù)器應(yīng)用程序編程接口。

當(dāng)Apache服務(wù)器啟動(dòng)后,PHP解釋程序也隨之啟動(dòng),PHP啟動(dòng)的過程分為兩步:

  • 初始化環(huán)境變量,這些環(huán)境變量將在SAPI生命周期中發(fā)生作用。
    PHP解釋程序啟動(dòng)后,會(huì)調(diào)用各個(gè)擴(kuò)展的MINIT方法即“模塊初始化”,從而使擴(kuò)展切換到可用狀態(tài)。MINIT指的是,每個(gè)擴(kuò)展模塊都定義了一組函數(shù)、類庫等用于處理其它請(qǐng)求。
  • 生成只針對(duì)當(dāng)前請(qǐng)求的變量設(shè)置
    當(dāng)客戶端的請(qǐng)求發(fā)生時(shí),SAPI層將控制權(quán)交給PHP層。于是,PHP設(shè)置了用于回復(fù)本次請(qǐng)求所需的環(huán)境變量,用來存放執(zhí)行過程中產(chǎn)生的變量名和值。PHP調(diào)用各個(gè)擴(kuò)展模塊的RINIT方法即請(qǐng)求初始化。經(jīng)典的案例使Session模塊的RINIT方法,如果在php.ini中啟用了Session擴(kuò)展模塊,那么在調(diào)用該模塊的RINIT時(shí)就會(huì)初始化$_SESSION全局變量,并將相關(guān)內(nèi)容讀取。RINIT方法可看作是一個(gè)準(zhǔn)備過程,在程序執(zhí)行之間就會(huì)自動(dòng)啟動(dòng)。

如同PHP啟動(dòng)一樣,PHP的關(guān)閉也分為兩個(gè)步驟

  • 一旦腳本執(zhí)行完畢,無論是執(zhí)行到文件末尾還是使用exitdie函數(shù)中止。PHP都會(huì)啟動(dòng)清理程序,清理程序會(huì)按順序調(diào)用各個(gè)擴(kuò)展模塊的RSHUTDOWN方法,RSHUTDOWN方法用來清理程序運(yùn)行時(shí)產(chǎn)生的符號(hào)表,也就是對(duì)每個(gè)變量調(diào)用unset函數(shù)。
  • 當(dāng)所有的請(qǐng)求都處理完畢后,SAPI也準(zhǔn)備關(guān)閉了。此時(shí),PHP會(huì)調(diào)用每個(gè)擴(kuò)展模塊的MSHUTDOWN方法,這是各個(gè)擴(kuò)展模塊最后一次釋放內(nèi)存的機(jī)會(huì)。
  1. PHP中共有三個(gè)模塊:PHP內(nèi)核、Zend引擎、擴(kuò)展層
PHP核心
  • PHP內(nèi)核:用來處理請(qǐng)求、文件流、錯(cuò)誤處理等相關(guān)操作
  • Zend引擎:將PHP源文件轉(zhuǎn)換成機(jī)器語言,并在Zend虛擬機(jī)上運(yùn)行。
  • 擴(kuò)展層:是一組函數(shù)、類庫和流

PHP使用這個(gè)三個(gè)模塊來執(zhí)行特定的操作,如使用MySQL擴(kuò)展來連接MySQL數(shù)據(jù)。

  1. 當(dāng)Zend引擎執(zhí)行程序時(shí)可能會(huì)需要連接若干擴(kuò)展,此時(shí)Zend引擎會(huì)將控制權(quán)交給擴(kuò)展,等處理完特定任務(wù)后再返還。
  2. Zend引擎將運(yùn)行結(jié)果返回給PHP內(nèi)核,PHP內(nèi)核將結(jié)果傳遞給SAPI,最終通過Web服務(wù)器輸出到瀏覽器。

PHP腳本運(yùn)行流程

PHP作為Swoole的宿主,下圖是以CLI命令行下執(zhí)行一個(gè)PHP腳本文件時(shí)的完整流程:

PHP生命周期

SAPI是PHP給外部環(huán)境執(zhí)行PHP內(nèi)核提供的統(tǒng)一接口,常見有三種:CLI、PHP-FPM、MOD_PHP。

以PHP-FPM為例,將PHP運(yùn)行周期的關(guān)鍵步驟提?。?/p>

PHP-FPM
  1. 初始化
    PHP引擎初始化公用配置,讀取.ini配置文件,加載zend引擎。

  2. MINIT
    執(zhí)行PHP各個(gè)擴(kuò)展模塊的MINIT(模塊初始化)方法后,常駐在PHP-FPM進(jìn)程中,等待處理請(qǐng)求。

  3. RINIT
    當(dāng)請(qǐng)求過來后,調(diào)用PHP各個(gè)擴(kuò)展模塊的RINIT(請(qǐng)求初始化)方法進(jìn)行請(qǐng)求內(nèi)數(shù)據(jù)的初始化,如超全局變量和模塊數(shù)據(jù)的初始化等操作。

  4. 執(zhí)行PHP腳本
    加載PHP腳本文件,進(jìn)行詞法分析、語法分析、生成Opcode中間代碼,然后交給Zend虛擬機(jī),暫存執(zhí)行結(jié)果。


    解釋型語言PHP的執(zhí)行流程
  5. RSHUTDOWN
    在結(jié)果返回給PHP-FPM之前,會(huì)調(diào)用PHP各個(gè)擴(kuò)展模塊的RSHUTDOWN(請(qǐng)求關(guān)閉)方法進(jìn)行數(shù)據(jù)的回收,Zend虛擬機(jī)會(huì)關(guān)閉打開的數(shù)據(jù)流,進(jìn)行內(nèi)存釋放等操作,然后把暫存的執(zhí)行結(jié)果flush輸出。

  6. MSHUTDOWN
    當(dāng)重啟PHP-FPM時(shí)會(huì)調(diào)用PHP各個(gè)擴(kuò)展模塊的MSHUTDOWN(模塊關(guān)閉)方法,執(zhí)行關(guān)閉Zend引擎等操作。

通過以上流程可以發(fā)現(xiàn)PHP-FPM中每個(gè)請(qǐng)求都是在執(zhí)行第3~5步,Opcode緩存是將第4步的詞法分析、語法分析、生成Opcode中間代碼等幾個(gè)操作給緩存起來,從而達(dá)到加速的目的。

Opcode

既然每個(gè)請(qǐng)求都是獨(dú)立的,那么能不能進(jìn)行數(shù)據(jù)共享呢?由于在MINIT模塊初始化時(shí)數(shù)據(jù)是常駐在PHP-FPM進(jìn)程中的,所有是可以實(shí)現(xiàn)的,例如比較典型的.ini配置文件是放在這一步的。另外每個(gè)請(qǐng)求都能夠獨(dú)立釋放內(nèi)存,總體上是安全的,但也是有問題的,很有可能在擴(kuò)展層就存在內(nèi)存泄漏。所以PHP-FPM提供max_request來重啟PHP-FPM,達(dá)到完全釋放內(nèi)存的目的。

Swoole的生命周期

分析了PHP的基本執(zhí)行流程后,Swoole是在哪一步執(zhí)行的呢?首先,Swoole運(yùn)行有個(gè)前提條件:必須在CLI命令行模式下執(zhí)行。Swoole在PHP執(zhí)行流程的第4步執(zhí)行PHP腳本時(shí)就接管了PHP,進(jìn)入了Swoole的生命周期。

Swoole的生命周期以多進(jìn)程模式為例,具體流程如下:

Swoole執(zhí)行流程
  1. 初始化
    創(chuàng)建Manager管理進(jìn)程,創(chuàng)建Worker工作子進(jìn)程,監(jiān)聽所有TCP/UDP端口,監(jiān)聽定時(shí)器Timer。
  2. onStart
    onStart回調(diào)函數(shù)是在Master主進(jìn)程中執(zhí)行的,和Worker工作子進(jìn)程的onWorkStart是并行的,并沒有先后之分。在此回調(diào)函數(shù)中強(qiáng)烈要求只做Log記錄和進(jìn)程名設(shè)置操作,不要做業(yè)務(wù)邏輯。因?yàn)闃I(yè)務(wù)邏輯代碼的錯(cuò)誤將直接導(dǎo)致Master主進(jìn)程Crash崩潰,進(jìn)而讓整個(gè)Swoole服務(wù)器無法對(duì)外提供服務(wù)。
  3. onReceive
    客戶端請(qǐng)求的數(shù)據(jù)到達(dá)時(shí)會(huì)調(diào)用onReceive函數(shù),進(jìn)行業(yè)務(wù)邏輯處理輸出結(jié)果??蛻舳税l(fā)送的多次請(qǐng)求,服務(wù)端是可以一次性接收的,所以會(huì)發(fā)現(xiàn)一個(gè)問題是onReceive接收的數(shù)據(jù)會(huì)非常大。
  4. onWorkerStop
    Worker工作子進(jìn)程退出時(shí)回調(diào)onWorkerStop函數(shù)。
  5. onShutDown
    Swoole服務(wù)停止時(shí)回調(diào)onShutDown函數(shù),然后繼續(xù)PHP-FPM的第5~6步,最后退出PHP的生命周期。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考資料 官方網(wǎng)站 https://www.swoole.com/page/download PHP沒有像Pyth...
    JunChow520閱讀 3,087評(píng)論 0 6
  • 進(jìn)程 什么是進(jìn)程 進(jìn)程Process是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)分配資源和調(diào)度的基本單位...
    JunChow520閱讀 2,131評(píng)論 2 9
  • 前文再續(xù),就書接上一回,隨著與Server、TCP、Protocol的邂逅,Swoole終于迎來了自己的故事,今天...
    蝸牛淋雨閱讀 1,900評(píng)論 1 14
  • 原文github地址 1.PHP概述 1.1 PHP的歷史發(fā)展 1995年由Lerdorf創(chuàng)建PHP,高級(jí)腳本語言...
    10xjzheng閱讀 1,572評(píng)論 0 2
  • 并發(fā)IO問題一直是服務(wù)器端編程中的技術(shù)難題,從最早的同步阻塞直接Fork進(jìn)程,到Worker進(jìn)程池/線程池,到現(xiàn)在...
    零一間閱讀 1,792評(píng)論 1 34

友情鏈接更多精彩內(nèi)容