前面我们说了,设置多个php-fpm进程池来分离网站。今天来聊聊多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”的默认行为(它将重新加载所有池)。

那么实现这一目标需要什么;

  1. 每个PHP-FPM池都需要自己的init.d启动/停止脚本
  2. 每个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 文件应该位于何处。池配置具有要侦听的位置和进程管理器的类型的基本信息。

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文件中定义。

您现在可以与其他所有池分开启动/停止此池。它的配置可以在不影响其他配置的情况下进行更改。如果您配置了多个池,则您的进程列表将如下所示。

root      5963  4704 ?        Ss   19:23   0:00 php-fpm: master process (/etc/php-fpm.d/pool1.conf)
root      6036  4744 ?        Ss   19:23   0:00 php-fpm: master process (/etc/php-fpm.d/pool2.conf)

多个主进程以root身份运行,并且正在侦听池配置中定义的套接字。一旦发出PHP请求,它们就会产生子进程来处理它们并在10次空闲后再次停止它们。
主进程还会显示它加载的配置文件,从而可以轻松查明该特定池的配置。

更好的分离

一旦发出PHP请求,进程列表就像这样。

root  5963  4704  Ss  19:23  php-fpm: master process (/etc/php-fpm.d/p1.conf)
user  3987  4504  S   19:23   \_ php-fpm: pool pool1
user  3987  4504  S   19:23   \_ php-fpm: pool pool1
root  6036  4744  Ss  19:23  php-fpm: master process (/etc/php-fpm.d/p2.conf)
user  3987  4504  S   19:23   \_ php-fpm: pool pool2

总而言之,以上有两个主要优点:

  1. 每个PHP-FPM池享有单独的APC / OPcache字节码缓存
  2. 能够在不影响其他已定义池的情况下启动/停止/重新配置PHP-FPM池

这对于在PHP部署中遇到APC / OPcache / realpath / stat缓存问题的任何人来说,这种配置可以通过允许(sudo)访问重新启动或重新加载特定池的主PHP-FPM进程来清除所有缓存。

这样做时要记住的事情:

  • 如果在每个FPM池中使用错误日志记录,则应修改Logrotate,以使用正确的池的PID重新加载主进程;
  • 确保所有FPM池都在系统引导时启动,因为它们每个都有一个新的init.d脚本(通过chkconfig --list检查);

本文地址 http://blog.p2hp.com/archives/5814,转载请注明来自Lenix的博客,谢谢。

共享APC或OPcache:为什么多个PHP-FPM主机更好
标签: