php與nginx之間的通訊

Nginx是俄國人最先開發的Webserver,如今已經風靡全球,相信你們並不陌生。PHP也經過二十多年的發展來到了7系列版本,更加關注性能。這對搭檔在最近這些年,叱吒風雲,基本上LNMP成了當下的標配。但是,你用了這麼多年的Nginx+PHP的搭配,你真正知道他們之間是怎麼交互怎麼通訊的麼?做爲一道經常用來面試的考題,從過往經驗看,狀況並不樂觀。更多的同窗是知道PHP-FPM、知道FastCGI,但不曉得Nginx、PHP這對老搭檔具體的交互細節。那麼,今天咱們就來一塊兒學習一下,作一回認真的PHP工程師。php

前菜html

爲了講解的有理有據,咱們先來準備一個純淨精簡的Nginx+PHP環境,這裏咱們使用Docker拉取Centos最新版本環境,來快速經過編譯安裝方式搭建一個Nginx+PHP環境。(圖1,經過docker啓動一臺CentOS機器並進入)nginx

圖1,經過docker啓動一臺CentOS機器並進入

有了Linux環境,咱們來源碼編譯安裝Nginx、PHP,這個過程網絡裏有不少的教程,咱們就不細說了。固然你也能夠安裝lnmp一鍵安裝包來快速搭建。經過安裝nginx、php,咱們的Linux環境裏就有了今天的這兩位主角了。咱們稍加配置,讓Nginx能夠接收請求並轉發給PHP-FPM,咱們目標是輸出一個phpinfo()的信息。(圖2,phpinfo()的輸出內容)
圖2面試

咱們經過對Nginx新增Server配置實現了nginx與PHP的一次通訊,配置文件很是簡單,以下圖:(圖3,一份nginx server配置)
圖3,一份nginxdocker

有了上面的一個sample示例,咱們開始深刻Nginx與FastCGI協議。編程

主食後端

從上圖的Nginx配置中能夠注意到 fastcgi* 開頭的一些配置,以及引入的 fastcgi.conf 文件。其實在fastcgi.conf中,也是一堆fastcgi*的配置項,只是這些配置項相對不常變,一般單獨文件保管能夠在多處引用。(圖4,fastcgi.conf文件中的內容)
圖4,fastcgi.conf文件中的內容服務器

能夠看到在fastcgi.conf中,有不少的fastcgi_param配置,結合nginx server配置中的fastcgi_pass、fastcgi_index,一般咱們的同窗已經可以想到Nginx與PHP之間打交道就是用的FastCGI,但再深問FastCGI是什麼?它起到銜接Nginx、PHP的什麼做用?等等深刻的問題的時候,不少同窗就卡殼了。那麼,咱們就來一探究竟。網絡

CGI是通用網關協議,FastCGI則是一種常住進程的CGI模式程序。咱們所熟知的PHP-FPM的全稱是PHP FastCGI Process Manager,即PHP-FPM會經過用戶配置來管理一批FastCGI進程,例如在PHP-FPM管理下的某個FastCGI進程掛了,PHP-FPM會根據用戶配置來看是否要重啓補全,PHP-FPM更像是管理器,而真正銜接Nginx與PHP的則是FastCGI進程。(圖5,FastCGI在請求流中的位置)
圖5,FastCGI在請求流中的位置架構

如上圖所示,FastCGI的下游,是CGI-APP,在咱們的LNMP架構裏,這個CGI-APP就是PHP程序。而FastCGI的上游是Nginx,他們之間有一個通訊載體,即圖中的socket。在咱們上文圖3的配置文件中,fastcgi_pass所配置的內容,即是告訴Nginx你接收到用戶請求之後,你該往哪裏轉發,在咱們圖3中是轉發到本機的一個socket文件,這裏fastcgi_pass也常配置爲一個http接口地址(這個能夠在php-fpm.conf中配置)。而上圖5中的Pre-fork,則對應着咱們PHP-FPM的啓動,也就是在咱們啓動PHP-FPM時便會根據用戶配置啓動諸多FastCGI觸發器(FastCGI Wrapper)。

對FastCGI在Nginx+PHP的模式中的定位有了必定了解後,咱們再來了解下Nginx中爲什麼能寫不少fastcgi_*的配置項。這是由於Nginx的一個默認內置module實現了FastCGI的Client。關於Module ngx_http_fastcgi_module的詳細文檔能夠查看這裏: http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html 。咱們關心一下咱們圖4中的這些fastcgi_param都是些什麼吧,詳細描述見下圖。(圖6,nginx模塊中fastcgi_param的介紹)
圖6,nginx模塊中fastcgi_param的介紹

從圖6中能夠看到,fastcgi_param所聲明的內容,將會被傳遞給「FastCGI server」,那這裏指的就是fastcgi_pass所指向的server,也就是咱們Nginx+PHP模式下的PHP-FPM所管理的FastCGI進程,或者說是那個socket文件載體。這時,有的同窗會問:「爲何PHP-FPM管理的那些FastCGI進程要關心這些參數呢?」,好問題,咱們一塊兒想一想咱們作PHP應用開發時候有沒有用到 $_SERVER 這個全局變量,它裏面包含了不少服務器的信息,好比包含了用戶的IP地址。同窗們不想一想咱們的PHP身處socket文件以後,爲何能獲得遠端用戶的IP呢?聰明的同窗應該注意到圖4中的一個fastcgi_param配置 REMOTE_ADDR ,這不正是咱們在PHP中用 $_SERVER[‘REMOTE_ADDR’] 取到的用戶IP麼。的確,Nginx這個模塊裏fastcgi_param參數,就是考慮後端程序有時須要獲取Webserver外部的變量以及服務器狀況,那麼ngx_http_fastcgi_module就幫咱們作了這件事。真的是太感謝它啦!

那麼咱們已經說清了FastCGI是個什麼東東,而且它在Nginx+PHP中的定位。咱們回到前面提出的問題,「它起到銜接Nginx、PHP的什麼做用?」。

對PHP有必定了解的同窗,應該會知道PHP提供SAPI面向Webserver來提供擴展編程。可是這樣的方式意味着你要是自主研發一套Webserver,你就須要學習SAPI,而且在你的Webserver程序中實現它。這意味着你的Webserver與PHP產生了耦合。在互聯網的大趨勢下,通常你們都不喜歡看到耦合。譬如Nginx在最初研發時候也不是爲了和PHP組成黃金搭檔而研發的,相信早些年的Nginx後端程序多是其餘語言開發。那麼解決耦合的辦法,比較好的方式是有一套通用的規範,上下游都兼容它。那麼CGI協議便成了Nginx、PHP都願意接受的一種方式,而FastCGI常住進程的模式又讓上下游程序有了高併發的可能。那麼,FastCGI的做用是Nginx、PHP的接口載體,就像插座與插銷,讓流行的WebServer與「世界上最好的語言」有了合做的可能。

有了這些基礎背景知識與他們的原因,咱們就能夠觸類旁通的作更多有意思的事情。譬如我在前年曾實現了Java程序中按照FastCGI Client的方式(替代Nginx)與PHP-FPM通訊,實現Java項目+PHP的一種組合搭配,解決的問題是Java程序通常來講在代碼調整後須要編譯過程,而PHP能夠隨時調整代碼隨時生效,那麼讓Java做爲項目外殼,一些易變的代碼由PHP實現,在須要的時候Java程序經過FastCGI與PHP打交道就好。這套想法也是基於對Nginx+PHP交互模式的理解之上想到的。

網絡中也有一些藉助FastCGI的嘗試與實踐,譬如《Writing Hello World in FCGI with C++》這篇文章,用C++實現一個FastCGI的程序,外部依然是某款Webserver來處理HTTP請求,但具體功能則有C++來實現,他們的中間交互一樣適用的FastCGI。同窗們有興趣了也能夠作些Geek嘗試。(圖7,C++實現一個FastCGI程序)
圖7,C++實現一個FastCGI程序

甜品

經過本文的講解,咱們但願讓你們看到,Nginx+PHP的工程模式下,兩位主角分工明確,Nginx負責承載HTTP請求的響應與返回,以及超時控制記錄日誌等HTTP相關的功能,而PHP則負責處理具體請求要作的業務邏輯,它們倆的這種合做模式也是常見的分層架構設計中的一種,在它們各有專一面的同時,FastCGI又很好的將兩塊銜接,保障上下游通訊交互,這種經過某種協議或規範來銜接好上下游的模式,在咱們平常的PHP應用開發中也有這樣的思想落地,譬如咱們所開發的高性能API,具體的Client究竟是PC、APP仍是某個其餘程序,咱們不關心,而這些PC、APP、第三方程序也不關心咱們的PHP代碼實現,他們按照API的規範來請求作處理便可。同窗們是否是發現技術思想是能夠在各個環節融會貫通的,是否是很興奮?很刺激?哈,同窗們開心就好,祝你們在工做學習過程當中,能挖掘到更多的好知識,提高本身的同時造福身邊小夥伴!

做者: Pangee 連接:http://www.imooc.com/article/19278來源:慕課網本文原創發佈於慕課網 ,轉載請註明出處,謝謝合做!

相關文章
相關標籤/搜索