WebService之nginx+(php-fpm)結構模型剖析及優化

  隨着php腳本語言使用的普及,目前webserice服務大部分都在用nginx+(php-fpm)的結構,瞭解了其工做過程後才能夠在各個方面想辦法作調整優化和故障排查,從如下幾點總結一下這種模型。php


1、nginxphp-fpm的關係和分工html

nginxweb服務器,php-fpm是一個PHPFastCGI進程管理器,二者遵循fastcgi的協議進行通訊,nginx負責靜態相似html文件的處理,php-fpm負責php腳本語言的執行,這麼設計的目的是爲了解耦前端nginx和後端的php,不至於讓容易出問題的php腳本堵塞整個nginx的業務處理,影響用戶體驗,由於php腳本語言的執行是會比較容易出問題的。nginx之因此能處理成千上萬高併發業務,除其自己的異步非阻塞模式,在與和其餘模塊的耦合擴展方法也是分不開的,在nginx的設計裏不能接受的就是阻塞,不過並不是徹底沒有梗,好比說用到的最多的多進程單線程的模式,因爲nginx日誌沒有單獨的處理進程,若是收集日誌時處理不當就會把worker進程堵死。前端

  對應nginx+php-fpm的模型結構圖以下:nginx


wKioL1fOU-fiLC8nAAEc-FGrRjo932.png

(圖 1)web


一、nginx的工做簡介(對應圖1看)後端

在接到php的腳本請求後,nginx經過fastcgi_pass指令將請求傳遞給後端php-fpmworker進程處理,在此過程當中,nginx作了各類超時機制、緩存機制、buffer機制和長鏈接機制等來保障與後端的php-fpm可以良性高效的合做。瀏覽器

在超時機制方面控制nginx對後端php的等待時間,經過各類timeout指令進行控制,例如:緩存

fastcgi_connect_timeout   後端連接時間服務器

fastcgi_send_timeout    數據發送時間,兩次成功發送時間差,不是整個發送時間網絡

fastcgi_read_timeout    數據接收時間,兩次成功接收時間差,不是整個接收時間

  當超時後會返回504超時的狀態碼,在buffer機制指令也有不少,例如:

fastcgi_buffer_size 存放fastcgi傳過來的響應頭,通常設置爲分頁大小

fastcgi_buffers 存放fastcgi傳過來的相應內容,通常設置分頁的倍數,格式例如 8  4k|8k

  另外還有一些其它的緩存、長鏈接機制不作介紹,當設置不合理時也會出現5XX錯誤,nginx的文章介紹寫了有不少的,再也不作過多的說明。

 

二、php-fpm工做介紹(對應圖1看)

Php-fpm是一個PHPfastcgi進程管理器,在啓動後會有masterworker兩種進程,master負責接收外部信號和管理worker進程,worker進程是負責幹活的,處理nginx傳過來的任務。

master進程只有一個,負責監聽端口和管理worker進程,每次傳來任務,與前端的nginx創建3次握手後放入鏈接隊列,供worker進程進行accept,當worker進程出現錯誤或執行超時時,負責將worker進程重啓或者殺掉,是php-fpm模型中的大內總管。

Worker進程是工做進程,每一個worker進程都獨立的執行php程序腳本,而後把執行的結果經過fastcgi協議交給nginx,執行過程當中受master的管理。在工做中,worker進程去競爭accept管理進程master的連接隊列,accept函數將從鏈接請求隊列中得到鏈接信息,建立新的socket,並返回該套接字的fd,新建立的socket用於服務器與nginx的通訊,而原來的套接字仍然處於監聽狀態。

php-fpm能夠配置多個pool,全部poolmaster統一管理監聽不一樣端口並分配不一樣worker進程池,worker進程池支持動態prefork同時也支持靜態開啓,服務器內存較大時建議直接計算後配置靜態資源池,能夠減小頻繁prefork進程所帶來的開銷,提升服務質量,因爲進程模型越跑程序耗費越大,由於每一個worker進程能夠配置執行多少個請求後進行重啓,對應的池子的指令和執行多少個請求的指令以下:

pm = static | dynamic | ondemand 靜態池、服務優先、內存優先

pm.max_children = 256  開啓的最大php進程數

pm.max_requests = 1024   在執行了1024個請求後重啓worker進程

   這也是咱們線上服務器的配置,咱們線上用的web服務的機器是12cpu12G內存,nginx開啓12worker進程,php開啓256個進程,跑起來後每一個進程大概佔用30M內存,也就是(256+12*30=8G ,另外還跑了一些配管、監控、統計、日誌收集等七七八八的軟件,總體業務是比較輕鬆的,這種靜態池的配置大大減小了prefork進程帶來的開銷,RT時間100ms之內的佔到90%以上(這個與程序寫的如何有關),運行一段時間後的開銷截圖以下:


wKiom1fOVyGwRrByAAB0HEoKVdw112.png

 


2、此模型結構常見的5XX服務器端錯誤及優化(對應圖1看) 


一、nginx日誌裏產生502錯誤

  第一種狀況,php-fpm的worker進程執行php程序腳本時,超過了配置的最長執行時間,master進程將worker進程殺掉,直接返回502

返回502nginx對應的error日誌是104: Connection reset by peer

對應的php執行時間的配置以下,一些版本中php-fpm的配置會覆蓋php.ini的配置,使php.ini的配置不起做用:

php.ini中默認30smax_execution_time =

php-fpm中:request_terminate_timeout =

  第二種狀況,鏈接請求數(accpet以前)超出了端口所能監聽的tcp鏈接的最大值(backlog的值),進不了fpm等待accept的連接隊列,直接返回502,這裏可能會產生tcp重傳;

返回502nginx對應的error日誌是111: Connection refused

   backlog的值是半鏈接和全鏈接的總和,他的存在也有短期緩衝解耦nginx請求與fpm處理的做用,半鏈接指收到了syn請求,3次握手還沒有創建,全鏈接指的是3次握手已經成功,不過還沒有被accpet的請求,fpm裏面有調節的參數,若是fpm的參數設置爲-1,則默認走的是系統內核參數net.core.somaxconn的設置值,若是不設置能夠在/proc/sys/net/core/somaxconn裏查看,默認值是128,因此在鏈接請求較高的業務裏要增大這個值。

  第三種狀況,網絡卡時,客戶端斷開鏈接,nginx處顯示499,而後php檢查到前端nginx產生abort後,又master結束此條任務的繼而產生502,通常此種狀況的報警,先是499,過會兒變成502,再過一會變成504.

 

  • 減小避免502報錯優化建議

502主要從php-fpm的配置方考慮,根據服務器狀況,適量增大php-fpm的工做進程數,適當增長php的執行時間,適當增長backlog

php的工做進程數也不是越大越好,這種進程模型運行時間長了佔的內存會增大,通常一個php進程是佔到30M左右的內存,開多少合適本身算吧,nginxworker進程通常也能跑到30M的內存,綜合計算一下;php的執行時間能夠根據你的服務標準來設定,超過服務時間瀏覽器返回的是502錯誤,這個按照實際的狀況處理吧,通常狀況要設置超時時間,避免某些請求慢,將整個業務堵死;至於backlog值,當程序寫的比較好時,建議設置其數量爲php工做進程的12倍。

  

二、nginx日誌裏產生504錯誤

  第一種狀況,phpworker進程池處理慢,沒法儘快處理等待accept的連接隊列,致使3次握手後的連接隊列長時間沒有被acceptnginx連接等待超時;

返回504nginx對應的error日誌是110: Connection timed out

  第二種狀況,後端php-fpm執行腳本的時間太長,超過了nginx配置的超時機制,這個時候也是會報出504錯誤的。

  第三種狀況,客戶端的網絡及其差,php將請求處理完交給nginx後,nginx沒能在超時時間內將內容所有吐給用戶,這時也會超時,只有504而沒有502。

  • 減小避免504報錯的優化建議

504主要從nginx的配置方考慮,根據業務狀況配置好超時的各類機制,包含但不限於下屬參數:

fastcgi_connect_timeout

fastcgi_send_timeout 

fastcgi_read_timeout 

。。。。。。。。


另外:在配置過程當中,好比遇到大併發或者是特殊業務的場景,不合理的fd、buffer等設置也會帶來5XX錯誤,好比說大併發鏈接的業務要增大系統和單個程序的fd數量,若是是上傳業務要增大頭buffer等,這些要視狀況而作優化,正所謂道法天然,術變萬千,要以不變應萬變。

自建我的原創站運維網咖社(www.net-add.com),新的博文會在網咖社更新,歡迎瀏覽

相關文章
相關標籤/搜索