APC Is the Easiest PHP Speedup You're Not Using
Every time someone loads a page on a stock PHP setup, PHP reads each script the page needs, compiles it into opcodes (the low level instructions the Zend engine actually runs), executes them, and then throws the compiled result away. The next request does all of that again, even though the file hasn’t changed since last Tuesday. A WordPress or Drupal page pulls in a lot of files, so that adds up.
An opcode cache keeps that compiled result around. The Alternative PHP Cache, APC for short, is a free and open one, and on most sites it’s about as close to a free performance win as you’ll get.
What APC actually does
APC hooks into PHP’s compile step. When a script is requested, APC checks its cache first. On a hit, it installs the functions and classes that were cached with that file and hands the stored opcodes to the engine, which runs them as if it had just compiled them. On a miss, APC calls PHP’s normal compiler, then copies the opcodes, functions and classes into shared memory so the next request can skip the work. The developer TECHNOTES walk through this if you want the details.
Shared memory is the important part. Under mod_php, every Apache child process reads from the same cache, so a file compiled by one child is ready for all of them.
Files are identified by device and inode, which takes a single stat call. By default, apc.stat is on, so APC stats each script on every request and recompiles it if it has changed. That’s why you can deploy new code without thinking about the cache. You can turn it off for extra speed on a server where files rarely change, but then you’ll need to restart the web server or clear the cache every time you deploy.
Installing it
On Debian and Ubuntu there’s a package. On Ubuntu 9.10 it’s php-apc in universe, and it drops its settings into /etc/php5/conf.d/apc.ini.
sudo apt-get install php-apc
sudo /etc/init.d/apache2 restart
Otherwise, install it from PECL. You’ll need the PHP development package (php5-dev on Debian and Ubuntu), which provides phpize, then add extension=apc.so to your php.ini and restart Apache.
There’s one wrinkle worth knowing today. PECL installs the newest stable release by default, and for APC that’s still 3.0.19 from May 2008. The 3.1 line is marked beta, but 3.0.19’s changelog only promises initial PHP 5.3 support, while 3.1.3 lists 5.3 support outright. If you’re on PHP 5.3, I’d ask for the beta explicitly.
sudo pecl install apc-beta
If you’re on PHP 5.2, the stable release is a perfectly reasonable choice. The PHP manual has a general page on installing PECL extensions if you’re doing this for the first time.
Is it working? Ask apc.php
APC comes with a script called apc.php. The Ubuntu package puts it at /usr/share/doc/php-apc/apc.php.gz, and the PECL tarball has it in the top level. Copy it somewhere in your docroot and open it in a browser.
Two numbers matter. The first is the hits and misses split, shown as percentages next to the graphs. Once the site has been up for a while, hits should dominate, since misses mostly come from files being compiled for the first time or after they change. Don’t be fooled by the row labeled Hit Rate in the File Cache Information box; that’s cache requests per second, not a percentage.
The second is Cache full count. Every time the cache fills up, APC has to throw out entries to make room, and that count goes up. On a well sized cache it stays at or near zero.
Before you leave apc.php up, open it in an editor. It ships with ADMIN_PASSWORD set to password, and the admin features stay locked until you change it. Even with a real password, I’d rather not leave a page that describes my server’s internals publicly reachable, so either protect it or delete it when you’re done.
Give it enough memory
The setting you’re most likely to need to change is apc.shm_size, the size of the shared memory segment in megabytes. In the current releases it’s a plain number and the default is 30.
apc.shm_size=64
If Cache full count keeps climbing, raise it until it stops. Keep an eye on the Detailed Memory Usage and Fragmentation section too, since a full or badly fragmented cache means APC is churning instead of helping. The APC docs also warn that some systems, most BSD variants among them, have low default limits on shared memory segment size, so a big value may need an OS setting changed too.
The takeaway
If you run PHP on your own server without an opcode cache, install APC, give it enough memory, and watch apc.php for a day. You want hits climbing and Cache full count sitting at zero. It’s one package and one line of config, and your pages stop doing the same work twice.