php-fpm 内存调优

为了高效利用服务器,今天特地把博客迁移到一台只有 1G 内存的新服务器上。原想一个静态博客而已,耗不了多大机器性能。不曾想,1G 的内存很快就不够用了,看了一下,连 swap 都被用上了。于是赶紧用命令查下各进程的内存开销:

$ ps aux

发现占据一大半内存的是一堆 php-fpm 相关的子进程。看来是 php-fpm 的配置不合理,导致它们被不合理地创建出来。这就要分析 php-fpm 创建子进程的方式了。

php-fpm 有三种孵化子进程的方式,一般可在 /etc/php-fpm.d/www.conf 里面,通过指定 pm 的值(例如,pm = dynamic),结合对应的参数(例如,pm.max_children = 50)来配置。这三种孵化方式分别是:

  • 静态 static
  • 动态 dynamic
  • 按需 ondemand

下面就分别来讨论这三种方式。

静态 static

通过配置 pm = static,可以告知 php-fpm 孵化固定数量的子进程。数量可以通过参数 pm.max_children 来指定,例如

pm = static
pm.max_children = 50

这种方式自然是不灵活的。不过,在内存比较小的时候,只固定开一两个子进程也不是不可以。只是,对我这种想要高效利用服务器的人来说,这么做显然没有多大意义。

动态 dynamic

通过配置 pm = dynamic,可以让 php-fpm 动态改变子进程的数量。php-fpm 启动时,首先会创建一定数量的子进程,具体的数量由参数 pm.start_servers 来控制。动态的方式同样有最大子进程数,也使用 pm.max_children 参数。除此之外,我们之所以说动态,是因为还要在合适的时机里杀掉闲置的子进程,从而释放内存。这就要考虑到另外两个参数了,它们分别是 pm.min_spare_serverspm.max_spare_servers。前者代表最小闲置子进程数,后者代表最大闲置子进程数。一旦闲置的子进程超出了 pm.max_spare_servers, 就要被杀掉。php-fpm 默认就采用这种方式。一个典型的配置如下:

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

可以看出,尽管动态的方式让子进程的数量动态增减,体现了灵活性,但当最大闲置子进程数很大,而博客的访问量很小的时候,子进程是不会被杀掉的,这就会造成大量的内存开销。换句话说,动态的方式可以最大化地优化服务器响应(因为子进程没有被杀掉),但所需付出的代价就是更大的内存占用。文章一开始说到内存不够用,就是因为子进程数量尚未超过最大闲置数量而不被杀掉,导致内存被大量占用造成的。这时候最直接的解决方式就是调低最大闲置子进程数。

按需 ondemand

使用动态的方式,并调低最大闲置子进程数,似乎已经解决问题了。不过,尽管只有 1G 内存,我仍然指望着它能发挥更大的作用,替我做更多的事情。可是,内存已经捉襟见肘了,如何才能高效利用这台服务器呢?考虑到静态博客对即时性的要求并不太高,因此,如果能够尽可能回收内存,那么就算只有 1G,也同样可以做很多事情。这就该使用到按需模式了。

所谓按需模式,顾名思义就是有需要的时候才分配给你,不需要的时候就释放掉。这就非常符合我的需求了。配置方式也很简单,就是指定 pm = ondemand。当然了,按需模式也不是说子进程一闲置就立刻杀掉,而是要通过参数 pm.process_idle_timeout 来控制闲置时长(单位是秒)。pm.process_idle_timeout 太短,php-fpm 将不可避免地要频繁创建和杀掉子进程;而太长,又会长期占用内存,不利于其他进程的创建。因此,典型的配置是:

pm = ondemand
pm.process_idle_timeout = 15

留下评论