Skip to content

APC: get a key's expiration time

It's always surprising to me, but APC is still the best kept secret.

APC offers a bunch of very useful features — foremost a realpath cache and an opcode cache. However, my favorite is neither: it's being able to cache data in shared memory. How so? Simple: use apc_store() and apc_fetch() to persist data between requests.

The other day, I wanted use a key's expiration date to send the appropriate headers (Expires and Last-Modified) to the client, but it didn't seem like APC supports this out of the box yet.

Here is more or less a small hack until there's a native call:

/**
 * Return a key's expiration time.
 *
 * @param string $key The name of the key.
 *
 * @return mixed Returns false when no keys are cached or when the key
 *               does not exist. Returns int 0 when the key never expires
 *               (ttl = 0) or an integer (unix timestamp) otherwise.
 */
function apc\_expire($key) {
    $cache = apc\_cache\_info('user');
    if (empty($cache['cache\_list'])) {
        return false;
    }
    foreach ($cache['cache\_list'] as $entry) {
        if ($entry['info'] != $key) {
            continue;
        }
        if ($entry['ttl'] == 0) {
            return 0;
        }
        $expire = $entry['creation_time']+$entry['ttl'];
        return $expire;
    }
    return false;
}

Installing Varnish on Ubuntu Hardy

This is a quick and dirty rundown on how to install Varnish 2.1.x on Ubuntu Hardy (8.04 LTS).

Get sources setup

Add the repository to /etc/apt/sources.list:

deb http://repo.varnish-cache.org/ubuntu/ hardy Varnish-2.1 

Import the key for the new repository:

gpg --keyserver wwwkeys.eu.pgp.net --recv-keys 60E7C096C4DEFFEB
gpg --armor --export 60E7C096C4DEFFEB | apt-key add -

Installation

Update sources list and install varnish:

apt-get update
apt-get install varnish

Files of importance:

/etc/default/varnish
/etc/varnish/default.vcl
/etc/init.d/varnish

Double-check:

root@server:~# varnishd -V
varnishd (varnish-2.1.2 SVN )
Copyright (c) 2006-2009 Linpro AS / Verdens Gang AS

Further reading

I recommend a mix of the following websites/links:

Fin

That's all!

Caching for dummies

Caching is one of the things recommended whenever something is slow — "Your [database, website, server]? Well, duh! You need a cache!".

All things aside, it's not always easy to cache stuff. I find myself often in situations where I can't cache at all or where a caching solution is complex as hell to implement. All of the sudden you need to dissect your page and lazy load half of it with Ajax — bah. And that's just because those users never want to wait for a cache to expire or invalidate. They just expect the most recent ever! :-)

Sometimes however, caching can be so trivial, it even hurts.

Bypass the application server

There are lots of different techniques and strategies to employ when you start to think about caching. The fastest albeit not always available method is to bypass your app server stack completely. And here's how. :-)

An example

My example is a pet project of mine where I display screenshots of different news outlets which are taken every 3 (three) hours — 0:00, 3:00 AM, 6:00 AM, 9:00 AM, 12:00 PM, 3:00 PM, 6:00 PM, 9:00 PM and so on. In between those fixed dates, the page basically never changes and why would I need PHP to render a page if it didn't change since the last request?

Correct, I don't! :)

And here's what I did to setup my cache:

  • Apache 1.3.x (!) and mod_php5
  • my homepage: docroot/home.php
  • httpd.conf: DirectoryIndex index.html home.php
  • a cronjob: */10 * * * * fetch -q -o docroot/index.html http://example.org/home.php

In greater detail

Homepage

The home.php does all the PHP funkyness whenever I need a fresh rendered version of my website to track an error, or adjust something.

DirectoryIndex

If I ever delete my cache (index.html), my website will still be available. The DirectoryIndex will use home.php next and the request will be a little slower and also more expensive on my side, but the website will continue to work.

Cronjob

The cronjob will issue a HTTP request (GET) using fetch against my homepage and save the result to my index.html. It's really so simple, it hurts. Currently, this cronjob is executed every 10 minutes so I can fiddle with the design and deploy a change more easily, but I could run that cronjob every hour or every few hours as well.

If you don't have fetch, try the following wget command:

wget -q -O docroot/index.html http://example.org/home.php

Fin

That's all, a really simple cache which bypasses your application server. Enjoy!

If you're in for another nifty solution, I suggest you read Brandon Savage's article on caching with the Zend Framework and/or take a look at nginx+Memcached.