首先搞清楚php-fpm與cgi的關系
- cgi
cgi是一個web server與cgi程序(這里可以理解為是php解釋器)之間進行數據傳輸的協議,保證了傳遞的是標准數據。
- php-cgi
php-cgi是php解釋器,就是上文提到的cgi程序。
- Fastcgi
Fastcgi是用來提高cgi程序(php-cgi)性能的方案/協議。
cgi程序的性能問題在哪呢?"PHP解析器會解析php.ini文件,初始化執行環境",就是這里了。標准的CGI對每個請求都會執行這些步驟,所以處理的時間會比較長。
Fastcgi會先啟一個master,解析配置文件,初始化執行環境,然后再啟動多個worker。當請求過來時,master會傳遞給一個worker,然后立即可以接受下一個請求。這樣就避免了重復勞動,效率自然提高。而且當worker不夠用時,master可以根據配置預先啟動幾個worker等着;當然空閑worker太多時,也會停掉一些,這樣就提高了性能,也節約了資源。這就是Fastcgi的對進程的管理。
- php-fpm
上文提到了Fastcgi只是一個方案或者協議,那么php-fpm就是這個實現了Fastcgi的程序,也就是說,上文所描述的進程分配和管理是FPM來做的。官方對FPM的解釋是 Fastcgi Process Manager(Fastcgi 進程管理器) 。
PHP對並發訪問的處理
- 進程和線程
PHP從代碼級別來講不支持多線程操作,不能像Java、C#等語言一樣可以編寫多線程代碼。但多線程和並發沒有直接關系,多線程只是代碼被運行時在同一時間同時執行多個線程任務,來提高服務器CPU的利用率,提高代碼效率。但php是可以多進程執行的,上文所述的FPM進程管理機制就是多進程單線程的,有效提高了並發訪問的響應效率。
- 簡單的web server + php-fpm 模式
1. 當客戶端發送一個請求時,web server會通過一個php-fpm進程(這里和下文所說指的fpm進程都是fpm開啟的worker進程,關於fpm的工作原理這里不再累述)去執行php代碼,php代碼的執行是單線程的。
2. 那么,當有多個客戶端同時發送請求時(並發),web server會通過php-fpm為每個請求開啟一個單獨進程去執行php代碼。
3. 請求執行過后,空閑的php-fpm進程被銷毀,內存得以釋放。
4. 但並發的問題在於,在某一時間,客戶端請求讓php-fpm進程數量達到了最大限制數,這個時候,新來的請求只能等待空閑的php-fpm進程來處理,這就是多進程同步阻塞模式的弊端,當然還有進程過多所帶來的內存占用問題。
高並發和多線程
“高並發和多線程”總是被一起提起,給人感覺兩者好像相等,實則 高並發 ≠ 多線程
多線程是完成任務的一種方法,高並發是系統運行的一種狀態,通過多線程有助於系統承受高並發狀態的實現。
高並發是一種系統運行過程中遇到的一種“短時間內遇到大量操作請求”的情況,主要發生在web系統集中大量訪問或者socket端口集中性收到大量請求(例如:12306的搶票情況;天貓雙十一活動)。該情況的發生會導致系統在這段時間內執行大量操作,例如對資源的請求,數據庫的操作等。如果高並發處理不好,不僅僅降低了用戶的體驗度(請求響應時間過長),同時可能導致系統宕機,嚴重的甚至導致OOM異常,系統停止工作等。如果要想系統能夠適應高並發狀態,則需要從各個方面進行系統優化,包括,硬件、網絡、系統架構、開發語言的選取、數據結構的運用、算法優化、數據庫優化……而多線程只是其中解決方法之一。
實現高並發需要考慮:
系統的架構設計,如何在架構層面減少不必要的處理(網絡請求,數據庫操作等)
網絡拓撲優化減少網絡請求時間、如何設計拓撲結構,分布式如何實現?
系統代碼級別的代碼優化,使用什么設計模式來進行工作?哪些類需要使用單例,哪些需要盡量減少new操作?
提高代碼層面的運行效率、如何選取合適的數據結構進行數據存取?如何設計合適的算法?
任務執行方式級別的同異步操作,在哪里使用同步,哪里使用異步?
JVM調優,是以server模式還是以clien模式運行,如何設置Heap、Stack、Eden的大小,如何選擇GC策略,控制Full GC的頻率?
數據庫優化減少查詢修改時間。數據庫的選取?數據庫引擎的選取?數據庫表結構的設計?數據庫索引、觸發器等設計?是否使用讀寫分離?還是需要考慮使用數據倉庫?
緩存數據庫的使用,如何選擇緩存數據庫?是Redis還是Memcache? 如何設計緩存機制?
數據通信問題,如何選擇通信方式?是使用TCP還是UDP,是使用長連接還是短連接?NIO還是BIO?netty、mina還是原生socket?
操作系統選取,是使用winserver還是Linux?或者Unix?
硬件配置?是8G內存還是32G,網卡10G還是1G?
……
……
以上的這些問題在高並發中都是必須要深入考慮的,就像木桶原理一樣,只要其中的某一方面沒有考慮到,都會造成系統瓶頸,影響整個系統的運行。而高並發問題不僅僅涉及面之廣,同時又要求有足夠的深度!!!
而多線程在這里只是在同/異步角度上解決高並發問題的其中的一個方法手段,是在同一時刻利用計算機閑置資源的一種方式。
多線程在解決高並發問題中所起到的作用就是使計算機的資源在每一時刻都能達到最大的利用率,不至於浪費計算機資源使其閑置。