Monday, 14 September 2009

Utilizing Memcache with PHP

Intro
In this article I will demonstrate how to use the PHP memcache extension, as well as a possible use case for memcache. If you have not already installed memcached and the PHP memcache extension check out http://www.wolflabs.org/2008/12/07/memcached-php-memcache-extension-installation/.

Example Source

Here is the code that I will be using for this example. Please note that this script should be run from the cli on the same server memcached is currently running on.

<?php
/**
* Memcache demo script
*
* @author Anthony Stramer
* @version $Id: memcache.demo.php 2 2009-01-20 20:43:23Z absynth $
* @filesource memcached.demo.php
* @copyright (c) 2009 Anthony Stramer - All Rights Reserved
* @license http://www.gnu.org/licenses/gpl.html
*/


// create a new memcache object
$memcache = new Memcache;


// connect to our memcache server
$memcache->connect('localhost', 11211);

echo 'Checking if cache existed...';

// get the data from memcached
$var = $memcache->get('testData');

// check to see if our data is in cache already
if(!$var)
{
echo "no.n";

$temp = time();

echo "Setting cache to value [{$temp}]…”;
$memcache->set(’testData’, $temp, MEMCACHE_COMPRESSED);
echo “done”;
}else{
echo “yes.n”;
echo “Data in cache: {$var}n”;

// clear the cache
echo “Clearing cache…”;
$memcache->delete(’testData’);
echo “done.”;
}



echo “n”;
?>


Using the Memcache PHP Extension
In the example code above I have outlined how to connect, set data, and destroy data in memcached. Lets go step by step through the code, the first thing we need to do is create a new memcache class, if you get an error saying that the class does not exist that means that the PHP memcache extension is not installed. As well we will connect to the memcahe server, in my case it is my localhost on the default memcahe port.

// create a new memcache object
$memcache = new Memcache;


// connect to our memcache server
$memcache->connect('localhost', 11211);


Next we will try to see if our test data already exists in memcache in the ‘testData’ key, think of memcache as an associative array.

$var = $memcache->get('testData');

Now the data that is loaded for the ‘testData’ key should be in our variable. We are going to check to see if there was data in our ‘testData’ key. If the data exists then we will unset it, although if the data did not exist we will set it with the current UNIX time stamp. Also please note that we are using the MEMCACHE_COMPRESSED flag, the reason for this is that we can store more information in memory this way, but it does cause more strain on the server’s CPU since every time we put or get data it needs to be compressed or uncompressed. If you are unable to set/get any data from memcache make sure your php install was compiled with zlib support, memcache compression uses zlib, if it is not available the set or get will fail silently and you won’t get any data.

// get the data from memcached
$var = $memcache->get('testData');


// check to see if our data is in cache already
if(!$var)
{
echo "no.n";

$temp = time();

echo "Setting cache to value [{$temp}]…”;
$memcache->set(’testData’, $temp, MEMCACHE_COMPRESSED);
echo “done”;
}else{
echo “yes.n”;
echo “Data in cache: {$var}n”;



// clear the cache
echo “Clearing cache…”;
$memcache->delete(’testData’);
echo “done.”;
}


A Real World Example
A real world example for the use of memcache is user data for an application. Lets say that you have a really complicated ACL (access control list) that you use to set down fine grain permissions, these type of scripts can be very database intensive if you use normalization like I do, lets say that you are running 4 queries per user to figure out their permissions, that may not seem like a lot but you need to take into account all of the other read/writes that are happening in the database for every other user. You will strain the database with these queries that really do not need to be run on each page load. What I do for applications I work on is create a cache of the user’s permissions as well as their overall user data, and use a key that will be unique to each user, for example ‘USRD_’. In a perfect world this would work all the time and you would never have to reload user data once it is compiled, but this isn’t true since administrators could change user permissions on the fly. So my solution is to simply destroy the cached user data of all logged in users, or for a single user if permissions were changed for a single person, as well any time that a user changes their data, like email or name, the cache is destroyed and recreated on the next page load. Using caching techniques like this you should be able to lower the hit on the database server by a lot.

Something else that I would suggest that you should do is take a look at your slow query logs. If you see a particular query coming up a lot or generally taking a ton of system resources, ask yourself if it could be cached, remember memcache servers are cheap, database servers are not.

http://www.wolflabs.org/2009/04/04/utilizing-memcache-with-php/

http://www.wolflabs.org/2009/04/04/utilizing-memcache-with-php/

http://www.wolflabs.org/2009/04/04/utilizing-memcache-with-php/

No comments:

Post a Comment