phpfpm多個
① qps 100 設置多少個php-fpm
qps100需要設置40個php-fpm。
工作中經常會遇到會給客戶配置伺服器,其中有的客戶還會有並發量要求,其中也會必須要用負載均衡承載壓力的。
增加伺服器數量肯定能有效的提升伺服器承載能力,但只有根據目前已有配置設置好單台伺服器才能更好的發揮出伺服器的性能。調整好一台伺服器後剩下的就更簡單了拿著快照復制n多台。
② 啟動php-fpm為什麼有啟動了多個進程
php-fpm的兩種進程管理模式 php-fpm的進程數也是可以根據設置分為動態和靜態的。 一種是直接開啟指定數量的php-fpm進程,不再增加或者減少; 另一種則是開始的時候開啟一定數量的php-fpm進程,當請求量變大的時候,動態的增加php-fpm進程數到上限,當空閑的時候自動釋放空閑的進程數到一個下限。 這兩種不同的執行方式,可以根據伺服器的實際需求來進行調整。 這里先說一下涉及到這個的幾個參數吧,他們分別是pm、pm.max_children、pm.start_servers、pm.min_spare_servers和pm.max_spare_servers。 pm表示使用那種方式,有兩個值可以選擇,就是static(靜態)或者dynamic(動態)。 在更老一些的版本中,dynamic被稱作apache-like。這個要注意看配置文件給出的說明了。PHP5.3 php-fpm的默認靜態處理方式會使得php-cgi的進程長期佔用內存而無法釋放,這也是導致nginx出錯的原因之 一,因此可以將php-fpm的處理方式改成apache模式。 下面4個參數的意思分別為: pm.max_children:靜態方式下開啟的php-fpm進程數量。 pm.start_servers:動態方式下的起始php-fpm進程數量。 pm.min_spare_servers:動態方式下的最小php-fpm進程數量。 pm.max_spare_servers:動態方式下的最大php-fpm進程數量。 如果dm設置為static,那麼其實只有pm.max_children這個參數生效。系統會開啟設置的數量個php-fpm進程。 如果dm設置為dynamic,那麼pm.max_children參數失效,後面3個參數生效。系統會在php-fpm運行開始的時候啟動 pm.start_servers個php-fpm進程,然後根據系統的需求動態在pm.min_spare_servers和 pm.max_spare_servers之間調整php-fpm進程數。 那麼,對於我們的伺服器,選擇哪種執行方式比較好呢?事實上,跟Apache一樣,我們運行的PHP程序在執行完成後,或多或少會有內存泄露的問題。 這也是為什麼開始的時候一個php-fpm進程只佔用3M左右內存,運行一段時間後就會上升到20-30M的原因了。所以,動態方式因為會結束掉多餘的進程,可以回收釋放一些內存,所以推薦在內存較少的伺服器或者VPS上使用。具體最大數量根據 內存/20M 得到。比如說512M的VPS,建議pm.max_spare_servers設置為20。至於pm.min_spare_servers,則建議根據伺服器的負載情況來設置,比較合適的值在5~10之間。 然後對於比較大內存的伺服器來說,設置為靜態的話會提高效率。因為頻繁開關php-fpm進程也會有時滯,所以內存夠大的情況下開靜態效果會更好。數量也可以根據內存/30M 得到。比如說2GB內存的伺服器,可以設置為50;4GB內存可以設置為100等。
③ php-fpm的工作機制
概括來說,fpm 的實現就是創建一個 master 進程,在 master 進程中創建並監聽 socket,然後 fork 出多個子進程,這些子進程各自 accept 請求,子進程的處理非常簡單,它在啟動後阻塞在 accept 上,有請求到達後開始讀取請求數據,讀取完成後開始處理然後再返回,在這期間是不會接收其它請求的,也就是說 fpm 的子進程同時只能響應一個請求,只有把這個請求處理完成後才會 accept 下一個請求,這一點與 nginx 的事件驅動有很大的區別,nginx 的子進程通過 epoll 管理套接字,如果一個請求數據還未發送完成則會處理下一個請求,即一個進程會同時連接多個請求,它是非阻塞的模型,只處理活躍的套接字。
fpm 的 master 進程與 worker 進程之間不會直接進行通信,master 通過共享內存獲取 worker 進程的信息,比如 worker 進程當前狀態、已處理請求數等,當 master 進程要殺掉一個 worker 進程時則通過發送信號的方式通知 worker 進程。
fpm 可以同時監聽多個埠,每個埠對應一個 worker pool,而每個 pool 下對應多個 worker 進程,類似 nginx 中 server 概念。
在 php-fpm.conf 中通過[pool name]聲明一個 worker pool:
啟動 fpm 後查看進程:
具體實現上 worker pool 通過fpm_worker_pool_s這個結構表示,多個 worker pool 組成一個單鏈表
接下來看下 fpm 的啟動流程,從main()函數開始:
fpm_init()主要有以下幾個關鍵操作:
(1) fpm_conf_init_main():
解析 php-fpm.conf 配置文件,分配 worker pool 內存結構並保存到全局變數中:fpm_worker_all_pools,各 worker pool 配置解析到fpm_worker_pool_s->config中。
(2)fpm_scoreboard_init_main():
分配用於記錄 worker 進程運行信息的共享內存,按照 worker pool 的最大 worker 進程數分配,每個 worker pool 分配一個fpm_scoreboard_s結構,pool 下對應的每個 worker 進程分配一個fpm_scoreboard_proc_s結構。
(3)fpm_signals_init_main():
這里會通過socketpair()創建一個管道,這個管道並不是用於 master 與 worker 進程通信的,它只在 master 進程中使用,具體用途在稍後介紹 event 事件處理時再作說明。另外設置 master 的信號處理 handler,當 master 收到 SIGTERM、SIGINT、SIGUSR1、SIGUSR2、SIGCHLD、SIGQUIT 這些信號時將調用sig_handler()處理:
(4)fpm_sockets_init_main()
創建每個 worker pool 的 socket 套接字。
(5)fpm_event_init_main():
啟動 master 的事件管理,fpm 實現了一個事件管理器用於管理 IO、定時事件,其中 IO 事件通過 kqueue、epoll、poll、select 等管理,定時事件就是定時器,一定時間後觸發某個事件。
在fpm_init()初始化完成後接下來就是最關鍵的fpm_run()操作了,此環節將 fork 子進程,啟動進程管理器,另外 master 進程將不會再返回,只有各 worker 進程會返回,也就是說fpm_run()之後的操作均是 worker 進程的。
在 fork 後 worker 進程返回了監聽的套接字繼續 main() 後面的處理,而 master 將永遠阻塞在fpm_event_loop(),接下來分別介紹 master、worker 進程的後續操作。
fpm_run()執行後將 fork 出 worker 進程,worker 進程返回main()中繼續向下執行,後面的流程就是 worker 進程不斷 accept 請求,然後執行 PHP 腳本並返回。整體流程如下:
worker 進程一次請求的處理被劃分為 5 個階段:
worker 處理到各個階段時將會把當前階段更新到fpm_scoreboard_proc_s->request_stage,master 進程正是通過這個標識判斷 worker 進程是否空閑的。
接下來我們來看下 master 是如何管理 worker 進程的,首先介紹下三種不同的進程管理方式:
前面介紹到在fpm_run()中 master 進程將進入fpm_event_loop():
這就是 master 整體的處理,其進程管理主要依賴注冊的幾個事件,接下來我們詳細分析下這幾個事件的功能。
(1)sp[1]管道可讀事件:
在 fpm_init() 階段 master 曾創建了一個全雙工的管道:sp,然後在這里創建了一個 sp[0] 可讀的事件,當 sp[0] 可讀時將交由 fpm_got_signal() 處理,向 sp[1] 寫數據時 sp[0] 才會可讀,那麼什麼時機會向 sp[1] 寫數據呢?前面已經提到了:當 master 收到注冊的那幾種信號時會寫入 sp[1] 端,這個時候將觸發 sp[0] 可讀事件。
這個事件是 master 用於處理信號的,我們根據 master 注冊的信號逐個看下不同用途:
具體處理邏輯在 fpm_got_signal() 函數中,這里不再羅列。
(2)fpm_pctl_perform_idle_server_maintenance_heartbeat():
這是進程管理實現的主要事件,master 啟動了一個定時器,每隔 1s 觸發一次,主要用於 dynamic、ondemand 模式下的 worker 管理,master 會定時檢查各 worker pool 的 worker 進程數,通過此定時器實現 worker 數量的控制,處理邏輯如下:
(3)fpm_pctl_heartbeat():
這個事件是用於限制 worker 處理單個請求最大耗時的,php-fpm.conf 中有一個request_terminate_timeout的配置項,如果 worker 處理一個請求的總時長超過了這個值那麼 master 將會向此 worker 進程發送kill -TERM信號殺掉 worker 進程,此配置單位為秒,默認值為 0 表示關閉此機制,另外 fpm 列印的 slow log 也是在這里完成的。
除了上面這幾個事件外還有一個沒有提到,那就是 ondemand 模式下 master 監聽的新請求到達的事件,因為 ondemand 模式下 fpm 啟動時是不會預創建 worker 的,有請求時才會生成子進程,所以請求到達時需要通知 master 進程,這個事件是在fpm_children_create_initial()時注冊的,事件處理函數為fpm_pctl_on_socket_accept(),具體邏輯這里不再展開,比較容易理解。
原文出處: https://www.fanhao.com/2017/10/internal-php-fpm.html
④ 如何修改 php-fpm的運行用戶
第一種:一個php-fpm主進程
這種方式比較簡單,也只需要一個php-fpm自啟動文件。
首先我們查看一下原php-fpm.conf的這個配置文件,分為兩個部分,一個是global塊,另外一個是自定義的塊,配置文件裡面稱為pool池,默認叫「www」。在global池的上方,有一行注釋了的「include=etc/fpm.d/*.conf」配置項,再通過www池的配置,我們可知可以通過不同的池來配置不同的用戶,來達到多個用戶運行php-fpm的目的,步驟如下:
4、刪除前面的global塊,或者注釋掉。
5、修改[www]為其他,比如你[blog]。
6、配置[blog]池,主要修改兩個地方:
6.1:第一處為運行的用戶和用戶組。
即將
12user = www3group = www4。
修改為
12user=nobody #具體用哪個用戶視自己情況而定,我只做個示例3group=nobody4。
6.2:修改監聽的埠或者socket:
即將:
12listen = 127.0.0.1:90003。
修改為:
12listen = /var/socket/php-fpm/blog.socket #php-fpm需要自己創建,當然也可以直接放在php-fpm目錄下3。
修改成其他埠也是可以的,比如:listen = 127.0.0.1:9001。
7、到主配置文件 php-fpm.conf將「include=…」前面的注釋去掉,讓它去讀取fpm.d目錄下的配置文件。
8、到此第一種方案就修改完畢了,重新啟動測試一下:
12service php-fpm reload3。
第二種:兩個php-fpm主進程。
這種方法需要獨立的配置文件和獨立的自啟動文件:
1、復制一份php-fpm.conf主配置文件。
12cp php-fpm.conf php-fpm-blog.conf3。
2、修改主配置文件。
12vim php-fpm-blog.conf3。
2.1:修改[global]下pid和error_log文件的路徑。
修改 pid=run/php-fpm.pid 為 pid=run/php-fpm-blog.pid 。
修改 error_log = /log/php-fpm.log 為 error_log = /log/php-fpm-blog.log。
2.2:修改池的名稱[www]為[blog],不過這個可以不用修改了,因為這里和原來的進程是獨立的。
2.3:修改用戶和用戶組。
2.4:監聽埠或socket文件。
以上兩部可以按照第一種方案進行修改,這里就不再重復。
3、進入/etc/init.d目錄,復制一份自啟動文件。
12cp php-fpm php-fpm23。
4、修改自啟動文件php-fpm2:
4.1:修改配置文件路徑。
12php_fpm-CONF=${prefix}/etc/php-fpm.conf3。
為
12php_fpm-CONF=${prefix}/etc/php-fpm-blog.conf3。
這個路徑就是剛才的主配置文件。
4.2:修改PID文件路徑:
12php_fpm_PID=${prefix}/var/run/php-fpm.pid3。
為:
12php_fpm_PID=${prefix}/var/run/php-fpm-blog.pid3。
這個路徑要和主配置文件中的pid路徑一致。
5、修改完畢後添加自動啟動。
12chkconfig --add php-fpm23chkconfig --level 2345 php-fpm2 on4。
6、啟動服務。