Memcached is a distributed, high performance caching solution developed for use atLiveJournal.com. It can provide tremendous performance benefits for your site if used correctly, but also adds a degree of complexity to your site, so be sure that you truly need to increase performance before you decide to implement Memcached.
When you’ve decided to use Memcached, integrating it with the Zend Framework is fairly straightforward, especially if you are familiar with basic caching with the Zend Framework. Of course, you need to have Memcached installed and running on your server first. When it’s up and running, you simply use the factory method of the Zend_Cache class to create your caching object, and pass it some configuration parameters.
Let’s explore some parameters we can use…
Frontend Options
This example uses the ‘Core’ Frontend, which is the standard way to use caching in the Zend Framework. The other frontends, Output, Function, Class, File, and Page, may have additional parameters. The ‘main’ frontend options are:
- Caching - This controls whether or not to actually use the caching mechanism. The purpose of this is so you can turn off caching in your application for testing purposes, without having to alter any of your code…it all will behave exactly the same, but the cache backend will never ‘hit’, nor will it send any saves.
- Lifetime - How long the cache will be good for. Anything that has been cached for longer than this time (in seconds) will automatically be invalidated. If you pass ‘null‘, the cache will never be invalidated. 1800 seconds (30 minutes) is a good starting point.
- Automatic Serialization - You can cache any kind of variable…from strings to complex objects. In order to store objects and arrays, Zend must first serialize data into a string. If this parameter is set to ‘true‘, this serialization will happen on the fly and behind the scenes. If set to ‘false’ (default), you must perform this serialization beforehand, otherwise an exception is thrown. I highly recommended setting this to ‘true’, unless you know you’ll never be caching anything but strings.
For a complete listing of all available options, see the Zend Framework Documentation.
Backend Options
The backend is how you tell Zend where to physically save your data. Available options are File, Sqlite, Memcached, Apc, Xcache, ZendPlatform, and TwoLevels.Memcached is usually considered the fastest option, and relatively easy to implement. The only easier backend is File, and possibly Sqlite, but those are non-distributed and significantly less perfomant that Memcached, and will be covered in separate articles.
The two backend options for Memcached are:
- Servers - A multidimensional array of your Memcached servers you wish to connect to
- Compression - If you want on-the-fly compression of your data in Memcached. Recommended in low memory environments, but it comes with a performance hit, so usually I just set this to false
Putting It All Together
Now that we’ve explored our options, lets see it in action!
Both the frontend options and backend options are associative arrays, so let’s set those up first:
$frontendOpts = array( 'caching' => true, 'lifetime' => 1800, 'automatic_serialization' => true ); $backendOpts = array( 'servers' =>array( array( 'host' => '192.168.XXX.XXX', 'port' => 11211, 'weight' => 1 ) ), 'compression' => false );
And now instantiate the object:
$cache = Zend_Cache::factory('Core', 'Memcached', $frontendOpts, $backendOpts);
And that’s it! You can now use your cache like any Zend Framework Cache:
Getting data:
$date = $cache->load($cacheKey);
Saving Data:
$cache->save($data, $cacheKey);
An Example
Reading the database on every page view can be a major performance killer! If your data doesn’t need to be 100% up-to-date, a caching solution like this can really speed up your site:
//Check to see if the $topStories are cached and look them up if not if(!$topStories = $cache->load('topStories')){ //Look up the $topStories $result = mysql_query('SELECT * FROM stories ORDER BY rating DESC'); while($story = mysql_fetch_object($result)){ $stories[] = $story; } //Save to the cache, so we don't have to look it up next time $cache->save($stories, 'topStories'); }
Extra Credit
To make your caching object even more useful, you’ll probably want to make it easily available to your entire application. You could use global
variables, but you can accidently overwrite them and you must declare them as global in your functions, which invites errors. The better approach is to use Zend_Registry to hold your caching object and make it available to your application.
To save your object for future use (can have any key, not just ‘Memcache’, just make sure it is memorable):
Zend_Registry::set('Memcache', $cache);
Then at anytime in your application, you can access your Memcache object with:
Zend_Registry::get('Memcache');
…which returns your Memcache object. You can directly call any Zend_Cache method on the returned object:
Zend_Registry::get('Memcache')->save($stories, 'topStories');
…or…
$topStories = Zend_Registry::get('Memcache')->load('topStories');