php-fpm與mysql長連接


總結:php-fpm在整個進程的生命周期中會把所有長連接的鏈接句柄緩存到進程中,在每個請求進來時都會復用

轉載自:http://blog.csdn.net/twg17865933200/article/details/52672826


之前在寫博文關於學習PHPde 幾點思考遺留了一個數據庫連接的疑問,疑問解決了,新oJ也上線運行一個多月了,今天整理出來記錄一下。

其實是利用PHP-fpm的工作方式配合MySQL配置一下實現了一個偽連接池。

首先明白一下php語言的架構和php生命周期。

SAPI接口

SAPI: Server abstraction API,它提供了一個接口,使得PHP可以和其他應用進行交互數據。 

看圖很清楚就可以理解,sapi以上是使用php的各種方式mod_php,fastcgi,cli等等,sapi以下是php語言,我們使用php一切的開始就從sapi開始。

php開始階段 (分兩個階段)

第一階段:是在我們啟動php-fpm,或者apache的時候是在所有請求到達之前進行的,且只進行一次。啟動Apache或者php-fpm后,PHP解釋程序也隨之啟動; PHP調用各個擴展(模塊)的MINIT方法,從而使這些擴展切換到可用狀態。看看php.ini文件里打開了哪些擴展吧; MINIT的意思是“模塊初始化”。各個模塊都定義了一組函數、類庫等用以處理其他請求。 模塊在這個階段可以進行一些初始化工作,例如注冊常量, 定義模塊使用的類等等.

第二階段:是在請求發生階段,當一個頁面請求發生時.則在每次請求之前都會進行初始化過程(RINIT請求開始).請求到達之后,SAPI層將控制權交給PHP層,PHP初始化本次請求執行腳本所需的環境變量,例如創建一個執行環境,包括保存php運行過程中變量名稱和變量值內容的符號表. 以及當前所有的函數以及類等信息的符號表.例如是Session模塊的RINIT,如果在php.ini中啟用了Session 模塊,那在調用該模塊的RINIT時就會初始化$_SESSION變量,並將相關內容讀入; 然后PHP會調用所有模塊RINIT函數,即“請求初始化”。 在這個階段各個模塊也可以執行一些相關的操作, 模塊的RINIT函數和MINIT函數類似 ,RINIT方法可以看作是一個准備過程,在程序執行之前就會自動執行。

php結束階段(分兩個階段)

第一階段:請求結束,請求處理完后就進入了結束階段,PHP就會啟動清理程序。它會按順序調用各個模塊的RSHUTDOWN方法。 RSHUTDOWN用以清除程序運行時產生的符號表,也就是對每個變量調用unset函數。

第二階段:SAPI關閉,比如php-fpm銷毀一個子進程。php調用每個擴展的MSHUTDOWN方法,這是各個模塊最后一次釋放內存的機會。

單進程SAPI生命周期


多進程SAPI生命周期


單進程圖可以對映我們在命令行執行php腳本,MINT,RINT執行后執行我們的腳本代碼,然后執行RSHUTDOWN,MSHUTDOWN就結束了。 
多進程圖可以對映php-fpm的方式,一個進程MINT后,循環執行RINT,RSHUTDOWN,循環處理很多請求直到該進程要銷毀執行MINT,然后結束。

數據庫長連接(偽連接池)

在上面講php結束階段的時候我們知道php在執行RSHUTDOWN的時候會釋放所有處理本次請求的資源,如申請的變量。那么理所當然的是我們打開的數據庫連接句柄也會被釋放,但是這只限於我們打開連接的時候使用的是短鏈接,看官方文檔我們可知道如果你打開的是長連接,在請求處理完后php會收留在本次打開的連接(即使你主動關閉也不會關閉而被收留),在下次有打開相同連接的請求時php會把收留的句柄直接給出去,就免去了建立連接的過程效率更高。這個收留的域是MINT,MSHUTDOWN之間也就對應我們php-fpm的一個子進程存活期。好了,現在我們想,php-fpm子進程數固定,一個子進程收留一個連接(假設打開的都是同一個數據庫)給這個進程處理的所有頁面用,那么我數據庫連接的數量就應該和我php-fpm子進程的數量一樣無論我們處理多少個頁面,這樣效果就和一個連接池差不多了。 
這樣配置php-fpm子進程數實現的偽連接池也要配合數據庫的一些配置才好使,比如數據庫允許連接數要大於php-fpm子進程數,如mysq再配置一下wait_timeout 和interactive_timeout控制連接時長當一個連接很長時間沒活動的時候mysql就關閉它,php活動時這邊會重新建立新連接。這樣避免時間長了mysql有一大堆不活動的連接。

另外有人會有這樣的疑問,我們知道一個php-fpm子進程處理請求是阻塞的,一個進程瞬間也就處理一個請求,那么同時我處理的請求數就應該是我php-fpm子進程數,那這樣我用短鏈接打開用完后關閉,那同時我活動的連接數也應該是和我php-fpm子進程的數量相同啊,那為什么在很多人訪問的時候我mysql會報too many connection?這個應該真的是應該和項目代碼有關了,短連接,長鏈接主要省的是建立鏈接關閉鏈接過程的消耗。

參考連接: 
深入理解Zend SAPIs(Zend SAPI Internals) 
http://www.laruence.com/2008/08/12/180.html 
深入理解php底層:php生命周期 
http://blog.csdn.net/hguisu/article/details/7377520#comments 
數據庫持久鏈接 
http://php.net/manual/zh/features.persistent-connections.php

 

轉載自:http://www.liuxos.com/post/56/php-fpm%E4%B8%8Emysql%E9%95%BF%E8%BF%9E%E6%8E%A5.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM