本篇文章給大家詳解介紹一下PHP-FMP。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)大家有所幫助。
什么是php-fpm
- 在了解php-fpm之前,請(qǐng)大家先思考一個(gè)問(wèn)題,一個(gè)用戶發(fā)起了一個(gè)web(niginx服務(wù)器)請(qǐng)求,在php代碼里面,那么我們?cè)趺礃硬趴梢酝ㄟ^(guò)
$_POST,$_GET,$_SERVER
獲取一些請(qǐng)求信息呢?我們應(yīng)該參照什么格式去組裝數(shù)據(jù)呢?
其實(shí)我們知道,每種動(dòng)態(tài)語(yǔ)言,也就是解釋性語(yǔ)言,都需要通過(guò)對(duì)應(yīng)的解析器才能被服務(wù)器(這里指web服務(wù)器)識(shí)別,但是解釋器和服務(wù)器 必須遵循某種協(xié)議,雙方才能夠正常通信,那么這種協(xié)議就是CGI協(xié)議,但是CGI的機(jī)制是每響應(yīng)一次web請(qǐng)求,都會(huì)創(chuàng)建和初始化一個(gè)新的處理進(jìn)程,請(qǐng)求結(jié)束就kill掉這個(gè)進(jìn)程。那每次請(qǐng)求,都要執(zhí)行這三步 創(chuàng)建->初始化->結(jié)束,那其實(shí)這個(gè)過(guò)程不僅浪費(fèi)了資源,而且效率也很低。那怎么辦?FastCGI應(yīng)時(shí)而生,作為CGI的改良版本,F(xiàn)astCGI會(huì)啟動(dòng)一個(gè)常駐服務(wù)進(jìn)程,這個(gè)進(jìn)程不需要管理生命周期,也就避免了進(jìn)程的重復(fù)的創(chuàng)建和結(jié)束,另一方面,不需要再重復(fù)的讀取環(huán)境變量,每當(dāng)有web請(qǐng)求過(guò)來(lái),由FastCGI管理器,也就那個(gè)常駐服務(wù)進(jìn)程去啟動(dòng)CGI解釋器進(jìn)程
- 好了,既然有了CGI,那么針對(duì)這些解釋性語(yǔ)言,比如php phython,都要根據(jù)自己的語(yǔ)言做一個(gè)適配吧。那么php官方就弄出來(lái)了PHP-CGI,php定制版的CGI。
- 但是隨著使用,大家發(fā)現(xiàn)了PHP-CGI的問(wèn)題
1.修改php.ini 后必須重啟PHP-CGI才可以生效,而不能實(shí)現(xiàn)平滑重啟 2.直接干掉PHP-CGI,php就不能運(yùn)行了,這顯然是不能接受的 3.這玩意不會(huì)自己管理進(jìn)程,它只能解析請(qǐng)求,返回結(jié)果
那么FastCGI都已經(jīng)到來(lái)了,php的FastCGI還會(huì)遠(yuǎn)嗎,當(dāng)然不會(huì),到 2004年一個(gè)叫 Andrei Nigmatulin的屌絲發(fā)明了PHP-FPM,PHP-FMP 全名叫做PHP-FASTCGI Process Manager,說(shuō)白了就是php定制版的FastCGI(這里強(qiáng)調(diào)一下,不管是PHP-CGI 還是 PHP-FPM都是為了實(shí)現(xiàn)CGI協(xié)議,而不是一種新的協(xié)議),其實(shí)有一句話剛才我沒(méi)說(shuō),網(wǎng)上很多人說(shuō)PHP-CGI 就是 php管理FAST-CGI的一種程序,那你現(xiàn)在知道了PHP-FMP 全名叫做PHP-FASTCGI Process Manager之后,你可以理直氣壯的跟他們說(shuō)no,并給他們普及一下這個(gè)知識(shí)點(diǎn)了。
php-fpm的進(jìn)程包括 master(常駐服務(wù)程序)和worker進(jìn)程兩種
master進(jìn)程
- master負(fù)責(zé)進(jìn)程的調(diào)度(比如worker進(jìn)程不夠的時(shí)候去fork一個(gè)子進(jìn)程)
- 負(fù)責(zé)監(jiān)聽(tīng)端口,一般是9000這個(gè)端口,可以在配置文件里面設(shè)置,當(dāng)然,還有另外一種方式,就是通過(guò)socket,可以通過(guò)
netstat -nap | grep master的進(jìn)程號(hào)
查看端口信息(9000端口其實(shí)就是tcp的通信方式,而socket是說(shuō)的unix socket,從效率上來(lái)說(shuō),unix socket顯然是最好的,因?yàn)樗沁M(jìn)程之間的通信,但是unix socket要保證是在一臺(tái)服務(wù)器,如果是不同機(jī)器之間的通信,還是要使用tcp通信)
- 接收來(lái)自服務(wù)器的請(qǐng)求
work進(jìn)度 看名字就知道了,就是真正的打工階級(jí),代碼真正執(zhí)行的地方
- 再來(lái)看看php-fmp和nignx是怎么通信的
以socker通信為栗子,nginx的conf文件里面,可以看到下面這段信息
location ~ [^/].php(/|$) { try_files $uri =404; fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_index index.php; include fastcgi.conf; }
相信這段信息大家都可以看明白,/tmp/php-cgi.sock 就是php和nginx聯(lián)系的橋梁,同時(shí)我們也看到了include fastcgi.conf
,我們來(lái)看一下
root@6d05153a8988:/usr/local/nginx/conf# cat fastcgi.conf fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; fastcgi_param PHP_ADMIN_VALUE "open_basedir=NULL";
我們看到了一些熟悉的,比如REMOTE_ADDR,REQUEST_URI,現(xiàn)在你應(yīng)該明白了,我們通過(guò)$_SERVER獲取到的信息就是這個(gè)配置文件里面指定的
我們?cè)賮?lái)看一下php-fmp的配置文件(請(qǐng)注意看里面的注釋,我不做解釋了)
root@6d05153a8988:/usr/local/php/etc# cat php-fpm.conf [global] pid = /usr/local/php/var/run/php-fpm.pid error_log = /usr/local/php/var/log/php-fpm.log log_level = notice [www] listen = /tmp/php-cgi.sock listen.backlog = -1 listen.allowed_clients = 127.0.0.1 listen.owner = www listen.group = www listen.mode = 0666 user = www group = www # 如何控制子進(jìn)程,選項(xiàng)有static和dynamic #區(qū)別: #如果dm設(shè)置為 static,那么其實(shí)只有pm.max_children這個(gè)參數(shù)生效。系統(tǒng)會(huì)開(kāi)#啟設(shè)置數(shù)量的php-fpm進(jìn)程。 #如果dm設(shè)置為 dynamic,那么pm.max_children參數(shù)失效,后面3個(gè)參數(shù)生效。 #系統(tǒng)會(huì)在php-fpm運(yùn)行開(kāi)始 的時(shí)候啟動(dòng)pm.start_servers個(gè)php-fpm進(jìn)程, #然后根據(jù)系統(tǒng)的需求動(dòng)態(tài)在pm.min_spare_servers和pm.max_spare_servers之#間調(diào)整php-fpm進(jìn)程數(shù)。 pm = dynamic # 靜態(tài)方式下開(kāi)啟的php-fpm進(jìn)程數(shù)量 pm.max_children = 20 # 動(dòng)態(tài)方式下的起始php-fpm進(jìn)程數(shù)量 pm.start_servers = 10 # 動(dòng)態(tài)方式下的最小php-fpm進(jìn)程數(shù) pm.min_spare_servers = 10 # 動(dòng)態(tài)方式下的最大php-fpm進(jìn)程數(shù)量 pm.max_spare_servers = 20 # php-fpm子進(jìn)程能處理的最大請(qǐng)求數(shù) pm.max_requests = 1024 pm.process_idle_timeout = 10s request_terminate_timeout = 100 request_slowlog_timeout = 0 slowlog = var/log/slow.log
- 關(guān)于php-fpm 的相關(guān)操作
INT, TERM QUIT 平滑終止 USR1 重新打開(kāi)日志文件 USR2 平滑重載所有worker進(jìn)程并重新載入配置和二進(jìn)制模塊
啟動(dòng): /usr/local/php/sbin/php-fpm
查看進(jìn)程數(shù): ps aux | grep -c php-fpm
查看mater進(jìn)程號(hào):ps aux|grep 'php-fpm: master'|grep -v grep|awk '{print $2}'
或者cat /usr/local/php/var/run/php-fpm.pid
# 強(qiáng)制關(guān)閉 pkill php-fpm kill -INT `cat /usr/local/php/var/run/php-fpm.pid` kill -INT [pid] # 平滑重啟 其實(shí)就是通過(guò)創(chuàng)建新的進(jìn)程使 php.ini 生效 kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid` kill -USR2 [pid]
小結(jié)
至此,php-fpm 算是說(shuō)完了,其實(shí)通過(guò)上面的解說(shuō),大家也會(huì)明白一個(gè)問(wèn)題,為什么lnmp 承受的并發(fā)比lamp高,除了nginx的高性能之外,php-fpm 是不是也是其中的一個(gè)原因呢?
推薦學(xué)習(xí):《PHP視頻教程》