Using Memcache

1. About memcached

 

See http://en.wikipedia.org/wiki/Memcached

 


 

2. About memcache (the php extension)

 

See http://www.php.net/manual/en/book.memcache.php

 


 

3. Different between memcached and memcache

 

(1) What’s memcached?

Free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.

 

(2) What’s memcache?

Memcache module provides handy procedural and object oriented interface to memcached, highly effective caching daemon, which was especially designed to decrease database load in dynamic web applications. The Memcache module also provides a session handler (memcache).

 


 

4. Installation for windows

 

(1) Download memcached for Win32 : http://jehiah.cz/projects/memcached-win32/ .

The latest version is http://jehiah.cz/projects/memcached-win32/files/memcached-1.2.1-win32.zip

 

(2) Unzip the binaries in your desired directory (eg. c:\memcached) and see the help by using command:

c:\memcached\memcached.exe -h

 

(3) Install memcached service using command (optional):

c:\memcached\memcached.exe -d install

 

(4) Start the service using command:

c:\memcached\memcached.exe -d start

 

(5) Use ‘netstat -an‘ to see if port 11211 is being used, and check if memcached.exe is list in task manager

 

 

 

 

(6) Download memcache.dll for PHP from http://downloads.php.net (right now I am using PHP5.3.1) :

http://downloads.php.net/pierre/php_memcache-cvs-20090703-5.3-VC6-x86.zip

 

(7) Place your memcache.dll under php\ext\

 

 

(8) Open your php.ini and put "extension=php_memcache.dll" under extensions section, usually named [PECL]

 

 

(9) Restart apache and check phpinfo() whether you can see the memcache section


 

5. Installation for linux (Debian / Ubuntu)

 

(1) Install memcached service by

sudo apt-get install memcached

 

(2) Install libevent (though this is usually done for you automaticly by apt above) by

sudo apt-get install libevent

 

(3) Start memcached (normally installed on /usr/bin/memcached and started by default after apt installation)

memcached -d -m 64 -l 127.0.0.1 -p 11211 -u nobody

 

 

(4) Install memcache.so extension for your php

sudo apt-get install php5-memcache

cat /etc/php5/conf.d/memcache.ini

 

 

(5) Restart apache

sudo /etc/init.d/apache2 restart

 

(6) Check phpinfo() (usually by creating a phpinfo.php under /var/www/)

  


 

6. Security of memcached

 

(1) Local area network (listen web server 192.168.0.2)

memcached -d -m 1024 -u root -l 192.168.0.2 -p 11211 -c 1024 -P /tmp/memcached.pid

 

(2) iptables (firewall, allow 192.168.0.3 to be the only one who can access the memcached server)

iptables -F
iptables -P INPUT DROP
iptables -A INPUT -p tcp -s 192.168.0.3 –dport 11211 -j ACCEPT
iptables -A INPUT -p udp -s 192.168.0.3 –dport 11211 -j ACCEPT

 


 

7. Memcached Cluster (example on memcache)

 

To make memcache works as cluster is as simple as one function below : 

 

[codesyntax lang=”php”]

$mem = new Memcache();
$mem->addServer('192.168.1.2', '11211');
$mem->addServer('192.168.1.3', '11212');
$mem->addServer('192.168.1.4', '11213');
$mem->addServer('192.168.1.5', '11214');
// add more servers

[/codesyntax]

 


 

8. Testing memcache

 

To check whether your memcache is working, see this example: 

 

$mem = new Memcache();
$mem->connect('localhost', 11211);
$mem->set('key', 'This is the first test!', 0, 60);
if ($val = $mem->get('key')) {
echo $val;
} else {
echo 'fail!';
}

 


 

9. Memcache functions

 

<?php
$servers = array(
array('host' => '192.168.1.4', 'port' => '11211'),
array('host' => '192.168.1.3', 'port' => '11211'),
array('host' => '192.168.1.2', 'port' => '11211'),
array('host' => 'localhost', 'port' => '11211'),

);
/**
* init memcache obj
*/

$mem = new Memcache();

/**
* open the memcache debug
*/

memcache_debug(true);
/**
* add servers
*/

foreach ($servers as $s) {
$mem->addServer($s['host'], $s['port']);
}

/**
* print the server status
*/

foreach ($servers as $s) {
if ($mem->getServerStatus($s['host'], $s['port']) == 2) {
echo 'server : ' . $s['host'] . ':' . $s['port'] . ' is running!<br />';
} else {
echo 'server : ' . $s['host'] . ':' . $s['port'] . ' is not running!<br />';
}
}

/**
* print the current version of memcache
*/

echo '<p>current version : ' . $mem->getVersion() . '</p>';

/**
* print current stats of all server
*/

$stats = $mem->getextendedstats();
echo 'servers stats : <pre>' . print_r($stats, true) . '</pre>';

/**
* get current stats of current server
*/

$stats = $mem->getstats();
echo 'current server stats : <pre>' . print_r($stats, true) . '</pre>';

/**
* set first value
*/

$mem->set('key', 1, 0, 60);
echo '<p>original value of "key" : ' . $mem->get('key') . '<br />';

/**
* try to add a value using the same key
*/

if (!$mem->add('key', 'another value')) {
echo 'try to add "key" : value "key" already exists!</p>';

/**
* second value
*/

$mem->add('key2', 2);

/**
* third value
*/

$mem->add('key3', 3);
echo '<p>original value of "key3" : ' . $mem->get('key3') . '<br />';
$mem->delete('key3');
if (!$mem->get('key3')) {
echo 'value of "key3" is deleted!</p>';
}
}

/**
* increase the value
*/

$mem->increment('key', 3);
echo 'after "key" increased by 3 : ' . $mem->get('key') . '<br />';

/**
* decrease the value
*/

$mem->decrement('key', 2);
echo 'after "key" decreased by 2 : ' . $mem->get('key') . '<br />';

/**
* replace the value for some seconds
*/

$mem->replace('key', 100, false, 1);
echo '<br />"key" is replaced by : ' . $mem->get('key') . '<br />';

sleep(1);
if (!$mem->get('key')) {
echo '"key" expired!<br />';
}

$mem->flush();
if (!$mem->get('key') and !$mem->get('key2') and !$mem->get('key3')) {
echo '<p>data all flush</p>';
}

$mem->close();

/**
* get current stats of current server
*/

if (!$stats = $mem->getstats()) {
echo '<p>server is closed</p>';
}

 

 


 

10. Memcache in real world practise

 

(1) As session handler 

 

<?php
/**
* we use memcache for session handler
*/

ini_set('session.save_handler', 'memcache');
ini_set('session.save_path', "tcp://localhost:11211?persistent=1&amp;weight=1&amp;timeout=1&amp;retry_interval=15");
session_start();

/**
* set a random user
*/

if (!isset($_SESSION['randomUser'])) {
$_SESSION['randomUser'] = rand(1, 10) . '_' . time();
}

/**
* set a normal user
*/

$_SESSION['normalUser'] = 'X_' . time();

/**
* print the users info
*/

echo 'random user : ' . $_SESSION['randomUser'] . '<br />';
echo 'normal user : ' . $_SESSION['normalUser'] . '<br />';

/**
* print session id
*/

echo 'session id : ' . session_id() . '<br />';

/**
* check whether we can get the user info from memcache (instead of session)
*/

$memcache = memcache_connect('localhost', 11211);
var_dump($memcache->get(session_id()));

 

(2) Caching database

 

class  db
{
public $memcache;

public function __construct()
{
$this->memcache = new Memcache();
$this->memcache->connect('localhost', 11211) or die ("memcache Could not connect");
}

/**
* get value
*/

public function query($sql, $time)
{
$key = md5($sql);
$data = array();
if (!$data = $this->memcache->get($key)) {
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$data[] = $row;
}
$this->memcache->set($key, $data, false, $time);
}
return $data;
}
}

 


 

11. Memcache in symfony and doctrine

 

@see http://www.doctrine-project.org/documentation/manual/1_2/en/caching

@see http://www.symfony-project.org/gentle-introduction/1_4/en/12-Caching

 

in /config/ProjectConfiguration.class.php (or /apps/myapp/config/myappConfiguration.class.php) : 

 

/**
* myproject/config/ProjectConfiguration.class.php
*/

class ProjectConfiguration extends sfProjectConfiguration
{
/**
* configurations of doctrine
*/

public function configureDoctrine(Doctrine_Manager $manager)
{
// memcached server options
$servers = array(
'host' => 'localhost',
'port' => 11211,
'persistent' => true
);
// memcache driver
$cacheDriver = new Doctrine_Cache_Memcache(array(
'servers' => $servers,
'compression' => false
));
// get doctrine manager
$manager = Doctrine_Manager::getInstance();

// cache all queries automatically
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE_LIFESPAN, 3600);

// set result cache later by using useResultCache()
$manager->setAttribute(Doctrine::ATTR_RESULT_CACHE, $cacheDriver);
$manager->setAttribute(Doctrine::ATTR_RESULT_CACHE_LIFESPAN, 3600);
}
}

 

add useResultCache() to query :

 

/**
* example function
*/

public static function getResult()
{
// set query
$query = Doctrine::getTable('user')
->createQuery('u')
->select('u.*')
->useResultCache(true);
// get result
$result = $query->execute();
$query->free();
return $result;
}

 


 

12. Monitor memcached

 

(1) telnet 127.0.0.1 11211

stats

rate  = get_hits/cmd_get * 100%

 

(2) cacti

 

(3) memcache.php

 


 

13. Hit Rate 

 

(1) Value Size

(2) Page Size

(3) Growth Factor (memcached -f)



 

14. Slab, Page and Chunk

 


 

15. Resources

http://code.google.com/p/memcached/

http://tech.idv2.com/2008/08/17/memcached-pdf/

 

 

That’s all …

Posted in Optimization | Tagged | 5 Comments