GIT – The following guide will walk you through setting up possibly the fastest way to serve known to man. If there is a faster way, I’ve not yet found it climbing through zillions of blog posts out there on the subject. In this article, we’ll be installing http server, with the -FPM patches, as well as APC. 

Some Background

For the last 2+ years, we’ve been running Apache with mod_php at Massify . And, for the most part, it’s been painless and hassle free. But as traffic increases, we’ve noticed Apache struggling to keep up. It chews up memory like crazy and don’t even get me started about CPU. Add in the fact that we are currently moving the site from co-located metal to hosting on the cloud, we’ve needed to find a faster way to serve up these pages on machines that are a quarter of the spec we had with the metal.

It’s a pretty well know fact by now that Nginx  (pronounced engine-x, though I call it n-jinx) in typical scenarios outpaces Apache on all kinds of fronts: i/o, cpu, memory, reqs/sec. Feel free to google  around for more comparitive information. I can tell you from my own informal load testing on both setups of Massify that I’ve seen a pronounced difference between the two, specifically in the configuration I’ll be writing about in this post. I won’t be posting numbers, because my testing wasn’t scientific and it’s not really the focus of this article, but I am more than confident that we’ll be getting a level of performance a few steps above Apache. (Please don’t write me telling me I can recompile and reconfigure Apache to approach Nginx’s performance. I’m certain you are correct, but I don’t really care at this point.)

PHP-FPM?

The typical nginx configuration involves using spawn-fcgi from the LightTPD project to get nginx serving up PHP. There are a few issues with spawn-fcgi that are covered on more in-depth posts across the interwebs, so I won’t rehash them here. Suffice to say, it can lead to major headaches, so we want to do what we can to avoid those headaches.

Enter PHP-FPM , which stands for PHP FastCGI Process Manager. It is actually a set of patches for the PHP source that bake in FastCGI process management into your PHP binaries.

Note: Even if you are sticking with Apache, there are a variety of reasons to skip mod_php and go straight for PHP via FastCGI. For starters, with mod_php, each request that Apache handles loads PHP – and all of it’s libraries. That’s an epic shit ton of overhead. With FastCGI, PHP acts more akin to an application server. PHP-FPM, as well as spawn-fcgi, manage this; loading and killing PHP instances as needed. This has a lot of benefits, not the least of which is reduced memory overhead.

Let’s Get Rocking

We’re using a fresh of 8.10 Intrepid. With a little tooling, this can work equally well on other distros. I’ve deployed this on CentOS, with minor changes, just fine.

First things first, we’re going to have to install all the dependencies for building everything:

sudo apt-get install make bison flex gcc patch autoconf subversion locate
sudo apt-get install libxml2-dev libbz2-dev libpcre3-dev libssl-dev zlib1g-dev libmcrypt-dev libmhash-dev libmhash2 libcurl4-openssl-dev libpq-dev libpq5 libsyck0-dev

Now that we have everything we need, now it’s time to …

Compile PHP

We’re going to the source for PHP 5.2.8, as well as the matching patches for PHP-FPM. We’ll then apply the patches and get compling.

cd /usr/local/src/
sudo wget http://us.php.net/get/php-5.2.8.tar.gz/from/this/mirror
sudo tar zvxf php-5.2.8.tar.gz
sudo wget http://php-fpm.anight.org/downloads/head/php-5.2.8-fpm-0.5.10.diff.gz
sudo gzip -cd php-5.2.8-fpm-0.5.10.diff.gz | sudo patch -d php-5.2.8 -p1
cd php-5.2.8
sudo ./configure --enable-fastcgi --enable-fpm --with-mcrypt --with-zlib --enable-mbstring ---pdo --with-pgsql --with-curl ---debug --enable-pic ---rpath --enable-inline-optimization --with-bz2 --with-xml --with-zlib --enable-sockets --enable-sysvsem --enable-sysvshm --enable-pcntl --enable-mbregex --with-mhash --enable-xslt --enable-memcache --enable-zip --with-pcre-regex
sudo  make all install
sudo  strip /usr/local/bin/php-cgi

The above should have been completely auto-pilot. If you run into any errors, more than likely you don’t have some of the dependencies installed.Note: Make sure you enable and disable whatever PHP configuration options you need for your particular setup. The above are what we use at Massify, more or less. (We actually apply a couple of other custom patches, but that’s another post for another day).

While we are at it, let’s install some of the modules we’re going to need via PECL:

sudo pecl install memcache
sudo pecl install apc
sudo pecl install syck-beta

Now, when you build the APC extension, make sure you turn off the option to compile for apache. It will prompt you to make this change.

Let’s copy the stock php.ini:

sudo cp /usr/local/src/php-5.2.8/php.ini-recommended /usr/local/lib/php.ini

Finally, let’s setup symbolic links to make things easier to find:

sudo mkdir /etc/php/
sudo ln -s /usr/local/lib/php.ini /etc/php/php.ini
sudo ln -s /usr/local/etc/php-fpm.conf /etc/php/php-fpm.conf

That’s it for compiling PHP. The only thing we have left to do is change some setting in the php-fpm conf. Open up /etc/php/php-fpm.conf in your editor of choice. Do some searching and change the users who own the processes to www-data. The file is too big to post in here, but the values we want to change are on lines 51, 52, 63 and 66. Should look something like:

<value name="owner">www-data</value>
<value name="group">www-data</value>
<value name="user">www-data</value>
<value name="group">www-data</value>

Done!

NGINX

This is just as easy as compiling PHP was:

cd ..
sudo wget http://sysoev.ru/nginx/nginx-0.6.35.tar.gz
sudo tar zxvf nginx-0.6.35.tar.gz
sudo rm -f nginx-0.6.35.tar.gz
cd nginx-0.6.35
sudo ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module
sudo make && sudo make install

Let’s set up some links:

sudo ln -s /usr/local/nginx/conf /etc/nginx

Now the next step is optional, but this is what I’ve been using so far. Let’s open up /etc/nginx/nginx.conf in our editor and go to town. Salt and pepper to taste:

user  www-data;
worker_processes  6;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  10 10;

    gzip  on;
    gzip_comp_level 1;
    gzip_proxied any;
    gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        log_format main '$remote_addr - $remote_user [$time_local] '
                  '"$request" $status  $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx_access.log  main;

        error_log  /var/log/nginx_error.log debug;

        include /usr/local/nginx/sites-enabled/*;
}

We’re also going to have to set up some FastCGI parameters so that PHP doesn’t choke and you’ll avoid random 503 errors from nginx. Open up/etc/nginx/fastcgi_params and add the following:

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

Finally, let’s create a SystemV style init script and store it in /etc/init.d/nginx. This script was lifted from here .

#! /bin/sh

### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/sbin/nginx
NAME=nginx
DESC=nginx

test -x $DAEMON || exit 0

# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
        . /etc/default/nginx
fi

set -e

case "$1" in
  start)
        echo -n "Starting $DESC: "
        start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/$NAME.pid
                --exec $DAEMON -- $DAEMON_OPTS
        echo "$NAME."
        ;;
  stop)
        echo -n "Stopping $DESC: "
        start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/$NAME.pid
                --exec $DAEMON
        echo "$NAME."
        ;;
  restart|force-reload)
        echo -n "Restarting $DESC: "
        start-stop-daemon --stop --quiet --pidfile
                /usr/local/nginx/logs/$NAME.pid --exec $DAEMON
        sleep 1
        start-stop-daemon --start --quiet --pidfile
                /usr/local/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
        echo "$NAME."
        ;;
  reload)
      echo -n "Reloading $DESC configuration: "
      start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/$NAME.pid
          --exec $DAEMON
      echo "$NAME."
      ;;
  *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|force-reload}" >&2
        exit 1
        ;;
esac

exit 0

Don’t forget to set executable permissions on it!

Set Up Your Site

This part you’ll have to tool yourself, but here’s a rough guide.

First we’ll have to create a directory to store our site(s) conf files:

sudo mkdir /usr/local/nginx/sites-enabled
sudo ln -s /usr/local/nginx/sites-enabled /etc/sites

And now let’s add a conf file for our default site at /etc/sites/default.conf. The contents:

server {
        listen *:80;

        location / {
                   /var/www/default/pub;
                index index.php;

                # if file exists return it right away
                if (-f $request_filename) {
                        break;
                }

                # otherwise rewrite the fucker
                if (!-e $request_filename) {
                        rewrite ^(.+)$ /index.php$1 last;
                        break;
                }

        }

        # if the request starts with our frontcontroller, pass it on to fastcgi
        location ~ ^/index.php
        {
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_param SCRIPT_FILENAME /var/www/default/pub$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_script_name;
                include /usr/local/nginx/conf/fastcgi_params;
        }
}

The conf file above is for front controller style sites, which include wordpress, cake, etc. It also takes care of serving up static content without going through FastCGI. Note: You will need to change /var/www/default to wherever the files for your site reside.

Start It Up

Now all we have to do to get it rocking:

sudo php-fm start
sudo /etc/init.d/nginx start

You should be able to test your site out and see it working. Any questions, feel free to ask.

Reference

Print Friendly

Comments

comments

Bài viết liên quan