<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Abhi&#039;s Weblog &#187; Scalability</title>
	<atom:link href="http://abhinavsingh.com/blog/category/scalability/feed/" rel="self" type="application/rss+xml" />
	<link>http://abhinavsingh.com/blog</link>
	<description>PHP, Memcached, XMPP and Web Development</description>
	<lastBuildDate>Wed, 06 Apr 2011 22:19:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>MEMQ : Fast queue implementation using Memcached and PHP only</title>
		<link>http://abhinavsingh.com/blog/2010/02/memq-fast-queue-implementation-using-memcached-and-php-only/</link>
		<comments>http://abhinavsingh.com/blog/2010/02/memq-fast-queue-implementation-using-memcached-and-php-only/#comments</comments>
		<pubDate>Sun, 07 Feb 2010 14:16:27 +0000</pubDate>
		<dc:creator>Abhinav Singh</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Memcache]]></category>
		<category><![CDATA[Queue]]></category>

		<guid isPermaLink="false">http://abhinavsingh.com/blog/?p=580</guid>
		<description><![CDATA[Memcached is a scalable caching solution developed by Danga interactive. One can do a lot of cool things using memcached including spam control, online-offline detection of users, building scalable web services. In this post, I will demonstrate and explain how to implement fast scalable queues in PHP. MEMQ: Overview Every queue is uniquely identified by [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2010%2F02%2Fmemq-fast-queue-implementation-using-memcached-and-php-only%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2010%2F02%2Fmemq-fast-queue-implementation-using-memcached-and-php-only%2F&amp;source=imoracle&amp;style=normal&amp;service=bit.ly&amp;service_api=R_f027b5a79a20a49b713f16282f1e0857&amp;hashtags=Memcache,PHP,Queue&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Memcached is a scalable caching solution developed by <a href="http://www.danga.com/">Danga interactive</a>. One can do a lot of <a href="http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/">cool things using memcached</a> including spam control, online-offline detection of users, building scalable web services. In this post, I will demonstrate and explain how to implement fast scalable queues in PHP.</p>
<p><strong style="font-size:18px;"><u>MEMQ: Overview</u></strong><br />
Every queue is uniquely identified by it&#8217;s name. Let&#8217;s consider a queue named &#8220;foo&#8221; and see how MEMQ will implement it inside memcached:</p>
<ul>
<li>Two keys namely, <code>foo_head</code> and <code>foo_tail</code> contains meta information about the queue</li>
<li>While queuing, item is saved in key <code>foo_1234</code>, where 1234 is the current value of key foo_tail</li>
<li>While de-queuing, item saved in key <code>foo_123</code> is returned, where 123 is the current value of key foo_head</li>
<li>Value of keys <code>foo_head</code> and <code>foo_tail</code> start with 1 and gets incremented on every pop and push operation respectively</li>
<li>Value of key foo_head NEVER exceeds value of foo_tail. When value of two meta keys is same, queue is considered empty.</li>
</ul>
<p><strong style="font-size:18px;"><u>MEMQ: Code</u></strong><br />
Get the source code from GitHub:<br />
<a href="http://github.com/abhinavsingh/memq">http://github.com/abhinavsingh/memq</a></p>
<pre name="code" class="php">&lt;?php

	define('MEMQ_POOL', 'localhost:11211');
	define('MEMQ_TTL', 0);

	class MEMQ {

		private static $mem = NULL;

		private function __construct() {}

		private function __clone() {}

		private static function getInstance() {
			if(!self::$mem) self::init();
			return self::$mem;
		}

		private static function init() {
			$mem = new Memcached;
			$servers = explode(",", MEMQ_POOL);
			foreach($servers as $server) {
				list($host, $port) = explode(":", $server);
				$mem-&gt;addServer($host, $port);
			}
			self::$mem = $mem;
		}

		public static function is_empty($queue) {
			$mem = self::getInstance();
			$head = $mem-&gt;get($queue."_head");
			$tail = $mem-&gt;get($queue."_tail");

			if($head &gt;= $tail || $head === FALSE || $tail === FALSE)
				return TRUE;
			else
				return FALSE;
		}

		public static function dequeue($queue, $after_id=FALSE, $till_id=FALSE) {
			$mem = self::getInstance();

			if($after_id === FALSE &#038;&#038; $till_id === FALSE) {
				$tail = $mem-&gt;get($queue."_tail");
				if(($id = $mem-&gt;increment($queue."_head")) === FALSE)
					return FALSE;

				if($id &lt;= $tail) {
					return $mem-&gt;get($queue."_".($id-1));
				}
				else {
					$mem-&gt;decrement($queue."_head");
					return FALSE;
				}
			}
			else if($after_id !== FALSE &#038;&#038; $till_id === FALSE) {
				$till_id = $mem-&gt;get($queue."_tail");
			}

			$item_keys = array();
			for($i=$after_id+1; $i&lt;=$till_id; $i++)
				$item_keys[] = $queue."_".$i;
			$null = NULL;

			return $mem-&gt;getMulti($item_keys, $null, Memcached::GET_PRESERVE_ORDER);
		}

		public static function enqueue($queue, $item) {
			$mem = self::getInstance();

			$id = $mem-&gt;increment($queue."_tail");
			if($id === FALSE) {
				if($mem-&gt;add($queue."_tail", 1, MEMQ_TTL) === FALSE) {
					$id = $mem-&gt;increment($queue."_tail");
					if($id === FALSE)
						return FALSE;
				}
				else {
					$id = 1;
					$mem-&gt;add($queue."_head", $id, MEMQ_TTL);
				}
			}

			if($mem-&gt;add($queue."_".$id, $item, MEMQ_TTL) === FALSE)
				return FALSE;

			return $id;
		}

	}

?&gt;</pre>
<p><strong style="font-size:18px;"><u>MEMQ: Usage</u></strong><br />
The class file provide 3 methods which can be utilized for implementing queues:</p>
<ol>
<li><u>MEMQ::is_empty</u> &#8211; Returns TRUE if a queue is empty, otherwise FALSE</li>
<li><u>MEMQ::enqueue</u> &#8211; Queue up the passed item</li>
<li><u>MEMQ::dequeue</u> &#8211; De-queue an item from the queue</li>
</ol>
<p>Specifically MEMQ::dequeue can run in two modes depending upon the parameters passed, as defined below:</p>
<ol>
<li><u>$queue:</u> This is MUST for dequeue to work. If other optional parameters are not passed, top item from the queue is returned back</li>
<li><u>$after_id:</u> If this parameter is also passed along, all items from $after_id till the end of the queue are returned</li>
<li><u>$till_id:</u> If this paramater is also passed along with $after_id, dequeue acts like a popRange function</li>
</ol>
<p>Whenever optional parameters are passed, MEMQ do not remove the returned items from the queue.</p>
<p><strong style="font-size:18px;"><u>MEMQ: Is it working?</u></strong><br />
Add following line of code at the end of the above class file and hit the class file from your browser. You will get back inserted item id as response on the browser:</p>
<pre class="php" name="code">var_dump(MEMQ::enqueue($_GET['q'], time()));</pre>
<p>Lets see how cache keys looks like in memcached:</p>
<pre class="php" name="code">abhinavsingh@abhinavsingh-desktop:~$ telnet localhost 11211
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

get foo_head
VALUE foo_head 1 1
1
END

get foo_tail
VALUE foo_tail 1 1
2
END

get foo_1
VALUE foo_1 1 10
1265540583
END

get foo_2
VALUE foo_2 1 10
1265540585
END
</pre>
<p><strong style="font-size:18px;"><u>MEMQ: Benchmark</u></strong><br />
Below are the benchmarking results for varying load:</p>
<ol>
<li><u>Queuing performance:</u> 697.18 req/sec  (n=1000, c=100) and 258.64 req/sec (n=5000, c=500)</li>
<li><u>Dequeue performance:</u> 641.27 req/sec (n=1000, c=100) and 242.87 req/sec (n=5000, c=500)</li>
</ol>
<p><strong style="font-size:18px;"><u>MEMQ: Why and other alternatives</u></strong><br />
There are several open source alternatives which provide a lot more scalability. However, MEMQ was written because my application doesn&#8217;t expect a load in order of 10,000 hits/sec. Listed below are a few open source alternatives for applications expecting high load:</p>
<ol>
<li><u><a href="http://activemq.apache.org/">ActiveMQ</a>:</u> A reliable and fast solution under apache foundation</li>
<li><u><a href="http://www.rabbitmq.com/">RabbitMQ</a>:</u> Another reliable solution based on AMQP solution</li>
<li><u><a href="http://memcachedb.org/memcacheq/">Memcacheq</a>:</u> A mash-up of two very stable stacks namely memcached and berkleyDB. However, it&#8217;s installation is a bit tricky.</li>
</ol>
<p><strong style="font-size:18px;"><u>MEMQ: Mantra and Customization</u></strong><br />
At the base MEMQ implementation can be visualized as follows:</p>
<p>There is a race between two keys in memcached (foo_head and foo_tail). Both are incremented on every dequeue and queue operation respectively. However, foo_tail is strong enough and never allows foo_head to exceed. When value of keys foo_tail and foo_head are equal, queue is considered empty.</p>
<p>The above code file still doesn&#8217;t include utility methods like <code>MEMQ::total_items</code> etc. However, writing such methods should be pretty easy depending upon your application needs. Also depending upon your application requirement, you should also take care of overflowing integer values.</p>
<div id="paidTxtLinkAds">With our <a href="http://www.testking.org/642-436.htm">testking 642-436</a> php training, you will learn complete knowledge of different PHP functions using <a href="http://www.testking.org/642-845.htm">testking 642-845</a> dumps and <a href="http://www.testking.org/642-982.htm">testking 642-982</a> video tutorials.</div>
<script type="text/javascript">var wordpress_toolbar_urls = ["http:\/\/api.tweetmeme.com\/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2010%2F02%2Fmemq-fast-queue-implementation-using-memcached-and-php-only%2F","http:\/\/www.danga.com\/","http:\/\/github.com\/abhinavsingh\/memq","http:\/\/activemq.apache.org\/","http:\/\/www.rabbitmq.com\/","http:\/\/memcachedb.org\/memcacheq\/","http:\/\/www.testking.org\/642-436.htm","http:\/\/www.testking.org\/642-845.htm","http:\/\/www.testking.org\/642-982.htm"];var wordpress_toolbar_url = "http://abhinavsingh.com/blog/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "oinw";var wordpress_toolbar_hash = "aHR0cDovL2FiaGluYXZzaW5naC5jb20vYmxvZy8yMDEwLzAyL21lbXEtZmFzdC1xdWV1ZS1pbXBsZW1lbnRhdGlvbi11c2luZy1tZW1jYWNoZWQtYW5kLXBocC1vbmx5Lzx3cHRiPk1FTVEgOiBGYXN0IHF1ZXVlIGltcGxlbWVudGF0aW9uIHVzaW5nIE1lbWNhY2hlZCBhbmQgUEhQIG9ubHk8d3B0Yj5odHRwOi8vYWJoaW5hdnNpbmdoLmNvbS9ibG9nPHdwdGI%2BQWJoaSYjMDM5O3MgV2VibG9n";</script><ul class="related_post"><li><a href="http://abhinavsingh.com/blog/2010/01/wordpress-style-duplicate-comment-detected-using-memcached-and-php/" title="Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP">Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP</a> (8)</li><li><a href="http://abhinavsingh.com/blog/2009/12/how-to-use-locks-for-assuring-atomic-operation-in-memcached/" title="How to use locks for assuring atomic operation in Memcached?">How to use locks for assuring atomic operation in Memcached?</a> (9)</li><li><a href="http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/" title="Memcached and &quot;N&quot; things you can do with it &#8211; Part 1">Memcached and &quot;N&quot; things you can do with it &#8211; Part 1</a> (19)</li><li><a href="http://abhinavsingh.com/blog/2009/01/mysql-query-cache-wp-cache-apc-memcache-what-to-choose/" title="MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose">MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose</a> (43)</li><li><a href="http://abhinavsingh.com/blog/2010/08/php-code-setup-and-demo-of-jaxl-boshchat-application/" title="PHP Code, Setup and Demo of Jaxl boshchat application">PHP Code, Setup and Demo of Jaxl boshchat application</a> (80)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://abhinavsingh.com/blog/2010/02/memq-fast-queue-implementation-using-memcached-and-php-only/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>WordPress style &quot;Duplicate comment detected&quot; using Memcached and PHP</title>
		<link>http://abhinavsingh.com/blog/2010/01/wordpress-style-duplicate-comment-detected-using-memcached-and-php/</link>
		<comments>http://abhinavsingh.com/blog/2010/01/wordpress-style-duplicate-comment-detected-using-memcached-and-php/#comments</comments>
		<pubDate>Fri, 01 Jan 2010 19:00:04 +0000</pubDate>
		<dc:creator>Abhinav Singh</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Memcache]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Spam]]></category>

		<guid isPermaLink="false">http://abhinavsingh.com/blog/?p=558</guid>
		<description><![CDATA[If you have a knack of leaving comments on blogs, chances are you might have experienced a wordpress error page saying &#8220;Duplicate comment detected; it looks as though you’ve already said that!&#8220;, probably because you were not sure that your comment was saved last time and you tried to re-post your comment. In this blog [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2010%2F01%2Fwordpress-style-duplicate-comment-detected-using-memcached-and-php%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2010%2F01%2Fwordpress-style-duplicate-comment-detected-using-memcached-and-php%2F&amp;source=imoracle&amp;style=normal&amp;service=bit.ly&amp;service_api=R_f027b5a79a20a49b713f16282f1e0857&amp;hashtags=Memcache,PHP,Spam&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>If you have a knack of leaving comments on blogs, chances are you might have experienced a wordpress error page saying &#8220;<em>Duplicate comment detected; it looks as though you’ve already said that!</em>&#8220;, probably because you were not sure that your comment was saved last time and you tried to re-post your comment. In this blog post, I will put up some sample PHP code for Duplicate comment detection using Memcached without touching the databases. Towards the end, I will also discuss how the script can be modified for usage in any environment including forums and social networking websites.</p>
<p><strong style="font-size:18px;"><u>Duplicate comment detection using Memcached</u></strong><br />
Here is a php function called <code>is_repetitive_comment</code> which return some useful value if the comment is repetitive, otherwise FALSE.</p>
<pre class="php" name="code">&lt;?php

        define('COMPRESSION', 0);
        define('SIGNATURE_TTL', 60);

        $mem = new Memcache;
        $mem->addServer("localhost", 11211);

        function is_repetitive_comment($comment, $username) { // username can be ip address for anonymous env
                                                              // for per blog/forum checks pass forum id too
                                                              // for multi-host using same memcached instance, pass hostname too
                                                              // for restricting post of same comment, don't pass username
                $comment = trim($comment);
                $signature = md5(implode('',func_get_args()));

                global $mem;
                if(($value = $mem->get($signature)) !== FALSE) {
                        error_log($signature." found at ".time());
                        return $value;
                }
                else {
                        $value = array('comment' => $comment,
                                       'by' => $username,
                                       /* Other information if you may want to save */
                                      );
                        $mem->set($signature, $value, COMPRESSION, SIGNATURE_TTL);
                        error_log($signature." set at ".time());
                        return FALSE;
                }
        }

?&gt;</pre>
<p><strong style="font-size:18px;"><u>Is it working?</u></strong><br />
Lets verify the working of the code and then we will dig into the code:</p>
<ul>
<li>Save the sample code in a file, name it index.php</li>
<li>Towards the end of the script add following 3 line of code:
<pre class="php" name="code">        var_dump(is_repetitive_comment("User Comment", "username"));
        sleep(5); // Simulating the case when a user might try to post the same comment again knowingly or unknowingly
                  // Similar kind of check is done in wordpress comment submission (though without memcached)
        var_dump(is_repetitive_comment("User Comment", "username"));</pre>
</li>
<li>Run from command line:
<pre class="php" name="code">sabhinav$ php index.php
6105b67d969642fe9e27bc052f29e259 set at 1262393877
bool(false)
6105b67d969642fe9e27bc052f29e259 found at 1262393882
array(2) {
  ["comment"]=>
  string(12) "User Comment"
  ["by"]=>
  string(8) "username"
}</pre>
</li>
<li>As seen, function <code>is_repetitive_comment</code> returns bool(false) for the first time. However, after 5 seconds when same comment is being submitted it throws back some useful information from previous submission.</li>
</ul>
<p><strong style="font-size:18px;"><u>Working of is_repetitive_comment</u></strong><br />
Here is in brief, how memcached is used for duplicate comment detection by the script:</p>
<ul>
<li>SIGNATURE_TTL defines the time limit between two similar comment submissions. Default set to 60 seconds</li>
<li><code>is_repetitive_comment</code> takes two parameter namely the comment itself and the username of the user trying to post the comment.</li>
<li>The function create a signature by combining the passed parameters and checks whether a <code>key=$signature</code> exists in memcache</li>
<li>If key is found, it means same user has posted the same comment in past SIGNATURE_TTL i.e. 60 seconds. Function simply return back the value set for the key from memcache</li>
<li>However, if key is NOT found, user is allowed to post the comment by returning FALSE. However function also sets a key=$signature into memcache</li>
</ul>
<p>The value of key=$signature depends upon your application and use case. You might want to save some useful parameters so that you can show appropriate error message without hitting the databases for anything.</p>
<p><strong style="font-size:18px;"><u>Extracting more from the sample script</u></strong><br />
Here is how you can modify the above sample script for various environments:</p>
<ul>
<li>If you are performing repetitive comment check in an anonymous environment i.e. commenter may not be registered users, you can pass commenter&#8217;s ip address instead of username</li>
<li>If you serve multiple sites out of the same box and all share the same memcached instance, you SHOULD also pass site&#8217;s root url to the function. Otherwise you might end up showing error message to wrong users</li>
<li>If you want to restrict submission of same comment per blog or forum, also pass the blog id to the function</li>
<li>If you want to simply restrict submission of same comment through out your site, pass only the comment to the function</li>
</ul>
<p>Let me know if you do similar tiny little hacks using memcached <img src='http://abhinavsingh.com/blog/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<script type="text/javascript">var wordpress_toolbar_urls = ["http:\/\/api.tweetmeme.com\/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2010%2F01%2Fwordpress-style-duplicate-comment-detected-using-memcached-and-php%2F"];var wordpress_toolbar_url = "http://abhinavsingh.com/blog/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "oinw";var wordpress_toolbar_hash = "aHR0cDovL2FiaGluYXZzaW5naC5jb20vYmxvZy8yMDEwLzAxL3dvcmRwcmVzcy1zdHlsZS1kdXBsaWNhdGUtY29tbWVudC1kZXRlY3RlZC11c2luZy1tZW1jYWNoZWQtYW5kLXBocC88d3B0Yj5Xb3JkUHJlc3Mgc3R5bGUgJnF1b3Q7RHVwbGljYXRlIGNvbW1lbnQgZGV0ZWN0ZWQmcXVvdDsgdXNpbmcgTWVtY2FjaGVkIGFuZCBQSFA8d3B0Yj5odHRwOi8vYWJoaW5hdnNpbmdoLmNvbS9ibG9nPHdwdGI%2BQWJoaSYjMDM5O3MgV2VibG9n";</script><ul class="related_post"><li><a href="http://abhinavsingh.com/blog/2010/02/memq-fast-queue-implementation-using-memcached-and-php-only/" title="MEMQ : Fast queue implementation using Memcached and PHP only">MEMQ : Fast queue implementation using Memcached and PHP only</a> (17)</li><li><a href="http://abhinavsingh.com/blog/2009/12/how-to-use-locks-for-assuring-atomic-operation-in-memcached/" title="How to use locks for assuring atomic operation in Memcached?">How to use locks for assuring atomic operation in Memcached?</a> (9)</li><li><a href="http://abhinavsingh.com/blog/2009/10/web-security-using-crumbs-to-protect-your-php-api-ajax-call-from-cross-site-request-forgery-csrfxsrf-and-other-vulnerabilities/" title="Web Security : Using crumbs to protect your PHP API (Ajax) call from Cross-site request forgery (CSRF/XSRF) and other vulnerabilities">Web Security : Using crumbs to protect your PHP API (Ajax) call from Cross-site request forgery (CSRF/XSRF) and other vulnerabilities</a> (13)</li><li><a href="http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/" title="Memcached and &quot;N&quot; things you can do with it &#8211; Part 1">Memcached and &quot;N&quot; things you can do with it &#8211; Part 1</a> (19)</li><li><a href="http://abhinavsingh.com/blog/2009/01/mysql-query-cache-wp-cache-apc-memcache-what-to-choose/" title="MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose">MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose</a> (43)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://abhinavsingh.com/blog/2010/01/wordpress-style-duplicate-comment-detected-using-memcached-and-php/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>How to build a custom static file serving HTTP server using Libevent in C</title>
		<link>http://abhinavsingh.com/blog/2009/12/how-to-build-a-custom-static-file-serving-http-server-using-libevent-in-c/</link>
		<comments>http://abhinavsingh.com/blog/2009/12/how-to-build-a-custom-static-file-serving-http-server-using-libevent-in-c/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 20:06:36 +0000</pubDate>
		<dc:creator>Abhinav Singh</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Libevent]]></category>

		<guid isPermaLink="false">http://abhinavsingh.com/blog/?p=555</guid>
		<description><![CDATA[Libevent is an event notification library which lays the foundation for immensely successful open source projects like Memcached. As the web advances into a real time mode, more and more websites are using a mix of technologies like HTTP Pub-Sub, HTTP Long-polling and Comet with a custom light weight HTTP servers in the backend to [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F12%2Fhow-to-build-a-custom-static-file-serving-http-server-using-libevent-in-c%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F12%2Fhow-to-build-a-custom-static-file-serving-http-server-using-libevent-in-c%2F&amp;source=imoracle&amp;style=normal&amp;service=bit.ly&amp;service_api=R_f027b5a79a20a49b713f16282f1e0857&amp;hashtags=Libevent&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Libevent is an event notification library which lays the foundation for immensely successful open source projects like Memcached. As the web advances into a real time mode, more and more websites are using a mix of technologies like HTTP Pub-Sub, HTTP Long-polling and Comet with a custom light weight HTTP servers in the backend to create a real time user experience. In this blog post, I will start with necessary prerequisites for setting up the development environment. Further, I will demonstrate how to build a HTTP server capable of serving static pages. Finally, I will put up a few use cases of a custom HTTP server in today&#8217;s world.</p>
<p><strong style="font-size:18px;"><u>Setting up Environment</u></strong><br />
Follow the following steps to install the latest version of libevent (version <a href="http://www.monkey.org/~provos/libevent/doxygen-2.0.1/">2.0.3-alpha</a>)</p>
<ul>
<li>$ wget http://www.monkey.org/~provos/libevent-2.0.3-alpha.tar.gz</li>
<li>$ tar -xvzf libevent-2.0.3-alpha.tar.gz</li>
<li>$ cd libevent-2.0.3-alpha.tar.gz</li>
<li>./configure</li>
<li>make</li>
<li>sudo make install</li>
</ul>
<p>Check the environment by running the following piece of C code (<code>event2.cpp</code>):</p>
<pre class="c" name="code">#include &lt;event2/event.h&gt;

int main(int argc, char **argv) {
	const char *version;
	version = event_get_version();
	printf("%s\n", version);
	return 0;
}</pre>
<p>Compile and run as following:</p>
<pre class="c" name="code">$ g++ -arch x86_64 -Wall -levent event2.cpp -o event2
$ ./event2
$ 2.0.3-alpha</pre>
<p>I had to pass <code>-arch x86_64</code> flags on Mac OSX 10.5.8. This can vary depending upon your operating system.</p>
<p><strong style="font-size:18px;"><u>Libsrvr: Static file serving HTTP Server</u></strong><br />
Below is the C code for a static file serving HTTP server using libevent called <strong>&#8220;Libsrvr&#8221;</strong>:</p>
<p><strong><u>libsrvr.h</u></strong></p>
<pre class="c" name="code">// General purpose header files
#include &lt;iostream&gt;
#include &lt;getopt.h&gt;
#include &lt;sys/stat.h&gt;

// Libevent header files
#include &lt;/usr/local/include/event2/event.h&gt;
#include &lt;/usr/local/include/event2/http.h&gt;
#include &lt;/usr/local/include/event2/buffer.h&gt;

// Libsrvr configuration settings
#define LIBSRVR_SIGNATURE "libsrvr v 0.0.1"
#define LIBSRVR_HTDOCS "/Users/sabhinav/libsrvr/www"
#define LIBSRVR_INDEX "/index.html"

// Libsrvr http server and base struct
struct evhttp *libsrvr;
struct event_base *libbase;

// Libsrvr options
struct _options {
	int port;
	char *address;
	int verbose;
} options;</pre>
<ul>
<li>LIBSRVR_SIGNATURE is the server signature sent as response header for all incoming requests</li>
<li>LIBSRVR_HTDOCS is the path to the the DocumentRoot for libsrvr</li>
<li>LIBSRVR_INDEX is the similar to DirectoryIndex directive of apache</li>
</ul>
<p><strong><u>libsrvr.cpp</u></strong></p>
<pre class="c" name="code">#include &lt;/Users/sabhinav/libsrvr/libsrvr.h&gt;

void router(struct evhttp_request *r, void *arg) {
	const char *uri = evhttp_request_get_uri(r);

	char *static_file = (char *) malloc(strlen(LIBSRVR_HTDOCS) + strlen(uri) + strlen(LIBSRVR_INDEX) + 1);
	stpcpy(stpcpy(static_file, LIBSRVR_HTDOCS), uri);

	bool file_exists = true;
	struct stat st;
	if(stat(static_file, &#038;st) == -1) {
		file_exists = false;
		evhttp_send_error(r, HTTP_NOTFOUND, "NOTFOUND");
	}
	else {
		if(S_ISDIR(st.st_mode)) {
			strcat(static_file, LIBSRVR_INDEX);

			if(stat(static_file, &#038;st) == -1) {
				file_exists = false;
				evhttp_send_error(r, HTTP_NOTFOUND, "NOTFOUND");
			}
		}
	}

	if(file_exists) {
		int file_size = st.st_size;

		char *html;
		html = (char *) alloca(file_size);

		if(file_size != 0) {
			FILE *fp = fopen(static_file, "r");
			fread(html, 1, file_size, fp);
			fclose(fp);
		}

		struct evbuffer *buffer;
		buffer = evbuffer_new();

		struct evkeyvalq *headers = evhttp_request_get_output_headers(r);
		evhttp_add_header(headers, "Content-Type", "text/html; charset=UTF-8");
		evhttp_add_header(headers, "Server", LIBSRVR_SIGNATURE);

		evbuffer_add_printf(buffer, "%s", html);
		evhttp_send_reply(r, HTTP_OK, "OK", buffer);
		evbuffer_free(buffer);

		if(options.verbose) fprintf(stderr, "%s\t%d\n", static_file, file_size);
	}
	else {
		if(options.verbose) fprintf(stderr, "%s\t%s\n", static_file, "404 Not Found");
	}

	free(static_file);
}

int main(int argc, char **argv) {
	int opt;

	options.port = 4080;
	options.address = "0.0.0.0";
	options.verbose = 0;

	while((opt = getopt(argc,argv,"p:vh")) != -1) {
		switch(opt) {
			case 'p':
				options.port = atoi(optarg);
				break;
			case 'v':
				options.verbose = 1;
				break;
			case 'h':
				printf("Usage: ./libsrvr -p port -v[erbose] -h[elp]\n");
				exit(1);
		}
	}

	libbase = event_base_new();
	libsrvr = evhttp_new(libbase);
	evhttp_bind_socket(libsrvr, options.address, options.port);
	evhttp_set_gencb(libsrvr, router, NULL);
	event_base_dispatch(libbase);

	return 0;
}</pre>
<p>Here is some explanation for the above code:</p>
<ul>
<li>Command line options are parsed using GNU <a href="http://www.gnu.org/s/libc/manual/html_node/Getopt.html">getopt</a> library</li>
<li><code>libbase</code> is the event base for HTTP server <code>libsrvr</code>.</li>
<li>HTTP server is bind to port 4080 (by default).</li>
<li>A callback function is registered for each incoming HTTP request to libsrvr. Function <code>router</code> is invoked every time a HTTP request is received</li>
<li>Finally <code>libbase</code> is dispatched and code never reaches <code>return 0</code></li>
</ul>
<p>The working of the <code>router</code> function is as follows:</p>
<ul>
<li>Incoming request uri is converted to absolute file path on the system</li>
<li>Checks for file or directory existence is done</li>
<li>If absolute path is a directory, LIBSRVR_INDEX is served out of that directory</li>
</ul>
<p><strong style="font-size:18px;"><u>Launching Libsrvr:</u></strong><br />
Compile and run the libsrvr as follows:</p>
<pre class="c" name="code">$ g++ -arch x86_64 -Wall -levent libsrvr.cpp -o libsrvr
$ ./libsrvr -v
/Users/sabhinav/libsrvr/www//index.html	538
/Users/sabhinav/libsrvr/www/assets/style.css	35
/Users/sabhinav/libsrvr/www/assets/script.js	27
/Users/sabhinav/libsrvr/www/dummy	404 Not Found
/Users/sabhinav/libsrvr/www/index.html	538
/Users/sabhinav/libsrvr/www/assets/style.css	35
</pre>
<p>If started under verbose mode (-v), libsrvr will output each requested file path on the console as shown above.</p>
<p><strong style="font-size:18px;"><u>Use cases</u></strong><br />
Below are a few use cases of a custom HTTP server as seen in web today:</p>
<ul>
<li><u>Facebook Chat</u>: Uses a custom http server based on <a href="http://code.google.com/p/mochiweb/">mochiweb</a> framework</li>
<li><u>Yahoo finance</u>: Uses a custom http streaming server based on libevent</li>
</ul>
<p>Generally, iframe technique is combined with javascript hacks for streaming data from the custom http servers. Read &#8220;<a href="http://abhinavsingh.com/blog/2009/11/making-cross-sub-domain-ajax-xhr-requests-using-mod_proxy-and-iframes/">How to make cross-sub-domain ajax (XHR) requests using mod_proxy and iframes</a>&#8221; for details.</p>
<p><strong style="font-size:18px;"><u>Conclusion</u></strong><br />
Though a static file server find little place in today&#8217;s world, the idea was to show the ease by which you can create your own HTTP server which is light weight, fast and scalable (all thanks to <a href="http://www.citi.umich.edu/u/provos/">Niels</a> for his libevent). Couple libsrvr with memcached for caching static files, and benchmark will show over <code>10,000 req/sec</code> handling capability of libsrvr.</p>
<p>Share if you like it and also let me know your thoughts through comments.</p>
<script type="text/javascript">var wordpress_toolbar_urls = ["http:\/\/api.tweetmeme.com\/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F12%2Fhow-to-build-a-custom-static-file-serving-http-server-using-libevent-in-c%2F","http:\/\/www.monkey.org\/~provos\/libevent\/doxygen-2.0.1\/","http:\/\/www.gnu.org\/s\/libc\/manual\/html_node\/Getopt.html","http:\/\/code.google.com\/p\/mochiweb\/","http:\/\/www.citi.umich.edu\/u\/provos\/"];var wordpress_toolbar_url = "http://abhinavsingh.com/blog/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "oinw";var wordpress_toolbar_hash = "aHR0cDovL2FiaGluYXZzaW5naC5jb20vYmxvZy8yMDA5LzEyL2hvdy10by1idWlsZC1hLWN1c3RvbS1zdGF0aWMtZmlsZS1zZXJ2aW5nLWh0dHAtc2VydmVyLXVzaW5nLWxpYmV2ZW50LWluLWMvPHdwdGI%2BSG93IHRvIGJ1aWxkIGEgY3VzdG9tIHN0YXRpYyBmaWxlIHNlcnZpbmcgSFRUUCBzZXJ2ZXIgdXNpbmcgTGliZXZlbnQgaW4gQzx3cHRiPmh0dHA6Ly9hYmhpbmF2c2luZ2guY29tL2Jsb2c8d3B0Yj5BYmhpJiMwMzk7cyBXZWJsb2c%3D";</script><ul class="related_post"><li><a href="http://abhinavsingh.com/blog/2009/11/writing-a-custom-unix-style-tail-in-php-using-libevent-api-on-mac-os-x-10-5-x-and-other-platforms/" title="Writing a custom unix style tail in PHP using Libevent API on Mac OS X 10.5.x and other platforms">Writing a custom unix style tail in PHP using Libevent API on Mac OS X 10.5.x and other platforms</a> (16)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://abhinavsingh.com/blog/2009/12/how-to-build-a-custom-static-file-serving-http-server-using-libevent-in-c/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>How to use locks for assuring atomic operation in Memcached?</title>
		<link>http://abhinavsingh.com/blog/2009/12/how-to-use-locks-for-assuring-atomic-operation-in-memcached/</link>
		<comments>http://abhinavsingh.com/blog/2009/12/how-to-use-locks-for-assuring-atomic-operation-in-memcached/#comments</comments>
		<pubDate>Sat, 05 Dec 2009 13:08:19 +0000</pubDate>
		<dc:creator>Abhinav Singh</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Memcache]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://abhinavsingh.com/blog/?p=560</guid>
		<description><![CDATA[Memcached provide atomic increment and decrement commands to manipulate integer (key,value) pairs. However special care should be taken to ensure application performance and possible race conditions while using memcached. In this blog post, I will first build a facebook style &#8220;like&#8221; application using atomic increment command of memcached. Also, I will discuss various technical difficulty [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F12%2Fhow-to-use-locks-for-assuring-atomic-operation-in-memcached%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F12%2Fhow-to-use-locks-for-assuring-atomic-operation-in-memcached%2F&amp;source=imoracle&amp;style=normal&amp;service=bit.ly&amp;service_api=R_f027b5a79a20a49b713f16282f1e0857&amp;hashtags=Memcache,PHP&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Memcached provide atomic increment and decrement commands to manipulate integer (key,value) pairs. However special care should be taken to ensure application performance and possible race conditions while using memcached. In this blog post, I will first build a facebook style &#8220;like&#8221; application using atomic <code>increment</code> command of memcached. Also, I will discuss various technical difficulty one would face while ensuring atomicity in this application. Finally, I will demo how to ensure atomicity over a requested process using custom locks in memcached.</p>
<p><strong style="font-size:18px;"><u>Where should I care about it?</u></strong><br />
Lets consider a sample application as depicted by the flow diagram below:<br />
<img src="http://abhinavsingh.com/blog/wp-content/uploads/2009/12/Slide2.jpg" alt="Facebook style &quot;like&quot; demo architecture using &quot;memcached&quot;" title="Facebook style &quot;like&quot; demo architecture using &quot;memcached&quot;" width="540" class="aligncenter size-full wp-image-562" /></p>
<p>The above application is similar to facebook &#8220;like&#8221; feature. In brief, we maintain a key per post e.g. <code>$key="post_id_1234_likes_count"</code>, storing count of users who liked this post. Another <code>$key="post_id_1234_user_id_9999"</code>, stores user_id_9999 relationship with post_id_1234. Example, &#8220;liked&#8221; which is set to 1 if liked and &#8220;timestamp&#8221; which is the time when user liked this post.</p>
<p>Since this application is going to reside on a high traffic website, earlier design decisions are made to have memcached in-front of MySQL database and will act as the primary storage medium with periodic syncs to the database. For me a like/dislike functionality is not so important as compared to other social functionality on my website.</p>
<p>Here is a sample code for the above functionality:</p>
<pre class="php" name="code">	$mem = new Memcache;
	$mem->addServer("127.0.0.1", 11211);

	function incrementLikeCount($post_id) {
		global $mem;

		// prepare post key
		$key = "post_id_".$post_id."_likes_count";

		// get old count
		$old_count = $mem->get($key);

		// false means no one liked this post before
		if($old_count === FALSE) $old_count = 0;

		// increment count
		$new_count = $old_count+1;

		// set new count value
		if($mem->set($key, $new_count, 0, 0)) {
			error_log("Incremented key ".$key." to ".$new_count);
			return TRUE;
		}
		else {
			error_log("Error occurred in incrementing key ".$key);
			return FALSE;
		}
	}

	// get incoming parameters
	$post_id = $_GET['post_id'];

	// take action
	incrementLikeCount($post_id);</pre>
<p><strong style="font-size:18px;"><u>Why should I care about it?</u></strong><br />
Save the above code sample in a file called <code>memcached_no_lock.php</code> and hit the url http://localhost/memcached_no_lock.php?post_id=1234 five times. Verify the key value in memcached:</p>
<pre class="php" name="code">centurydaily-lm:Workspace sabhinav$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
get post_id_1234_likes_count
VALUE post_id_1234_likes_count 0 2
5
END
</pre>
<p>Alright, application seems to give expected results. Next, lets verify this application for high traffic websites using apache benchmark:</p>
<pre class="php" name="code">centurydaily-lm:Workspace sabhinav$ ab -n 100 -c 10 http://localhost/memcached_no_lock.php?post_id=1234
Concurrency Level:      10
Time taken for tests:   0.090 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      22200 bytes
HTML transferred:       0 bytes
Requests per second:    1112.03 [#/sec] (mean)
</pre>
<p>Verify the key value in memcached:</p>
<pre class="php" name="code">centurydaily-lm:Workspace sabhinav$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
get post_id_1234_likes_count
VALUE post_id_1234_likes_count 0 2
36
END
</pre>
<p>What happened? We expected value for <code>$key="post_id_1234_likes_count"</code> to reach 100, but actually it is 36. What went wrong? This behavior can be explained by simply looking at the apache error log file:</p>
<pre class="php" name="code">[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 1
[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 1
[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 1
[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 2
[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 2
[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 3
[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 3
[Sat Dec 05 14:32:08 2009] [error] [client ::1] Incremented key post_id_1234_likes_count to 3</pre>
<p>Ohk, from above log we understand concurrency killed our application, since we see $key being incremented to the same value by more than 1 incoming request.</p>
<p><strong style="font-size:18px;"><u>How should I take care of this?</u></strong><br />
Below is the modified code sample which will allow us atomic increments:</p>
<pre class="php" name="code">	$mem = new Memcache;
	$mem->addServer("127.0.0.1", 11211);

	function incrementLikeCount($post_id) {
		global $mem;

		// prepare post key
		$key = "post_id_".$post_id."_likes_count";

		$new_count = $mem->increment($key, 1);
		if($new_count === FALSE) {
			$new_count = $mem->add($key, 1, 0, 0);
			if($new_count === FALSE) {
				error_log("Someone raced us for first count on key ".$key);
				$new_count = $mem->increment($key, 1);
				if($new_count === FALSE) {
					error_log("Unable to increment key ".$key);
					return FALSE;
				}
				else {
					error_log("Incremented key ".$key." to ".$new_count);
					return TRUE;
				}
			}
			else {
				error_log("Initialized key ".$key." to ".$new_count);
				return TRUE;
			}
		}
		else {
			error_log("Incremented key ".$key." to ".$new_count);
			return TRUE;
		}

	}

	// get incoming parameters
	$post_id = $_GET['post_id'];

	// take action
	incrementLikeCount($post_id);</pre>
<p>To ensure atomicity, we start with incrementing the <code>$key="post_id_1234_likes_count"</code>. Since memcached <code>increment()</code> is atomic by itself, we need not put any locking mechanism in here. However, memcached increment returns FALSE, if the $key doesn&#8217;t already exists.</p>
<p>Hence, if we get a FALSE response from the first increment, we will try to initialize $key using memcached <code>add()</code> command. Good thing about memcached add is that, it will return a false FALSE, if the $key is already present. Hence, if more than one thread is trying to initialize $key, only one of them will succeed. All the rest of the threads will return FALSE for add command. Finally, if the response is FALSE from the first add, we will try to increment the $key again.</p>
<p>Lets try to test this modified code with apache benchmark. Also, this time we will increase concurrency from 10 to 100 threads. Save the above modified code in a file called <code>memcached_lock.php</code> and issue the following <code>ab</code> command:</p>
<pre class="php" name="code">centurydaily-lm:Workspace sabhinav$ ab -n 10000 -c 100 http://localhost/memcached_lock.php?post_id=1234
Concurrency Level:      100
Time taken for tests:   11.006 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      2224884 bytes
HTML transferred:       0 bytes
Requests per second:    908.61 [#/sec] (mean)
</pre>
<p>Lets verify the key value inside memcached:</p>
<pre class="php" name="code">centurydaily-lm:Workspace sabhinav$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
get post_id_1234_likes_count
VALUE post_id_1234_likes_count 0 5
10000
END
</pre>
<p>Bingo! As desired we have a value of 10000 for $key inside memcached.</p>
<p><strong style="font-size:18px;"><u>Using custom locks for atomicity:</u></strong><br />
There can be many instances where you SHOULD try to process a request atomically using locks. For e.g. while trying to fetch a query from database or while trying to regenerate a requested page template in your <a href="http://abhinavsingh.com/blog/2009/08/building-a-custom-php-framework-with-a-custom-template-caching-engine-using-output-control-functions">custom template caching engine</a>.</p>
<p>In the example below, I will modify the memcached_lock.php script to ensure atomic increments without using increment command. Instead I will use custom locks using memcached:</p>
<pre class="php" name="code">	$mem = new Memcache;
	$mem->addServer("127.0.0.1", 11211);

	function incrementLikeCount($post_id) {
		global $mem;

		// prepare post key
		$key = "post_id_".$post_id."_likes_count";

		// initialize lock
		$lock = FALSE;

		// initialize configurable parameters
		$tries = 0;
		$max_tries = 1000;
		$lock_ttl = 10;

		$new_count = $mem->get($key); // fetch older value
	    while($lock === FALSE &#038;&#038; $tries < $max_tries) {
	    	if($new_count === FALSE) $new_count = 0;
	        $new_count = $new_count + 1;

			// add() will return false if someone raced us for this lock
                       // ALWAYS USE add() FOR CUSTOM LOCKS
	        $lock = $mem->add("lock_".$new_count, 1, 0, $lock_ttl);

			$tries++;
			usleep(100*($tries%($max_tries/10))); // exponential backoff style of sleep
		}

		if($lock === FALSE &#038;&#038; $tries >= $max_tries) {
			error_log("Unable to increment key ".$key);
			return FALSE;
		}
		else {
	    	$mem->set($key, $new_count, 0, 0);
			error_log("Incremented key ".$key." to ".$new_count);
			return TRUE;
		}

	}

	// get incoming parameters
	$post_id = $_GET['post_id'];

	// take action
	incrementLikeCount($post_id);</pre>
<p>Try testing it using apache benchmark as above and then verify it with memcached.</p>
<pre class="php" name="code">centurydaily-lm:Workspace sabhinav$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
get post_id_1234_likes_count
VALUE post_id_1234_likes_count 0 3
100
END
</pre>
<p><strong style="font-size:18px;"><u>Benchmarks:</u></strong><br />
We see a drop in performance from 1112 hits/sec (memcached_no_lock) to 908 hits/sec (memcached_lock using increment). This is majorly because of increased concurrency. At same concurrency level of 10, I received a performance benchmark of 1128 hits/sec with our thread protected code. However, for our custom lock code above, I received a performance benchmark of 275 hits/sec.</p>
<p><strong style="font-size:18px;"><u>Conclusion:</u></strong><br />
Always use memcached increment/decrement while dealing with locks on integer valued keys. For achieving locks on a process, use custom locks as demoed above using memcached add command. Also custom locks are subjected to configurable options like <code>$max_tries</code> and others.</p>
<p>Hope you enjoyed reading.<br />
Do let me know through your comments.</p>
<script type="text/javascript">var wordpress_toolbar_urls = ["http:\/\/api.tweetmeme.com\/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F12%2Fhow-to-use-locks-for-assuring-atomic-operation-in-memcached%2F"];var wordpress_toolbar_url = "http://abhinavsingh.com/blog/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "oinw";var wordpress_toolbar_hash = "aHR0cDovL2FiaGluYXZzaW5naC5jb20vYmxvZy8yMDA5LzEyL2hvdy10by11c2UtbG9ja3MtZm9yLWFzc3VyaW5nLWF0b21pYy1vcGVyYXRpb24taW4tbWVtY2FjaGVkLzx3cHRiPkhvdyB0byB1c2UgbG9ja3MgZm9yIGFzc3VyaW5nIGF0b21pYyBvcGVyYXRpb24gaW4gTWVtY2FjaGVkPzx3cHRiPmh0dHA6Ly9hYmhpbmF2c2luZ2guY29tL2Jsb2c8d3B0Yj5BYmhpJiMwMzk7cyBXZWJsb2c%3D";</script><ul class="related_post"><li><a href="http://abhinavsingh.com/blog/2010/02/memq-fast-queue-implementation-using-memcached-and-php-only/" title="MEMQ : Fast queue implementation using Memcached and PHP only">MEMQ : Fast queue implementation using Memcached and PHP only</a> (17)</li><li><a href="http://abhinavsingh.com/blog/2010/01/wordpress-style-duplicate-comment-detected-using-memcached-and-php/" title="Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP">Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP</a> (8)</li><li><a href="http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/" title="Memcached and &quot;N&quot; things you can do with it &#8211; Part 1">Memcached and &quot;N&quot; things you can do with it &#8211; Part 1</a> (19)</li><li><a href="http://abhinavsingh.com/blog/2009/01/mysql-query-cache-wp-cache-apc-memcache-what-to-choose/" title="MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose">MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose</a> (43)</li><li><a href="http://abhinavsingh.com/blog/2010/08/php-code-setup-and-demo-of-jaxl-boshchat-application/" title="PHP Code, Setup and Demo of Jaxl boshchat application">PHP Code, Setup and Demo of Jaxl boshchat application</a> (80)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://abhinavsingh.com/blog/2009/12/how-to-use-locks-for-assuring-atomic-operation-in-memcached/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Memcached and &quot;N&quot; things you can do with it &#8211; Part 1</title>
		<link>http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/</link>
		<comments>http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 09:36:11 +0000</pubDate>
		<dc:creator>Abhinav Singh</dc:creator>
				<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Memcache]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://abhinavsingh.com/blog/?p=186</guid>
		<description><![CDATA[In my last post MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose, I discussed in brief about 4 caching technologies which you might have used knowingly or unknowingly. Towards the end we came to a conclusion that memcached is the best caching solution when you are looking for speed and number of hits [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F01%2Fmemcached-and-n-things-you-can-do-with-it%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F01%2Fmemcached-and-n-things-you-can-do-with-it%2F&amp;source=imoracle&amp;style=normal&amp;service=bit.ly&amp;service_api=R_f027b5a79a20a49b713f16282f1e0857&amp;hashtags=Debian,Facebook,Memcache,PHP,Ubuntu,Windows&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>In my last post <a target="_blank" href="http://abhinavsingh.com/blog/2009/01/mysql-query-cache-wp-cache-apc-memcache-what-to-choose/">MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose</a>, I discussed in brief about 4 caching technologies which you might have used knowingly or unknowingly.</p>
<p>Towards the end we came to a conclusion that memcached is the best caching solution when you are looking for speed and number of hits per second. By my experience, memcached is capable of handling more than a 100 Million PV&#8217;s per month without any problem. However, towards the end I did also discussed why memcached is unreliable and unsecure.</p>
<p>In this post I will dig a level deeper into memcached. For ease here is the so called table of content:</p>
<ol>
<li><strong>Basics:</strong> Memcached &#8211; Revisited</li>
<li><strong>Code Sample:</strong> A memcached class and how to use it</li>
<li><strong>N things:</strong> What else can I do with memcached</li>
<li><strong>Case Study:</strong> How Facebook uses memcached</li>
<li><strong>DONT&#8217;s:</strong> A few things to be taken care</li>
</ol>
<p><strong style="font-size:18px;"><u>Basics: Memcached &#8211; Revisited</u></strong><br />
Memcached was developed by <a target="_blank" href="http://bradfitz.com/">Brad</a> when live journal was hitting more than 20 Million PV&#8217;s per day. Handling 20 Million PV&#8217;s was no joke and he needed a better solution to handle such a high traffic. Since most of the blogs doesn&#8217;t change once published, he thought of having a model where he can skip the database read for the same posts again and again or atleast reduce the number of database reads. And hence came Memcached. Memcached is a deamon which runs in the background. By deamon you may think of a process running in the background doing its job.</p>
<p>If you are using ubuntu or debian like me, here are the steps for installing memcached:</p>
<ol>
<li>sudo apt-get install php5-memcache</li>
<li>Go to <em>/etc/php5/conf.d/memcache.ini</em> and uncomment the line <em>;extension=memcache.so</em> to enable this module</li>
<li>sudo pecl install memcache</li>
<li>Go to php.ini file and add this line: <em>extension=memcache.so</em></li>
<li>sudo apt-get install memcached</li>
<li>sudo /etc/init.d/memcached start</li>
<li>Restart Apache</li>
</ol>
<p>If you are on windows, here are the steps which will help you running memcached on windows machine:</p>
<ol>
<li>Download the memcached win32 binary from my <a href="http://code.google.com/p/abhinavsingh/source/browse/trunk/Memcached/memcache-1.2.5/memcached-1.2.5-win32-bin.zip" target="_blank">code.google</a> vault.</li>
<li>Unzip the downloaded file under <em>C:\memcached</em></li>
<li>As we need to install memcached as a service, run this from a command line: <em>C:\memcached\memcached.exe -d install</em> from the command line</li>
<li>Memcache by default loads with 64Mb of memory which is just not sufficient enough. Navigate to <em>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\memcached Server</em> in your registry and find the ImagePath entry. Change that to <em>&#8220;C:\memcached\memcached.exe&#8221; -d runservice -m 512</em></li>
<li>Start the server by running this command: <em>C:\memcached\memcached.exe -d start</em></li>
<li>Open folder C:\PHP\ext and check for <em>php_memcache.dll</em>. If you are unlucky not to have that download from <a href="http://code.google.com/p/abhinavsingh/source/browse/trunk/Memcached/dlls/php-4.x/php_memcache.dll" target="_blank">here for PHP-4.x</a> and from <a href="http://code.google.com/p/abhinavsingh/source/browse/trunk/Memcached/dlls/php-5.x/php_memcache.dll" target="_blank">here for PHP-5.x</a></li>
<li>Add <em>extension=php_memcache.dll</em> in your php.ini file</li>
<li>Restart Apache</li>
<li>Download the <a target="_blank" href="http://abhinavsingh.googlecode.com/files/svn-trunk-Memcached.rar">full package</a> consisting of exe&#8217;s, classes and dll&#8217;s from here.</li>
</ol>
<p>A few other options which you can use for starting memcached are:<br />
<em>memcached -d -m 2048 -l 10.0.0.40 -p 11211</em> , This will start memcached as a daemon, using 2GB of memory, and listening on IP 10.0.0.40, port 11211. Port 11211 is the default port for memcached.</p>
<p>By now I assume you have a <img src='http://abhinavsingh.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  on your face, because you have memcached deamon running on your machine. Windows users can check that by opening up the task manager and looking for a memcached.exe process. I don&#8217;t see any reason for you not smiling, but if in case you are that unlucky windows user, please leave that system and move to a unix machine. Atleast try running Ubuntu on windows by reading this post of mine <a target="_blank" href="http://abhinavsingh.com/blog/2008/05/how-to-configure-ubuntu-and-lamp-on-windows/">How to configure Ubuntu and LAMP on Windows</a>.</p>
<p><strong style="font-size:18px;"><u>Code Sample: Memcached class</u></strong><br />
So we have memcached setup on our system. Now we will try to hook up a simple code with it, which will do all the necessary talking with the deamon. Below I will demonstrate a very basic and simple application which will help you getting started. This application contains a total of 5 files namely: database.class.php, memcache.class.php, log.class.php, index.php, memcacheExtendedStats.php.</p>
<p><strong>log.class.php</strong><br />
This is a very basic logger class which will log every thing for you to inspect later. Here is the code:</p>
<pre name="code" class="php">
  class logAPI {
    var $LogFile = "log.txt";

    function Logger($Log) {
      $fh = fopen($this->LogFile,"a");
      fwrite($fh,$Log);
      fclose($fh);
    }
  }
</pre>
<p>When ever the code connects with memcached deamon, or database or fail to connect to either of them , this class will log the appropriate message in <em>log.txt</em></p>
<p><strong>database.class.php</strong><br />
This is another basic database class which have methods like <em>getData()</em> and <em>setData()</em>. <em>getData()</em> is used while trying to retrieve rows from the database while <em>setData()</em> is used while updating or inserting new rows in the database. For this demo application we will only be using the <em>getData()</em> method. Here is the code:</p>
<pre name="code" class="php">
  include_once("memcache.class.php");
  include_once("log.class.php");

  class databaseAPI {

    /************************/
    /** Database information **/
    /************************/
    var $dbhost = "localhost";
    var $dbuser = "root";
    var $dbpass = "";
    var $dbname = "gtalkbots";
    var $db = NULL;

    /******************************/
    // CONSTRUCTOR DEFINITION //
    /******************************/
    function __construct() {
      $this->connect();
    }

    /*************************************************/
    // Function establishes a connection to database //
    /*************************************************/
    function connect() {
      // Connect to the dbhost
      $connection = mysql_connect($this->dbhost,$this->dbuser,$this->dbpass) or die(mysql_error());

	  // If connection fails send a mail to $dbmail about the same
      if(!$connection) {
        echo "Failed to establish a connection to host";
        exit;
      }
      else {
        // Connect to dbname
        $database = @mysql_select_db($this->dbname);

	// If fails to connect to the database send a mail to $dbmail
        if(!$database) {
          echo "Failed to establish a connection to database";
          exit;
        }
        else {
          $this->db = $connection;
        }
      }
    }

    /*******************************************/
    // Function closes the database connection //
    /*******************************************/
    function close() {
      mysql_close($this->db);
    }

    /***********************************************************/
    // Function executes the query against database and returns the result set   //
    // Result returned is in associative array format, and then frees the result //
    /***********************************************************/
    function getData($query,$options=array("type"=>"array","cache"=>"on"),$resultset="") {
        // Lookup on memcache servers if cache is on
	if($options['cache'] == "on") {
	    $obj = new memcacheAPI();
	    if($obj->connect()) {
	        // Try to fetch from memcache server if present
		$resultset = $obj->getCache($query);
	    }
    	    else {
	        // Fetch query from the database directly
	    }
	}
	// If $resultset == "" i.e. either caching is off or memcache server is down
        // OR $resultset == null i.e. when $query is not cached
	if($resultset == "" || $resultset == null) {
	    $result = mysql_query($query,$this->db);
	    if($result) {
		if($options['type'] == "original") {
		    // Return the original result set, if passed options request for the same
		    $resultset = $result;
		}
                else if($options['type'] == "array") {
	            // Return the associative array and number of rows
	    	    $mysql_num_rows = mysql_num_rows($result);
		    $result_arr = array();
		    while($info = mysql_fetch_assoc($result)) {
		        array_push($result_arr,$info);
		    }
		    $resultset = array("mysql_num_rows" => $mysql_num_rows,"result" => $result_arr,"false_query" => "no");
		}
  		// Cache the $query and $resultset
		$obj->setCache($query,$resultset);
		$obj->close();
		return $resultset;

                // Free the memory
		mysql_free_result($result);
            }
            else {
	        $resultset = array("false_query" => "yes");
	        return $resultset;
            }
	}
	else {
	    // If $query was found in the cache, simple return it
	    $obj->close();
	    return $resultset;
	}
    }

    /**********************************************************/
    // Function executes the query against database (INSERT, UPDATE) types   //
    /************************************************************/
    function setData($query) {
      // Run the query
      $result = mysql_query($query,$this->db);
      // Return the result
      return array('result'=>$result,'mysql_affected_rows'=>mysql_affected_rows());
    }

  }
</pre>
<p><strong>memcache.class.php</strong><br />
Memcache class consists of two methods: getCache() and setCache(). getCache() will look up for the (key,value) pair in memory. If it exists, the method unserialize it and returns back. setCache() is used to set (key,value) pair in memory. It accepts the key and value, serialize the value before storing in cache.</p>
<pre name="code" class="php">
  class memcacheAPI {

	/* Define the class constructor */
	function __construct() {
	  $this->connection = new Memcache;
	  $this->log = new logAPI();
	  $this->date = date('Y-m-d H:i:s');
	  $this->log->Logger("[[".$this->date."]] "."New Instance Created<br/>\n");
	}

	/*  connect() connects to the Memcache Server  */
	/* returns TRUE if connection established */
	/* returns FALSE if connection failed */
	function connect() {
	  $memHost = "localhost";
	  $memPort = 11211;
	  if($this->connection->connect($memHost,$memPort)) {
	    $this->log->Logger("[[".$this->date."]] "."Connection established with memcache server<br/>\n");
		return TRUE;
	  }
	  else {
	    $this->log->Logger("[[".$this->date."]] "."Connection failed to establish with memcache server<br/>\n");
	    return FALSE;
	  }
	}

	/* close() will disconnet from Memcache Server */
	function close() {
	  if($this->connection->close()) {
	    $this->log->Logger("[[".$this->date."]] "."Connection closed with memcache server<br/>\n");
	    $this->log->Logger("=================================================================================================<br/>\n\n");
	    return TRUE;
	  }
	  else {
	    $this->log->Logger("[[".$this->date."]] "."Connection didn't close with memcache server<br/>\n");
		$this->log->Logger("=======================================================================================================<br/>\n\n");
	    return FALSE;
	  }
	}

	/* getCache() function will fetch the passed $query resultset from cache */
	/* returned resultset is null if $query not found in cache */
	function getCache($query) {
	  /* Generate the key corresponding to query */
	  $key = base64_encode($query);

	  /* Get the resultset from cache */
	  $resultset = $this->connection->get($key);

	  /* Unserialize the result if found in cache */
	  if($resultset != null) {
	    $this->log->Logger("[[".$this->date."]] "."Query ".$query." was found already cached<br/>\n");
	    $resultset = unserialize($resultset);
	  }
	  else {
	    $this->log->Logger("[[".$this->date."]] "."Query ".$query." was not found cached in memcache server<br/>\n");
	  }
	  return $resultset;
	}

	/* setCache() function will set the serialized resultset on Memcache Server */
	function setCache($query,$resultset,$useCompression=0,$ttl=600) {
	  /* Generate the key corresponding to query */
	  $key = base64_encode($query);

	  /* Set the value on Memcache Server */
	  $resultset = serialize($resultset);
	  if($this->connection->set($key,$resultset,$useCompression,$ttl)) {
	    $this->log->Logger("[[".$this->date."]] "."Query ".$query." was cached<br/>\n");
		return TRUE;
	  }
	  else {
	    $this->log->Logger("[[".$this->date."]] "."Query ".$query." was not able to cache<br/>\n");
		return FALSE;
	  }
	}

  }
</pre>
<p><strong>index.php</strong><br />
With everything in place, its time to test memcached. We will check if memcached is working fine by running this code file twice one by one. Open command line and point to this code. Run from command line: <em>php index.php</em> . Then again run from command line <em>php index.php</em>.</p>
<pre name="code" class="php">
  include_once("database.class.php");
  $mdb = new databaseAPI();

  $query = "SELECT * from status LIMIT 0,1000";
  $resultset = $mdb->getData($query);
  $mdb->close();

  echo "
<pre>";
  print_r($resultset);
  echo "</pre>
<p>";
</pre>
<p>If everything is working fine, you will see a log.txt file being generated which will look as follows.</p>
<p><strong>log.txt</strong></p>
<pre name="code" class="php">
[[2009-01-18 09:52:57]] New Instance Created<br/>
[[2009-01-18 09:52:57]] Connection established with memcache server<br/>
[[2009-01-18 09:52:57]] Query SELECT * from status LIMIT 0,1000 was not found cached in memcache server<br/>
[[2009-01-18 09:52:57]] Query SELECT * from status LIMIT 0,1000 was cached<br/>
[[2009-01-18 09:52:57]] Connection closed with memcache server<br/>
=================================================================================================<br/>

[[2009-01-18 09:53:08]] New Instance Created<br/>
[[2009-01-18 09:53:08]] Connection established with memcache server<br/>
[[2009-01-18 09:53:08]] Query SELECT * from status LIMIT 0,1000 was found already cached<br/>
[[2009-01-18 09:53:08]] Connection closed with memcache server<br/>
=================================================================================================<br/>
</pre>
<p>From the log file we can see that the 1st time results were fetched from the database and for the second time from memcached <img src='http://abhinavsingh.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Before we proceed further lets explain the flow of the above scripts. In <em>index.php</em> we create a new instance of <em>database.class.php</em> $mdb. Then we try to $query for 100 rows from the database. $mdb->getData($query) initiates this database fetch. As the program control goes to getData() method of <em>database.class.php</em>, it passed the control to getCache() method of <em>memcache.class.php</em>. There the code create a $key = base64_encode($query) and checks if we have the result set cached in memcached. If it doesn&#8217;t exists, it passed control back to getData() of database.class.php which fetches it from the database. After the fetch, it passes the $resultset back to setCache() method of memcache.class.php. There the setCache() method serialize the $resultset and cache it as ($key,$value) = (base64_encode($query), serialize($resultset)) in memcache.</p>
<p>Next time when the same query is fired and control goes to getCache() method of <em>memcache.class.php</em>, it fetches the result from cache, unserialize it and returns back the result to getData() of <em>database.class.php</em>. And thats why you see a log similar to above.</p>
<p><strong>memcache.extendedstats.php</strong><br />
Finally it&#8217;s time to see some statistics. Here is a simple file which will show memcache status:</p>
<pre name="code" class="php">
  $memcache_obj = new Memcache;
  $memcache_obj->addServer('localhost', 11211);

  $stats = $memcache_obj->getExtendedStats();

  echo "
<pre>";
  print_r($stats);
  echo "</pre>
<p>";
</pre>
<p>Running it from command line using: <em>php memcache.extendedstats.php</em> will give you a statistic array like this.</p>
<pre name="code" class="php">
Array
(
    [localhost:11211] => Array
        (
            [pid] => 5472
            [uptime] => 17
            [time] => 1232303504
            [version] => 1.2.5
            [pointer_size] => 32
            [curr_items] => 1
            [total_items] => 1
            [bytes] => 271631
            [curr_connections] => 2
            [total_connections] => 5
            [connection_structures] => 3
            [cmd_get] => 2
            [cmd_set] => 1
            [get_hits] => 1
            [get_misses] => 1
            [evictions] => 0
            [bytes_read] => 271705
            [bytes_written] => 271614
            [limit_maxbytes] => 536870912
            [threads] => 1
        )

)
</pre>
<p>This array tells you of a number of things about how your memcached deamon and caching architecture is performing. In short here is what each of the variable would mean:</p>
<ol>
<li><strong>pid:</strong> Process id of this server process</li>
<li><strong>uptime:</strong> Number of seconds this server has been running</li>
<li><strong>time:</strong> Current UNIX time according to the server</li>
<li><strong>version:</strong> Version string of this server</li>
<li><strong>rusage_user:</strong> Accumulated user time for this process</li>
<li><strong>rusage_system:</strong> Accumulated system time for this process</li>
<li><strong>curr_items:</strong> Current number of items stored by the server</li>
<li><strong>total_items:</strong> Total number of items stored by this server ever since it started</li>
<li><strong>bytes:</strong> Current number of bytes used by this server to store items</li>
<li><strong>curr_connections:</strong> Number of open connections</li>
<li><strong>total_connections:</strong> Total number of connections opened since the server started running</li>
<li><strong>connection_structures:</strong> Number of connection structures allocated by the server</li>
<li><strong>cmd_get:</strong> Cumulative number of retrieval requests</li>
<li><strong>cmd_set:</strong> Cumulative number of storage requests</li>
<li><strong>get_hits:</strong> Number of keys that have been requested and found present</li>
<li><strong>get_misses:</strong> Number of items that have been requested and not found</li>
<li><strong>bytes_read:</strong> Total number of bytes read by this server from network</li>
<li><strong>bytes_written:</strong> Total number of bytes sent by this server to network</li>
<li><strong>limit_maxbytes:</strong> Number of bytes this server is allowed to use for storage.</li>
</ol>
<p>However at this stage the figures which you might be interested in knowing are <em>get_hits</em> and <em>get_misses</em>. <em>get_misses</em> means number of times you requested for a key in memcache and it was not found while get_hits means number of times your requested key was successfully retrieved from memcached. Hence as expected we currently have <em>get_misses = 1</em> and <em>get_hits = 1</em>. Try running <em>php index.php</em> once more and <em>get_hits</em> will get incremented by one.</p>
<p><strong style="font-size:18px;"><u>N things: What else can I do</u></strong><br />
Till now you have memcached deamon running on your system and you know how to communicate with the deamon. You also know a very basic usage of memcached now, i.e. cache the queries to reduce load from your database. However there is a lot more you can do with memcached.</p>
<p>Here I would like to present before you a few applications of memcached which I learnt from my experiences. I hope they will be enough to make you think otherwise.</p>
<ol>
<li><strong><u>Restricting spammers on your site</u> :</strong> Often you will find on social networking sites like <em>Digg</em>, <em>Facebook</em> and <em>Orkut</em> that if you try to add several users as your friend within a short span, they (facebook) will show you a warning or they (digg) will restrict you from doing it. Similarly there are cases when you want to send a shout to more than 200 users on digg and you are restricted from doing so. How will you implement this on your site?
<p><strong style="color:#AA0000">Ordinary user&#8217;s solution:</strong> One solution is if a user &#8216;X&#8217; add another user &#8216;Y&#8217; as a friend, you will check how many friends has &#8216;X&#8217; added in the past 10 minutes. If that exceeds 20, you won&#8217;t allow him to add more friends or show him a warning message. Simple enough and will work coolly. But what if your site have more than a million users, with many hackers around the world trying to keep your servers busy. As a memcached user you must have following solution in your mind:</p>
<p><strong style="color:#0000AA">Your solution:</strong> As &#8216;X&#8217; adds &#8216;Y&#8217; in his friend list, you will set a (key,value) pair in memcached, where $key = &#8220;user_x&#8221; with $TTL = 10 minutes. For the first friend added, $value = 1. Now as &#8216;X&#8217; tries to add another friend, your simply increment $value for $key = &#8220;user_x&#8221;. As this $value equals 20, and &#8216;X&#8217; tried to add another friend, your code will check the value of $key = &#8220;user_x&#8221; and see if it&#8217;s present in memcached. If it&#8217;s present check for it&#8217;s value. If it&#8217;s value is equal to 20, you show a warning message to the user. Hence restricting him from adding more than 20 friends within a time span of 10 minutes. After 10 minutes, $key = &#8220;user_x&#8221; will automatically expires and your code will allow &#8216;X&#8217; to add more friends. Similar solution exists if you want to stop spammers from sending message or commenting over a limit on your site. Now I see confidence building in you as a memcached programmer <img src='http://abhinavsingh.com/blog/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  <br/><br/></li>
<li><strong><u>Detecting online active/inactive users</u> :</strong> Often you want a method which can tell your registered users, about their online friends. Or in a forum you want to tell the current reading user, about who all are reading this post. I won&#8217;t tell how an ordinary user will implement this, but as a memcached user your solution should be:
<p><strong style="color:#AA0000">Ordinary user&#8217;s solution:</strong> You don&#8217;t want to think of this.</p>
<p><strong style="color:#0000AA">Your solution:</strong> As user &#8216;X&#8217; visit post#12345 in the forum, not only you will fetch post data from the database, you also set two (key,value) pairs.</p>
<p>$key1 = &#8220;post_12345&#8243;<br />
$value1 = [[comma separated list of user names]]<br />
$TTL1 = [[some arbitrary large value is fine]]</p>
<p>$key2 = &#8220;user_x&#8221;<br />
$value2 = &#8220;post_12345&#8243;<br />
$TTL2 = 10 minutes, We assume a user to be inactive if he is on a particular post for more than 10 minutes (tunable), and we will mark him as inactive.</p>
<p>(key1,value1) is a post specific data while (key2,value2) is a user specific data. Now every time a user visits post#12345, you will do two things. Read all comma separated user names from $value1, and then check for their corresponding $key2 value. If corresponding $key2 exists and equals to $value2 = &#8220;post_12345&#8243;, i.e. on the same post and not idle, we will keep that user name in value of $key1. However if $key2 is not present (i.e. user gone away) or value of $key2 equals to some other post, we will remove his user name from $value1. Confused <img src='http://abhinavsingh.com/blog/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  , read twice and the picture will be clear.</p>
<p>Can you think of a better solution? Please let me and others know about it. (Remember we are trying to detect only active/inactive users, which is not same as online/offline users)<br/><br/></li>
<li><strong><u>Building scalable web services</u></strong> : Another application of memcached lies in building scalable web services and web widgets. <a href="http://gtalkbots.com" target="_blank">Gtalkbots</a> offer a cool widget which you can put on your blog and sites to show off your aggregated status messages. See this widget live in the right hand sidebar. While building this widget, one thing which I kept in mind was that, what if someone with million hits per day put my widget on his site. Even though, Gtalkbots gets a few thousand of hits per day, it will crash, mainly because of this particular widget being placed on a high traffic site. So as a memcached user I have done the following thing.
<p><strong style="color:#AA0000">Ordinary user&#8217;s solution:</strong> Deprecated</p>
<p><strong style="color:#0000AA">Your solution:</strong> I simply cache the widget data in memcache with $TTL = 1 hour. So every time this million hits per day site is accessed, which loads my widget million times a day, the query will be returned from cache. And hence saving my server from crashing. Fetch <a target="_blank" href="http://gtalkbots.com/dashboard/getwidgets">Gtalkbots widget</a> from here and try putting on your site.</li>
</ol>
<p>Alright by now you can impress your bosses with your cool memcache implementations. But wait there is a lot more you need to know. I can go on putting hundred&#8217;s of memcached applications here, but main point is, setting your mind as a memcached user. I personally have this habit of linking everything to memcached while designing a system, and if it suits my need, Bingo!.</p>
<ol>
<li><strong><u>Versioning your cache keys</u></strong> : One disadvantage of using cache at times is that, if unfortunately something goes wrong with your data and that buggy data is cached, your users will keep seeing that buggy data until your cache expires or you manually clear off your cache. Suppose you clear your cache and then one of your fucking engineer comes running saying the data is fine.
<p><strong style="color:#AA0000">Ordinary user&#8217;s solution:</strong> Stop it, No more plz</p>
<p><strong style="color:#0000AA">Your solution:</strong> As a memcached user, i would love to keep a Versioning system for my caches. Nothing complex, simply append <em>&#8220;v1&#8243;</em> (version number) to all your keys. i.e. $key = &#8220;user_x&#8221; will now become $key = &#8220;v1:user_x&#8221;. and at a place in your code you have <em>$current_cache_version = &#8220;v1&#8243;</em>. Now suppose you are told your data is buggy, so by the time your engineers are investigation change <em>$current_cache_version = &#8220;v2&#8243;</em>. This will keep your old caches, which you may want to recover after your investigation and at the same time show new data to your users.<br/><br/></li>
<li><strong><u>Not so frequent update of Db for trivial data</u></strong> : This is a site dependent application. Suppose you run a site where you are not so serious about database columns like &#8220;last_update_date&#8221;, &#8220;last_logged_in&#8221; and so on. However you still keep a track of such for analysis purpose and don&#8217;t mind if it&#8217;s not so accurate.
<p><strong style="color:#0000AA">Your solution:</strong> One simple solution to this problem is keep such trivial data in memcached and set up a cron job which will run every 10 minutes and populate such data in the database. <img src='http://abhinavsingh.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ol>
<p>I will leave you with a presentation on memcache which I gave sometime back at office. I hope it will help you gain more understanding of memcache.</p>
<p><center></p>
<div style="width:425px;text-align:left" id="__ss_917157"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/imoracle/memcache-presentation?type=powerpoint" title="Memcache">Memcache</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=memcache-1231956637654098-1&#038;stripped_title=memcache-presentation" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=memcache-1231956637654098-1&#038;stripped_title=memcache-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View SlideShare <a style="text-decoration:underline;" href="http://www.slideshare.net/imoracle/memcache-presentation?type=powerpoint" title="View Memcache on SlideShare">presentation</a> or <a style="text-decoration:underline;" href="http://www.slideshare.net/upload?type=powerpoint">Upload</a> your own. (tags: <a style="text-decoration:underline;" href="http://slideshare.net/tag/caching">caching</a> <a style="text-decoration:underline;" href="http://slideshare.net/tag/memcache">memcache</a>)</div>
</div>
<p></center></p>
<p>I hope after reading this you are well equipped on how to design scalable systems. All the best! , do leave a comment or suggestions if any. If you liked this post, do subscribe for the next post in memcache series.</p>
<div id="paidTxtLinkAds">Check out our latest <a href="http://www.testking.org/70-642.htm">testking 70-642</a> dumps and <a href="http://www.testking.org/642-902.htm">testking 642-902</a> tutorials for php to get deep insight into new releases. PHP is easy to learn with our <a href="http://www.testking.org/220-701.htm">testking 220-701</a> training course.</div>
<script type="text/javascript">var wordpress_toolbar_urls = ["http:\/\/api.tweetmeme.com\/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F01%2Fmemcached-and-n-things-you-can-do-with-it%2F","http:\/\/bradfitz.com\/","http:\/\/code.google.com\/p\/abhinavsingh\/source\/browse\/trunk\/Memcached\/memcache-1.2.5\/memcached-1.2.5-win32-bin.zip","http:\/\/code.google.com\/p\/abhinavsingh\/source\/browse\/trunk\/Memcached\/dlls\/php-4.x\/php_memcache.dll","http:\/\/code.google.com\/p\/abhinavsingh\/source\/browse\/trunk\/Memcached\/dlls\/php-5.x\/php_memcache.dll","http:\/\/abhinavsingh.googlecode.com\/files\/svn-trunk-Memcached.rar","http:\/\/gtalkbots.com","http:\/\/gtalkbots.com\/dashboard\/getwidgets","http:\/\/www.slideshare.net\/imoracle\/memcache-presentation?type=powerpoint","http:\/\/www.slideshare.net\/imoracle\/memcache-presentation?type=powerpoint","http:\/\/www.slideshare.net\/upload?type=powerpoint","http:\/\/slideshare.net\/tag\/caching","http:\/\/slideshare.net\/tag\/memcache","http:\/\/www.testking.org\/70-642.htm","http:\/\/www.testking.org\/642-902.htm","http:\/\/www.testking.org\/220-701.htm"];var wordpress_toolbar_url = "http://abhinavsingh.com/blog/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "oinw";var wordpress_toolbar_hash = "aHR0cDovL2FiaGluYXZzaW5naC5jb20vYmxvZy8yMDA5LzAxL21lbWNhY2hlZC1hbmQtbi10aGluZ3MteW91LWNhbi1kby13aXRoLWl0Lzx3cHRiPk1lbWNhY2hlZCBhbmQgJnF1b3Q7TiZxdW90OyB0aGluZ3MgeW91IGNhbiBkbyB3aXRoIGl0ICYjODIxMTsgUGFydCAxPHdwdGI%2BaHR0cDovL2FiaGluYXZzaW5naC5jb20vYmxvZzx3cHRiPkFiaGkmIzAzOTtzIFdlYmxvZw%3D%3D";</script><ul class="related_post"><li><a href="http://abhinavsingh.com/blog/2008/05/how-to-configure-ubuntu-and-lamp-on-windows/" title="How to configure Ubuntu and LAMP on Windows">How to configure Ubuntu and LAMP on Windows</a> (4)</li><li><a href="http://abhinavsingh.com/blog/2010/04/setting-nginx-php-fastcgi-and-xcache-on-a-new-ubuntu/" title="Setting Nginx, PHP Fastcgi and XCache on a new Ubuntu">Setting Nginx, PHP Fastcgi and XCache on a new Ubuntu</a> (5)</li><li><a href="http://abhinavsingh.com/blog/2010/02/writing-your-first-facebook-chat-bot-in-php-using-jaxl-library/" title="Writing your first facebook chat bot in PHP using Jaxl library">Writing your first facebook chat bot in PHP using Jaxl library</a> (57)</li><li><a href="http://abhinavsingh.com/blog/2010/02/memq-fast-queue-implementation-using-memcached-and-php-only/" title="MEMQ : Fast queue implementation using Memcached and PHP only">MEMQ : Fast queue implementation using Memcached and PHP only</a> (17)</li><li><a href="http://abhinavsingh.com/blog/2010/01/wordpress-style-duplicate-comment-detected-using-memcached-and-php/" title="Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP">Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP</a> (8)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>MySQL Query Cache, WP-Cache, APC, Memcache &#8211; What to choose</title>
		<link>http://abhinavsingh.com/blog/2009/01/mysql-query-cache-wp-cache-apc-memcache-what-to-choose/</link>
		<comments>http://abhinavsingh.com/blog/2009/01/mysql-query-cache-wp-cache-apc-memcache-what-to-choose/#comments</comments>
		<pubDate>Wed, 14 Jan 2009 18:18:58 +0000</pubDate>
		<dc:creator>Abhinav Singh</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[APC]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[Memcache]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Opcode]]></category>
		<category><![CDATA[Query Cache]]></category>
		<category><![CDATA[WP-Cache]]></category>

		<guid isPermaLink="false">http://abhinavsingh.com/blog/?p=153</guid>
		<description><![CDATA[Hello Cache Freaks, Ever since I changed my job (from Business Intelligence to Web development) and started working with my present employer, I have had a chance to work on a lot of scalable projects. From making my project to scale from 20 Million PV&#8217;s to 100 Million PV&#8217;s to development of an internal tool, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F01%2Fmysql-query-cache-wp-cache-apc-memcache-what-to-choose%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F01%2Fmysql-query-cache-wp-cache-apc-memcache-what-to-choose%2F&amp;source=imoracle&amp;style=normal&amp;service=bit.ly&amp;service_api=R_f027b5a79a20a49b713f16282f1e0857&amp;hashtags=APC,Caching,Memcache,MySQL,Opcode,PHP,Query+Cache,WP-Cache&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Hello Cache Freaks,</p>
<p>Ever since I changed my job (from Business Intelligence to Web development) and started working with my present employer, I have had a chance to work on a lot of scalable projects. From making my project to scale from 20 Million PV&#8217;s to 100 Million PV&#8217;s to development of an internal tool, the answer to all scalable applications have been caching.</p>
<p>There are a lot of caching techniques which are being employed by sites worldwide.</p>
<ol>
<li><strong>WP-Cache</strong> used in wordpress &#8211; a file system based caching mechanism</li>
<li><strong>APC Cache</strong> &#8211; an opcode based caching system</li>
<li><strong>Memcache</strong> &#8211; an in memory caching system</li>
<li><strong>Query Cache</strong> &#8211; caching mechanism employed in MySQL</li>
</ol>
<p>Here in this post I would like to pen down my experiences while working with all the caching mechanism. Their pros and cons. What things you need to take care while working with them and every little tit bit which comes to my mind while writing this post.</p>
<p><strong style="font-size:18px;"><u>Query Cache &#8211; inbuilt cache mechanism in MySQL</u></strong><br />
Query cache is an inbuilt cache mechanism for MySQL. Basically when you fire a query against a MySQL database, it goes through a lot of core modules. e.g. Connection Manager, Thread Manager, Connection Thread, User Authentication Module, Parse Module, Command Dispatcher, Optimizer Module, Table Manager, Query Cache Module and blah blah. Discussing these modules is out of scope of this blog post. The only module we are interested here is Query Cache Module.</p>
<p>Suppose I fire a query:<br />
$query = &#8220;Select * from users&#8221;;</p>
<p>MySQL fetches it for the first time from the database and caches the result for further similar query. Next time when you fire a similar query, it picks the result from the cache and deliver it back to you.</p>
<p>However, there are a few <u>drawbacks</u> with Query Cache:</p>
<ul>
<li>If there is a new entry in the <em>users</em> table, the cache is cleared.</li>
<li>Secondly, even if the result of your query is cached, MySQL has to go through a number of core modules before it give back the cached result to you.</li>
<li>Thirdly, even if your results are caches, you need to connect to your MySQL database, which generally have a bottleneck with number of connections allowed.</li>
</ul>
<p>One thing which you should take care while replying on Query Cache is that, your query must not have any parameter which is random or changes quite often. For e.g. If you wish to fetch url&#8217;s of 100 photo from the database, and then you want to present them in a random fashion every time, you might be tempted to use <strong>rand()</strong> somewhere in your MySQL queries. However by using rand() you ensure that the query is never returned from cache, since rand() parameter always makes the query look different.</p>
<p>Similarly, If you have a case where you need to show data not older than 15 days, and by mistake you also include the seconds parameter in your SQL query, then the query will never return from cache.</p>
<p>Hence for a scalable site, with 100 Million PV&#8217;s you can&#8217;t really survive with a simple query cache provided by MySQL database.</p>
<p><strong style="font-size:18px;"><u>WP-Cache &#8211; Caching mechanism for WordPress blogs</u></strong><br />
WP-Cache is a file system based caching mechanism i.e. it caches your blog posts in form of simple text files which are saved on your file system. You can have a look at these cached files by visiting <em><u>wp-content/cache</u></em> folder inside your blog directory. Generally you will find two set of files for a single blog post. One .html and another .meta file.</p>
<p><u><em>.html file</em></u> generally contains the static html content for your blog post. Once published, the blog post content is static, hence instead of fetching it&#8217;s data from the database, WP-Cache serves it from the <em>cache</em> directory.</p>
<p><u><em>.meta file</em></u> contains serialized information such as Last Modified, Content-Type, URI which WP-Cache uses to maintain cache expiry on your blog.</p>
<p>WP-Cache works really well, however if the traffic starts increasing on your blog, then the bottleneck will be maximum number of child processes which apache can create (<em>For starters you can think, each user connecting to your blog as one apache process, hence there is a restriction on number of users who can connect to your blog at a particular time</em>). In such case the solution can be either to have multiple front end servers with a load balancer to distribute the traffic among front end servers, or to have a better cache solution such as a memory based caching mechanism (e.g. Memcache). Also since memory read is always faster than file read, you must go for a memory based cache system.</p>
<p><strong style="font-size:18px;"><u>APC Cache &#8211; An opcode based cache for PHP</u></strong><br />
APC stands for Alternative PHP Cache. In one of my previous post <a target="_blank" href="http://abhinavsingh.com/blog/2008/11/how-does-php-echos-a-hello-world-behind-the-scene/">How does PHP echo’s a “Hello World”? &#8211; Behind the scene</a>, I talk about how PHP churns out &#8220;Hello World&#8221; for you.</p>
<p>PHP takes your code through various steps:</p>
<ol>
<li>Scanning &#8211; The human readable source code is turned into tokens.</li>
<li>Parsing &#8211; Groups of tokens are collected into simple, meaningful expressions.</li>
<li>Compilation &#8211; Expressions are translated into instruction (opcodes)</li>
<li>Execution &#8211; Opcode stacks are processed (one opcode at a time) to perform the scripted tasks.</li>
</ol>
<p>Opcode caches let the ZEND engine perform the first three of these steps, then store that compiled form (opcodes) so that the next time a given script is used, it can use the stored version without having to redo those steps only to come to the same result.</p>
<p>However the problem with APC cache is that it is not a distributed cache system. By distributed cache I mean, if you have 3 frontend server then you need to have a copy of this opcode on all the three fronend server. <del datetime="2009-01-16T14:17:16+00:00">Also like WP-Cache APC is again a file system driven cache system, which is not the optimal solution.</del> Also with APC cache, PHP still has to go through the last step as described above.</p>
<p><strong style="font-size:18px;"><u>Memcache &#8211; In memory based cache mechanism</u></strong><br />
Memcache is the solution when you talk about million PV&#8217;s on your site. <em>It is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.</em></p>
<p>For starters, Memcache is not PHP, nor Python or any other thing as you may think. It&#8217;s a deamon which runs in the background on your server. Your code connects to it and cache query results, JS, CSS and other cachable data in the server&#8217;s memory (RAM). Since its an in-memory caching system, it is faster than any of the discussed caching system above. However it is unreliable and unsecure but then there are ways to tackle this unreliable and unsecure nature of memcache.</p>
<p>Memcache is unreliable because it resides in your system memory. So an event like system reboot or power failure will result in loss of all your cache. Also memcache provides no mechanism to take backup of your caches. Hence once lost, you need to programmatically warmup your caches.</p>
<p>Memcache is unsecure because it doesn&#8217;t require any authentication mechanism. There is no username or password with which your code connects to it. (Hence it is super fast, unlike Query cache which has to go through auth module even if the query result is cached). It usually runs at port 11211 on your server and if not taken care, anyone can telnet to port 11211 on your server and steal your caches.</p>
<p>Below are the steps which are being followed on a memcache enabled website:</p>
<ol>
<li>User enter your site&#8217;s url in his browser, say http://localhost</li>
<li>There are about 6 queries which drives your opening page</li>
<li>Lets assume one of the query for this page is <em>$query = &#8220;SELECT photo_url from photos LIMIT 0,10&#8243;</em></li>
<li>When the user visit http://localhost, your code will first connect to memcache deamon on port 11211</li>
<li>If memcache deamon is running, it checks if the result of this query are already cached. Generally data is cached in memcache as (key,value) pair</li>
<li>Since this is the first visit on your site, ofcourse there is no query being cached till now. Hence your code now connect to your MySQL database and fetched the resultset. Something like this probably. <em>$resultset = mysql_query($query);</em></li>
<li>After successfully fetching the resultset, your code will cache this resultset in memcache. The code connects to memcache deamon and saves this (key,value) pair in memory, where $key = md5($query) and $value = serialize($resultset)</li>
<li>After caching the (key,value) pair, your code returns back the fetched resultset to the frontpage where it is being displayed to the user</li>
<li>Similarly all the 6 queries which drives your front page are being cached one by one</li>
<li>Now the next time when another user visit this page i.e. http://localhost, your code will first see if $key = md5($query) is already present in cache. It will find the $key being cached, fetches the serialized resultset from memory, unserialize it and throws back to the front page where it is displayed as intended</li>
<li>While caching (key,value) pair you also have a provision to specify a TTL (time to live) after which memcache will automatically expire your cached result</li>
<li>Suppose you specifies a TTL = 15 Minutes for all the above queries and now a visitor visit http://localhost after 30 minutes</li>
<li>Your code will again first connect to memcache deamon and check if $key = md5($query) is present in cache. Memcache deamon will see that this $key is present but it has expired. It will return a result saying $key is not cached and internally flushes out $key. Your code then again connect to MySQL database, fetches the resultset and cache back the results in memcache for further use</li>
</ol>
<p>I will leave you with a presentation on memcache which I gave sometime back at office. I hope it will help you gain more understanding of memcache.</p>
<p><center></p>
<div style="width:425px;text-align:left" id="__ss_917157"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/imoracle/memcache-presentation?type=powerpoint" title="Memcache">Memcache</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=memcache-1231956637654098-1&#038;stripped_title=memcache-presentation" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=memcache-1231956637654098-1&#038;stripped_title=memcache-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View SlideShare <a style="text-decoration:underline;" href="http://www.slideshare.net/imoracle/memcache-presentation?type=powerpoint" title="View Memcache on SlideShare">presentation</a> or <a style="text-decoration:underline;" href="http://www.slideshare.net/upload?type=powerpoint">Upload</a> your own. (tags: <a style="text-decoration:underline;" href="http://slideshare.net/tag/caching">caching</a> <a style="text-decoration:underline;" href="http://slideshare.net/tag/memcache">memcache</a>)</div>
</div>
<p></center></p>
<p>In my next posts, I will be covering a few code samples and use cases of memcache which you wouldn&#8217;t even heard of. If you liked the post don&#8217;t forget to promote it on social networking sites and do subscribe to my blog. <img src='http://abhinavsingh.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div id="paidTxtLinkAds">Learn PHP with our <a href="http://www.testking.org/642-901.htm">testking 642-901</a> web development course. Download <a href="http://www.testking.org/642-812.htm">testking 642-812</a> php material and reviews, articles and <a href="http://www.testking.org/70-640.htm">testking 70-640</a> video tutorials to get in depth knowledge.</div>
<script type="text/javascript">var wordpress_toolbar_urls = ["http:\/\/api.tweetmeme.com\/share?url=http%3A%2F%2Fabhinavsingh.com%2Fblog%2F2009%2F01%2Fmysql-query-cache-wp-cache-apc-memcache-what-to-choose%2F","http:\/\/www.slideshare.net\/imoracle\/memcache-presentation?type=powerpoint","http:\/\/www.slideshare.net\/imoracle\/memcache-presentation?type=powerpoint","http:\/\/www.slideshare.net\/upload?type=powerpoint","http:\/\/slideshare.net\/tag\/caching","http:\/\/slideshare.net\/tag\/memcache","http:\/\/www.testking.org\/642-901.htm","http:\/\/www.testking.org\/642-812.htm","http:\/\/www.testking.org\/70-640.htm"];var wordpress_toolbar_url = "http://abhinavsingh.com/blog/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "oinw";var wordpress_toolbar_hash = "aHR0cDovL2FiaGluYXZzaW5naC5jb20vYmxvZy8yMDA5LzAxL215c3FsLXF1ZXJ5LWNhY2hlLXdwLWNhY2hlLWFwYy1tZW1jYWNoZS13aGF0LXRvLWNob29zZS88d3B0Yj5NeVNRTCBRdWVyeSBDYWNoZSwgV1AtQ2FjaGUsIEFQQywgTWVtY2FjaGUgJiM4MjExOyBXaGF0IHRvIGNob29zZTx3cHRiPmh0dHA6Ly9hYmhpbmF2c2luZ2guY29tL2Jsb2c8d3B0Yj5BYmhpJiMwMzk7cyBXZWJsb2c%3D";</script><ul class="related_post"><li><a href="http://abhinavsingh.com/blog/2009/11/introducing-memchat-open-source-group-chat-framework-in-php-supporting-memcached-apc-sqlite-flat-files-and-mysql/" title="Introducing MemChat: Open source group chat framework in PHP supporting Memcached, APC, SQLite, Flat Files and MySQL">Introducing MemChat: Open source group chat framework in PHP supporting Memcached, APC, SQLite, Flat Files and MySQL</a> (32)</li><li><a href="http://abhinavsingh.com/blog/2010/02/memq-fast-queue-implementation-using-memcached-and-php-only/" title="MEMQ : Fast queue implementation using Memcached and PHP only">MEMQ : Fast queue implementation using Memcached and PHP only</a> (17)</li><li><a href="http://abhinavsingh.com/blog/2010/01/wordpress-style-duplicate-comment-detected-using-memcached-and-php/" title="Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP">Wordpress style &quot;Duplicate comment detected&quot; using Memcached and PHP</a> (8)</li><li><a href="http://abhinavsingh.com/blog/2009/12/how-to-use-locks-for-assuring-atomic-operation-in-memcached/" title="How to use locks for assuring atomic operation in Memcached?">How to use locks for assuring atomic operation in Memcached?</a> (9)</li><li><a href="http://abhinavsingh.com/blog/2009/11/php-tokens-and-opcodes-3-useful-extensions-for-understanding-the-working-of-zend-engine/" title="PHP tokens and opcodes : 3 useful extensions for understanding the working of Zend Engine">PHP tokens and opcodes : 3 useful extensions for understanding the working of Zend Engine</a> (10)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://abhinavsingh.com/blog/2009/01/mysql-query-cache-wp-cache-apc-memcache-what-to-choose/feed/</wfw:commentRss>
		<slash:comments>43</slash:comments>
		</item>
	</channel>
</rss>

