Monday, July 14, 2008

php-fpm: a smoother PHP/FastCGI process manager

I’ve been running PHP apps with the standard PHP FastCGI server behind nginx for a couple of years now, and in that time have worked up a set of tools to manage PHP processes with multiple configuration profiles. This has been based around my slightly hacked version of Alexey Kovyrin’s PHP–FCGI spawn script, along with a chkconfig–compatible init script I’ve written as a front–end to control it, taking in some simple per–profile configuration in /etc/sysconfig/php-fcgi.

Various contributors to the English nginx mailing list have posted in that time singing the praises of Andrei Nigmatulin’s php-fpm, a patch to the PHP source which adds “FastCGI Process Management” to the standard php-fcgi binary. It’s apparently in use in some pretty heavily–loaded sites, and I’ve had it in mind to check it out, but as my setup has been stable (if not exactly full–featured) over the last few projects, I haven’t had a huge impetus to get and do it. Today, however, I finally had enough downtime to check it out, and now I’m wishing I’d done it earlier.

My existing method basically worked like this:

· init script reads configuration file, with one “profile” per line detailing location of php.ini file, interface and port to run on, number of child processes to run, number of requests to serve before a re–spawn, etc.;

· init script uses these details to construct a command–line to call Alexey’s spawn script, once for each profile;

· spawn script constructs environment and command–line argument list to spawn a set of PHP processes for each profile entry.

This has worked fine, but as so often with these things, the init script became a bit unwieldy with additions over time, and is still unable to do anything elegant like graceful restarts on the PHP daemons.

php-fpm addresses these issues and more. The “profile” configuration is put into a sensible, clear configuration file (php-fpm.conf) which allows you to specify a number of named PHP process “pools”, each with its own detailed FastCGI server and PHP configuration.

The documentation’s somewhat light, and mostly in Russian, but it has all you need to get going, and the configuration file is easy to read. Once you’ve configured the pools you want (in my case sets of named dev/stage/live setups on different ports, so as to keep include_paths — and therefore library code — properly staged), you just need to run php-cgi --fpm. From there on, you can send various signals to the master process including SIGQUIT for a graceful stop, SIGUSR1 to cycle log files, and SIGUSR2 for a graceful reload/restart. The master process ID is stored in $PHP_PREFIX/logs/php-fpm.pid.

I’ll probably write a simple chkconfig/init wrapper to send these signals to the master using e.g. /etc/init.d/php-fpm graceful, but that’s about all I’ll need to do in order to replicate and extend my existing setup.

Not only does this simplify and tidy up my PHP–FCGI setup enormously, it also adds a number of convenient extra points, including IP–restriction and a nice fix for the “empty error” page problem. Intuitively it “feels” a lot more solid, and I’m looking forward to trying it out on the next suitable project. Nice bit of Russian coder humour there on the “extra points” page, too. Thanks, Andrei!

Comments

  • Nick made the following comment at 8:22am on March 17th 2009:
    Hi Igor, How is this working for you? I want to setup a PHP FastCGI backend for a nginx frontend and am looking at PHP-FPM. I would appreciate your opinion and any tips you can offer. Also, did you manage to get the chkconfig/init wrapper done for this, and if so, would you mind sharing it? Thanks for any help. - Nick
  • Igor Clark made the following comment at 10:44pm on March 17th 2009:
    Hi Nick, yep, it worked out really nicely. I ended up not needing a wrapper - I'm not sure how long it's been in there, but the most recent versions include an init script in $PHP_INSTALL_DIR/sbin/php-fpm. I've simply symlinked that in as /etc/init.d/php-fpm and added chkconfig comment lines (e.g. "# chkconfig : - 60 25" to make it S60 and K25). One really nice thing about the php-fpm.conf format is that you have a default set of PHP config values which you just override on a per-directive, per-'pool' basis. Overall it's made PHP-FCGI pretty painless. Hope that's of some help.
  • “Vito Botta” made the following comment at 9:50pm on July 22nd 2009:
    Hi! I am using nginx with php-fpm, and while it works nicely for the most part (and extremely fast!), I have a problem I haven't yet managed to solve: after a while the website has been in idle (for now there is no traffic apart mine), the php-cgi process die and there isn't a sort of auto restart as soon as a new request is made. Therefore all what I get is a nice "502/bad gateway". Any ideas? Thanks in advance.
  • Igor Clark made the following comment at 12:53pm on July 26th 2009:
    Hi Vito, sorry, I haven't come across that problem before. In my experience php-fpm has been stable whether there is traffic or not, and the fact that the processes are "dying" suggests that it's not working normally. Have you tried the "High load PHP" mailing list on google groups? It's at http://groups.google.com/group/highload-php-en - good luck anyway.

Add a comment

Name
Email
Website
Comment