What's the point ?
On highly dynamic websites such as forums, news sites or any user content based website, the database server load is often very high. The more traffic you get, the more cluttered your database server becomes, sometimes rendering your website completely unavailable to visitors. Using a data caching daemon will allow you to save some data in memory instead of fetching the data from the database every time. You should know that memcached is used by major websites such as Wikipedia, SourceForge, SlashDot... need I say more?
What is memcached ?
Memcached is the daemon running on your server. Its usage is extremely simple, there are no configuration files, all you do is start the daemon on a given port, and your websites will connect to this daemon to store data in memory. Yes, the data is stored in your RAM. So when starting memcached you'll have to decide how much RAM memcached will be allowed to use. If you start memcached with a 1GB memory space, memcached will store this much data; when the cache is full some of the older data will begin to disappear from the cache.
What is memcache ?
Memcache, in our case, is the PHP extension that will allow us to connect to and make use of Memcached. This PHP extension is not part of the default ones so you'll have to download and install it (see step 2). It provides classes as well as functions that I must admit are very easy to use and understandable. In this article, I provide a mysql+memcache wrapper class for anyone to use.
What is the difference between memcached and memcache ?
Well if you've read the two points above, you should already know. In short, memcached is the daemon running on your machine; memcache is the PHP extension allowing you to make use of memcached.
1. Setting up memcached
I haven't found memcached in my repositories (might aswell try # yum install memcached just in case?) so I'll download the source and compile it. First go get the latest version from the official website.
# make install
That's it, you're set! That was pretty easy wasn't it? We'll now see the command line arguments for starting memcached:
# memcached -d -m 1024 -l 127.0.0.1 -p 11211 -u nobody
The arguments are:
-d : start as daemon, running in the background
-m 1024: allow memcached to use up to 1024 MB of RAM (1GB)
-l 127.0.0.1: listen on local interface
-p 11211: listen on port 11211
-u nobody: run as user "nobody"
If you're not sure how much memory you should allocate to memcached, try running this command first:
Note that upon starting memcached, if all is OK, you will see no output message. To see if memcached is correctly started, run this command:
user 13143 0.0 0.0 4152 648 pts/0 R+ 07:11 0:00 grep memcached
2. Setting up memcache PHP extension
The memcache PHP extension should be found in the classic repositories, so try this command:
Installed: php-pecl-memcache.i386 0:2.2.3-1.el5_2
Dependency Installed: php-pear.noarch 1:1.4.9-4.el5.1
Just for reference, here's a link to the official memcache website, if you need to grab the sources.
Let's see if memcache was installed properly. First restart the httpd:
# service httpd restart
Then place a simple php file on your website containing the following code:
3. Using memcache in your code
Unfortunately, installing both components isn't enough. You'll have to edit your code in order to make use of the caching features. Be reassured though, it couldn't be easier! There are a couple of functions you'll need to use, nothing complex.
If you want to find out the complete listing of the memcache php functions, visit the official website. Basically we'll be using 5 methods:
- Memcache::connect($host, $port, $timeout): connect to your daemon
- Memcache::get($key) : fetch data from your cache
- Memcache::set($key, $var, $flag, $expire): store data in your cache
- Memcache::delete($key): remove data from your cache
- Memcache::close(): disconnect.
You can cache any data that you want:
Applied to MySQL queries:
As you can see in the example above, I use the "serialize" and "unserialize" php functions. Why is that? The reason is because the Memcache::get() function always returns a string. So if you want to store an array of data (or an object), you'll have to serialize said array, and unserialize it after having read it from the database.
If you know a better workaround for this problem please feel free to leave a comment.
4. Wrapper class for memcache & mysql
I have just written a simple wrapper class for MySQL, making use of the powerful caching system offered by memcache. You can download the class here, I included a simple example for testing the class.
The principle is very simple: when executing a query, the script will check if the query result is already in the cache. If the data is in the cache, it is returned immediatly (no query executed). if the data is not in the cache, the query is executed, and the results are then placed in the cache with the specified "time to live".
Here are the wrapper class functions:
function MySQLMemcache($mysql_info, $memcache_info, $autoconnect=true, $enable_logging=true);
function dataQuery($query, $usecache=true, $ttl=0);
function fieldDataQuery($query, $field, $usecache=true, $ttl=0);
More documentation is provided inside the actual php file.
Thank you for reading, feel free to leave a comment if this article has been helpful to you.
I'm finished with my server optimization thematic.