共享APC或OPcache:為什麼多個PHP-FPM主機更好
您可能不知道APC或OPcache實際上是由PHP中的主程序持有的。APC的任何配置都需要來自.INI配置,以後不能通過ini_set() 或php_admin_value覆蓋 。這是因為生成的PHP-FPM程序對APC快取的大小或配置沒有影響,因為它由主程序啟動和管理。
這本質上意味著APC / OPcache快取在所有PHP-FPM池之間共享。如果您只有一個網站可供服務,那就沒問題了。如果您通過PHP-FPM在同一臺伺服器上有幾十個站點,您應該知道它們都共享相同的APC / OPcache快取。然後,APC或OPcache大小應該足夠大,以儲存所有站點的操作碼快取。
為避免這種情況,每個PHP-FPM池也可以單獨啟動並擁有自己的主程序。這意味著每個站點都可以擁有自己的APC或OPcache,並且可以獨立於所有其他PHP-FPM池啟動/停止。當需要啟用新配置時,一個池配置的更改不會導致重新載入所有其他FPM池,這是“/etc/init.d/php-fpm reload”的預設行為(它將重新載入所有池)。
那麼實現這一目標需要什麼;
- 每個PHP-FPM池都需要自己的init.d啟動/停止指令碼
- 每個PHP-FPM池都需要自己的php-fpm.conf檔案才能擁有唯一的PID
如果您通過CMS(例如Puppet / Chef / Salt / Ansible)管理您的環境,則上述設定並不困難。如果您手動執行操作,則可能會成為負擔並且難以管理。
看看PHP-FPM配置
這是縮寫配置的樣子。您現在將擁有一個.conf檔案,其中包含主程序的配置(PID等)以及1 PHP-FPM池的定義 。
$ cat /etc/php-fpm.d/pool1.conf [global] pid = /var/run/php-fpm/pool1.pid log_level = notice emergency_restart_threshold = 0 emergency_restart_interval = 0 process_control_timeout = 0 daemonize = yes [pool1] listen = /var/run/php-fpm/pool1.sock listen.owner = pool1 listen.group = pool1 listen.mode = 0666 user = pool1 group = pool1 pm = ondemand pm.max_children = 5 pm.process_idle_timeout = 10s pm.max_requests = 500
以上包含最重要的位; 主配置確定它可以被守護程序以及PID檔案應該位於何處。Pool-configuration包含要監聽的基本資訊和Process Manager的型別。
init.d檔案是預設的/etc/init.d/php-fpm 的簡單複製/貼上,只有一些修改。
$ cat /etc/init.d/php-fpm-pool1 #! /bin/sh # # chkconfig: - 84 16 # description:PHP FastCGI Process Manager for pool 'pool1' # processname: php-fpm-pool1 # config: /etc/php-fpm.d/pool1.conf # pidfile: /var/run/php-fpm/pool1.pid # Standard LSB functions #. /lib/lsb/init-functions # Source function library. . /etc/init.d/functions # Check that networking is up. . /etc/sysconfig/network if [ "$NETWORKING" = "no" ] then exit 0 fi RETVAL=0 prog="php-fpm-pool1" pidfile=/var/run/php-fpm/pool1.pid lockfile=/var/lock/subsys/php-fpm-pool1 fpmconfig=/etc/php-fpm.d/pool1 start () { echo -n $"Starting $prog: " daemon --pidfile ${pidfile} php-fpm --fpm-config=${fpmconfig} --daemonize RETVAL=$? echo [ $RETVAL -eq 0 ] && touch ${lockfile} } stop () { echo -n $"Stopping $prog: " killproc -p ${pidfile} php-fpm RETVAL=$? echo if [ $RETVAL -eq 0 ] ; then rm -f ${lockfile} ${pidfile} fi } restart () { stop start } reload () { echo -n $"Reloading $prog: " killproc -p ${pidfile} php-fpm -USR2 RETVAL=$? echo } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) status -p ${pidfile} php-fpm RETVAL=$? ;; restart) restart ;; reload|force-reload) reload ;; condrestart|try-restart) [ -f ${lockfile} ] && restart || : ;; *) echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart|try-restart}" RETVAL=2 ;; esac exit $RETVAL
我們更改為init.d指令碼的唯一部分位於頂部;已定義新的程序名稱 (這需要是唯一的),並且PID檔案已更改 為指向此池的自定義PID檔案,因為它在上面的pool1.conf檔案中定義。
您現在可以與其他所有池分開啟動/停止此池。它的配置可以在不影響其他配置的情況下進行更改。如果您配置了多個池,則您的程序列表將如下所示。
root59634704 ?Ss19:230:00 php-fpm: master process (/etc/php-fpm.d/pool1.conf) root60364744 ?Ss19:230:00 php-fpm: master process (/etc/php-fpm.d/pool2.conf) 多個主程序以root身份執行,並且正在偵聽池配置中定義的套接字。一旦發出PHP請求,它們就會產生子程序來處理它們並在10次空閒後再次停止它們。 主程序還會顯示它載入的配置檔案,從而可以輕鬆查明該特定池的配置。
更好的分離
一旦發出PHP請求,程序列表就像這樣。
root59634704Ss19:23php-fpm: master process (/etc/php-fpm.d/p1.conf) user39874504S19:23\_ php-fpm: pool pool1 user39874504S19:23\_ php-fpm: pool pool1 root60364744Ss19:23php-fpm: master process (/etc/php-fpm.d/p2.conf) user39874504S19:23\_ php-fpm: pool pool2
總而言之,以上有兩個主要優點:
- 每個PHP-FPM池單獨的APC / OPcache位元組碼快取
- 能夠在不影響其他已定義池的情況下啟動/停止/重新配置PHP-FPM池
對於在PHP部署中遇到APC / OPcache / realpath / stat快取問題的任何人來說,這種配置可以通過允許(sudo)訪問重新啟動或重新載入特定池的主PHP-FPM程序來清除所有快取。
這樣做時要記住的事情:
- 如果在每個FPM池中使用錯誤日誌記錄,則應修改Logrotate,以使用正確的池的PID重新載入主程序;
- 確保所有FPM池都在系統引導時啟動,因為它們每個都有一個新的init.d指令碼(通過chkconfig –list 檢查);