## php\-fpm是什么?
?
PHP5.3.3開始集成了php-fpm模塊,不再是第三方的包了。PHP\-FPM提供了更好的PHP[進程管理](https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86)方式,可以有效控制內存和進程、可以平滑\[重載\](https://baike.baidu.com/item/%E9%87%8D%E8%BD%BD)PHP配置。
?
重點:
?
> php-fpm是fastcgi的實現。
?
## php-fpm的運行模型?
?
> 多進程同步阻塞模式
?
php-fpm是一種master(主)/worker(子)多進程架構模型。
?
當PHP-FPM啟動時,會讀取配置文件,然后創建一個Master進程和若干個Worker進程(具體是幾個Worker進程是由php-fpm.conf中配置的個數決定)。Worker進程是由Master進程fork出來的。
?
**master進程主要負責CGI及PHP環境初始化、事件監聽、Worker進程狀態等等,worker進程負責處理php請求**。
?
master進程負責創建和管理woker進程,同時負責監聽listen連接,**master進程是多路復用的**;woker進程負責accept請求連接,同時處理請求,**一個woker進程可以處理多個請求**(**復用**,不需要每次都創建銷毀woker進程,而是達到處理一定請求數后銷毀重新fork創建worker進程),**但一個woker進程一次只能處理一個請求**。
?
https://img.kancloud.cn/41/ed/41ed99b258dd1703acd803c8de18db1f_640x226.png
## cgi,php-cgi,php-fpm,fastcgi的區別?
?
**cgi**
?
cgi是一個web server與cgi程序(這里可以理解為是php解釋器)之間進行數據傳輸的協議,保證了傳遞的是標準數據。(服務端和解釋器之間的數據傳輸協議)
?
***php-cgi**
?
php-cgi是php解釋器。他自己本身只能解析請求,返回結果,不會管理進程。php-fpm是調度管理php-cgi進程的程序。(php解釋器,由php-fpm調度)
?
***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\-fpm的管理對象是php\-cgi,他負責管理一個進程池,來處理來自Web服務器的請求。
?
對于php.ini文件的修改,php\-cgi進程是沒辦法平滑重啟的,有了php\-fpm后,就把平滑重啟成為了一種可能,php\-fpm對此的處理機制是新的worker用新的配置,已經存在的worker處理完手上的活就可以歇著了,通過這種機制來平滑過度的。
?
## php\-fpm如何完成平滑重啟?
?
修改php.ini之后,php\-cgi進程的確是沒辦法平滑重啟的。php\-fpm對此的處理機制是新的worker用新的配置,已經存在的worker處理完手上的活就可以歇著了,通過這種機制來平滑過度。
?
## php\-fpm和nginx的通信機制是怎么樣的?
?
看下nginx的配置文件:
Nginx中fastcgi_pass的配置:
?
~~~
location ~ .php$ {
root /home/wwwroot;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
#fastcgi_pass unix:/tmp/php-cgi.sock;
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\\.php)(/.+)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
?
?
~~~
?
因為nginx不能直接執行php,所以需要借用fastcgi模塊,和php\-fpm進行通信。有兩種方式;
?
**1. TCP**
**2. UNIX Domain Socket**
?
TCP是IP加端口,可以跨服務器;
?
而UNIX Domain Socket不經過網絡,只能用于Nginx跟PHP\-FPM都在同一服務器的場景。具體配置:
?
~~~
方式1:
php-fpm.conf: listen = 127.0.0.1:9000
nginx.conf: fastcgi_pass 127.0.0.1:9000;
方式2:
php-fpm.conf: listen = /tmp/php-fpm.sock
nginx.conf: fastcgi_pass unix:/tmp/php-fpm.sock;
?
~~~
?
值得一提的是,MySQ命令行客戶端連接mysqld服務也類似有這兩種方式:
使用Unix Socket連接(默認):
?
~~~
mysql -uroot -p --protocol=socket --socket=/tmp/mysql.sock
?
?
~~~
?
使用TCP連接:
?
~~~
mysql -uroot -p --protocol=tcp --host=127.0.0.1 --port=3306
~~~
## php-fpm在請求鏈路的體現,畫出來?
?
~~~
www.example.com
|
|
\\!/
Nginx
|
|
\\!/
路由到www.example.com/index.php
|
|
\\!/
加載nginx的fast-cgi模塊
|
|
\\!/
fast-cgi監聽127.0.0.1:9000地址
|
|
\\!/
www.example.com/index.php請求到達127.0.0.1:9000
|
|
\\!/
php-fpm 監聽127.0.0.1:9000
|
|
\\!/
php-fpm 接收到請求,啟用worker進程處理請求
|
|
\\!/
php-fpm 處理完請求,返回給nginx
|
|
\\!/
nginx將結果通過http返回給瀏覽器
?
~~~
?
## php-fpm有幾種工作模式?
?
PHP-FPM進程管理方式有動態(Dynamic)、靜態(Static)、按需分配(Ondemand)三種。
?
**動態**
?
會初始化創建一部分worker,在運行過程中,動態調整worker數量,最大worker數受pm.max_children和process.max
?
~~~
listen = 127.0.0.1:9001
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 6
?
?
~~~
?
1. 當空閑進程數小于min_spare_servers時,創建新的子進程,總子進程數小于等于pm.max_children,小于等于process.max
2. 當空閑進程數大于max_spare_servers,會殺死啟動時間最長的子進程
3. 如果子進程(idle狀態)數大于max_children,會打印warning日志,結束處理
4. process小于 max_children ,計算一個num,啟動num個worker
5. 優點:動態擴容,不浪費系統資源
6. 缺點:所有worker都在工作,新的請求到來需要等待創建worker進程,最長等待1s(內部存在一個1s的定時器,去查看,創建進程),頻繁啟停進程消耗cpu,請求數穩定,不需要頻繁銷毀
?
**靜態**
?
啟動固定大小數量的worker,也有1s的定時器,用于統計進程的一些狀態信息,例如空閑worker個數,活動worker個數
?
~~~
pm.max_children = 10 #必須配置這個參數,而且只有這個參數有效
?
?
~~~
?
1. 優點:不用動態判斷負載,提升性能
2. 缺點:如果配置成static,只需要考慮max_children數量,數量取決于cpu的個數和應用的響應時間,一次啟動固定大小進程浪費系統資源
?
**按需分配**
?
php-fpm啟動的時候不會啟動worker進程,按需啟動worker,有鏈接進來后,才會啟動
?
~~~
listen = 127.0.0.1:9001
pm = ondemand
pm.process_idle_timeout = 60
pm.max_children = 10
?
?
~~~
?
連接到來時(只有鏈接,不沒有數據也會創建,telnet也會創建),創建新worker進程,worker進程數的創建收max_children設置限制,也受限于全局的process.max設置(三種模式都受限此,下文中有全局配置項講解),如果空閑時間超過了process_idle_timeout的設置就會銷毀worker進程
?
* 優點:按流量需求創建,不浪費系統資源,
* 缺點:因為php-fpm是短連接的,如果每次請求都先建立連接,大流量場景下會使得master進程變得繁忙,浪費cpu,不適合大流量模式
* 不推薦使用此模式
?
| 工作模式 | 特點 |
| --- | --- |
| 動態 | 均衡優先,適合小內存服務器,2g左右 |
| 靜態 | 性能優先, 適合大內存機器 |
| 按需分配 | 內存優先,適合微小的內存,2g以下 |
?
## 怎么選定php-fpm的worker進程數?
?
* 動態建立進程個數
* N+20% 到 M/m之間
* N是cpu核數,M是內存,m是每個php進程內存數
* 靜態進程個數
* M/(m*1.2)
* pm.max_requests, 設置最大請求數,達到這個數量以后,會自動長期worker進程,繁殖內存意外增長
?
注意:PHP程序在執行完成后,或多或少會有內存泄露的問題。這也是為什么開始的時候一個php-fpm進程只占用3M左右內存,運行一段時間后就會上升到20-30M。所以需要每個worker進程處理完一定的請求后,銷毀重新創建。
?
cpu密集型的pm.max_children不能超過cpu內核數,但是web服務屬于IO密集型的,可以將pm.max_children的值設置大于cpu核數。
?
## php-fpm如何優化?
?
(1)避免程序跑死(hang)
?
在負載較高的服務器上定時重載php-fpm,reload可以平滑重啟而不影響生產系統的php腳本運行,每15分鐘reload一次,定時任務如下:
?
~~~
0-59/15 * * * * /usr/local/php/sbin/php-fpm reload
?
?
~~~
?
(2)合理增加單個worker進程最大處理請求數,減少內存消耗
?
最大處理請求數是指一個php-fpm的worker進程在處理多少個請求后就終止掉,master進程會重新respawn新的。該配置可以避免php解釋器自身或程序引起的memory leaks。默認值是500,可以修改為如下配置:
?
~~~
pm.max_requests = 1024
?
~~~
?
(3)開啟靜態模式,指定數量的php-fpm進程,減少內存消耗
- 消息隊列
- 為什么要用消息隊列
- 各種消息隊列產品的對比
- 消息隊列的優缺點
- 如何保證消息隊列的高可用
- 如何保證消息不丟失
- 如何保證消息不會重復消費?如何保證消息的冪等性?
- 如何保證消息消費的順序性?
- 基于MQ的分布式事務實現
- Beanstalk
- PHP
- 函數
- 基礎
- 基礎函數題
- OOP思想及原則
- MVC生命周期
- PHP7.X新特性
- PHP8新特性
- PHP垃圾回收機制
- php-fpm相關
- 高級
- 設計模式
- 排序算法
- 正則
- OOP代碼基礎
- PHP運行原理
- zavl
- 網絡協議new
- 一面
- TCP和UDP
- 常見狀態碼和代表的意義以及解決方式
- 網絡分層和各層有啥協議
- TCP
- http
- 二面
- TCP2
- DNS
- Mysql
- 鎖
- 索引
- 事務
- 高可用?高并發?集群?
- 其他
- 主從復制
- 主從復制數據延遲
- SQL的語?分類
- mysqlQuestions
- Redis
- redis-question
- redis為什么那么快
- redis的優缺點
- redis的數據類型和使用場景
- redis的數據持久化
- 過期策略和淘汰機制
- 緩存穿透、緩存擊穿、緩存雪崩
- redis的事務
- redis的主從復制
- redis集群架構的理解
- redis的事件模型
- redis的數據類型、編碼、數據結構
- Redis連接時的connect與pconnect的區別是什么?
- redis的分布式鎖
- 緩存一致性問題
- redis變慢的原因
- 集群情況下,節點較少時數據分布不均勻怎么辦?
- redis 和 memcached 的區別?
- 基本算法
- MysqlNew
- 索引new
- 事務new
- 鎖new
- 日志new
- 主從復制new
- 樹結構
- mysql其他問題
- 刪除
- 主從配置
- 五種IO模型
- Kafka
- Nginx
- trait
- genergtor 生成器
- 如何實現手機掃碼登錄功能
- laravel框架的生命周期