<?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>kafka0102的边城客栈 &#187; memcache</title>
	<atom:link href="http://www.kafka0102.com/tag/memcache/feed" rel="self" type="application/rss+xml" />
	<link>http://www.kafka0102.com</link>
	<description>要有最朴素的生活与最遥远的梦想，即使明日天寒地冻、路远马亡。</description>
	<lastBuildDate>Sat, 18 Jun 2011 04:20:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>memcache proxy之moxi介绍</title>
		<link>http://www.kafka0102.com/2010/01/21.html</link>
		<comments>http://www.kafka0102.com/2010/01/21.html#comments</comments>
		<pubDate>Sat, 23 Jan 2010 13:39:36 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[cache]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[memcache proxy]]></category>
		<category><![CDATA[moxi]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=21</guid>
		<description><![CDATA[续接上文 memcache-proxy之memagent介绍分析，本文介绍另一个功能强大的memcache proxy之moxi（http://labs.northscale.com/moxi/）。话说一个proxy都敢造次自称为先知！由于精力有限，本文只对moxi做些功能性介绍，而不对其实现代码做分析。]]></description>
			<content:encoded><![CDATA[<p><span style="font-size: medium;"> 续接上文 <a href="http://www.kafka0102.com/2010/01/memcache-proxy之memagent介绍分析/" target="blank">memcache-proxy之memagent介绍分析</a>，本文介绍另一个功能强大的memcache proxy之<a href="http://labs.northscale.com/moxi/" target="blank">moxi</a>。话说一个proxy都敢造次自称为先知！由于精力有限，本文只对moxi做些功能性介绍，而不对其实现代码做分析。<br />
0、先上来一张moxi的内部结构图，如果你领会了结构图，下面的文字可以飘过。这个结构图取自<a href="http://www.slideshare.net/northscale/moxi-memcached-proxy" target="blank">moxi-memcached-proxy</a>，算是moxi的文档了。</span></p>
<p><span style="font-size: medium;"> </span></p>
<div id="attachment_23" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kafka0102.com/wp-content/uploads/2010/01/3a47ffee-8a3e-4e47-acea-478c91cdd511.jpg"><img class="size-medium wp-image-23 " title="inside moxi" src="http://www.kafka0102.com/wp-content/uploads/2010/01/3a47ffee-8a3e-4e47-acea-478c91cdd511-300x214.jpg" alt="inside moxi " width="300" height="214" /></a><p class="wp-caption-text">inside moxi</p></div>
<p><span style="font-size: medium;"> 1、moxi基于最新的memcached代码，我简单的浏览moxi，发现它里面就有memcached的代码文件。所以，它对后面的memcached支持binaray和text两种协议，对前面的client目前只支持text协议，以后也会支持binaray协议。<br />
2、moxi极力吸取已有工作成果，基于memcached开发，自然也是基于libevent、多线程模型，而一致性hash它使用的libmemcached客户端库。<br />
3、对于并发的gets请求，moxi会做合并来减少和memcache server的交互，这个效果依赖于它对请求的get key做管道处理，所以在事件回调时能检测到需要合并的请求，效果图如下：</span></p>
<p><span style="font-size: medium;"> </span></p>
<div id="attachment_24" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.kafka0102.com/wp-content/uploads/2010/01/5cc59479-35a9-4e3c-b3ce-ea16661d9ac7.jpg"><img class="size-medium wp-image-24" title="moxi get de-duplication" src="http://www.kafka0102.com/wp-content/uploads/2010/01/5cc59479-35a9-4e3c-b3ce-ea16661d9ac7-300x247.jpg" alt="moxi get de-duplication" width="300" height="247" /></a><p class="wp-caption-text">moxi get de-duplication</p></div>
<p><span style="font-size: medium;"> 4、对热点访问的cache（可以人工通过前缀key指定），moxi会在本地缓存，使得moxi相当于memcache server的前端cache，能减少network hops。不过这种热点cache项相对要少很多，而且为保证能正确失效，热点cache需要被复制到moxi集群的每个节点。这个功能在特定场景下还是很实用的，毕竟加个proxy，cache访问的效率还是会低一些，这对热点cache会有效率上的提升。<br />
5、Fire &amp; forget set功能（该怎么翻译呢？），说的是对于某种类型的key，在set时可以异步提交到memcache server而不需要client等待返回结果，这对于cache项的值字节数较大时（比如session内容）效果不错。<br />
6、超时处理。可以配置请求的超时时间，如果超时就返回失败。如果直接操作memcache server，因为没有超时机制，在一些情况下会hang住很长时间（比如网络问题、memcache server处理大数据量的缓慢等）。<br />
7、故障处理。memcache server不能访问时，Moxi会重试多次，如果失败就返回给client失败。Moxi支持动态的迁移memcache server配置。特别的，moxi可以做到将已有的一台memcache server的数据迁移到新的机器上，当新机器数据准备就绪，moxi就将它替换旧memcache server来提供服务。这个功能对memcache server的自动化运维很有帮助。</span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/01/21.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>memcache proxy之memagent介绍分析</title>
		<link>http://www.kafka0102.com/2010/01/9.html</link>
		<comments>http://www.kafka0102.com/2010/01/9.html#comments</comments>
		<pubDate>Sat, 23 Jan 2010 02:16:47 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[cache]]></category>
		<category><![CDATA[memagent]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[memcache proxy]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=9</guid>
		<description><![CDATA[	memagent（http://code.google.com/p/memagent/）是一个memcache proxy，它提供的功能及特点有：
	1、和每个memcache server保持多个长连接，效果是减少memcache server保持的连接数量及创建销毁连接的开销。不过，memcache本身就支持大并发连接，这个功能也就没什么特别的说道。
	2、支持memcache的binary协议命令，实现请求的转发。
	3、和memcache一样，基于libevent的事件驱动来处理IO。
	4、支持ketama 的一致性hash算法。
	5、支持memcache backup集群，当memcache集群有机器挂了，memagent会将get请求转向memcache backup集群。这个功能对于cache的稳定性要求高的场景下会有用武之地。
	就提供的功能而言，memagent是个很简单的东西。对于较大的memcache集群，可以考虑搭一套memagent作为proxy使用。
]]></description>
			<content:encoded><![CDATA[<p>memagent（<a href="http://code.google.com/p/memagent/">http://code.google.com/p/memagent/</a>）是一个memcache proxy，它提供的功能及特点有：</p>
<p>1、和每个memcache server保持多个长连接，效果是减少memcache server保持的连接数量及创建销毁连接的开销。不过，memcache本身就支持大并发连接，这个功能也就没什么特别的说道。</p>
<p>2、支持memcache的binary协议命令，实现请求的转发。</p>
<p>3、和memcache一样，基于libevent的事件驱动来处理IO。</p>
<p>4、支持ketama 的一致性hash算法。</p>
<p>5、支持memcache backup集群，当memcache集群有机器挂了，memagent会将get请求转向memcache backup集群。这个功能对于cache的稳定性要求高的场景下会有用武之地。</p>
<p>就提供的功能而言，memagent是个很简单的东西。对于较大的memcache集群，可以考虑搭一套memagent作为proxy使用。</p>
<h2>实现分析</h2>
<p>1、我得到memagent版本是0.5。除去一致性hash算法ketama的代码，memagent的代码都在magent.c文件中，代码总行数2000多行。稍微拿出半个晚上，就能把这份代码分析得差不多了。</p>
<p>2、memagent像memcache一样，使用了libevent来驱动状态及处理。Libevent是个很适合于事件驱动（最典型的就是网络IO事件）的场景。像memagent，对于client端的一个请求，它既要处理client端的网络IO，又要处理server端的网络IO，还有可能处理back server的网络IO，一个流程下来就触发了多达6、7次的网络IO事件。</p>
<p>3、memagent是单进程单线程程序，因为它的工作主要就是接受请求、对请求稍作解析后转发请求，所以逻辑上较为简单，最多的也就是内存拷贝工作，采用单进程单线程也就足够了。</p>
<p>4、memagent的事件回调函数分别是server_accept、drive_client、drive_memcached_server、drive_backup_server。这4个回调函数的功能也很明显，在drive_client、drive_memcached_server和drive_backup_server也分别涉及到读写处理的状态机机制，这部分代码涉及到协议解析及IO处理，代码细节也是琐碎繁杂的很。 基本的过程是：</p>
<p>1）memagent解析出client端的数据（主要是命令类型和key），向映射到的memcache server发送数据，如果memcache server连接不上，memagent会向backup集群（如果设置的话）发送数据。</p>
<p>2）在得到memcache server返回的数据后，memagent还是需要解析，如果这段时间memcache server返回失败，memagent还会再向backup集群请求数据。</p>
<p>3）最后，memagent将数据返回给client。</p>
<p>5、对于backup集群，如果配置了，memagent每次提交操作都会发给backup集群。在get某个memcache server失败时会将向backup集群再请求一遍。</p>
<p>6、对于gets命令，memagent对批量的每个key是单独和memcache server交互的。这块我觉得还可优化，可以合并映射到同一个memcache server的key在发往server的一个请求中批量处理。</p>
<p>7、无论是读client数据还是读server端数据，memagent都是不知道这个请求中到底有多少字节的数据，所以读时首先调用ioctl(fd, FIONREAD, &amp;toread)函数计算出IO buffer中已经收到的网络字节数据，再对收到的数据做分析确定是否需要继续read。这个技巧在不知道数据包头大小的情况下采用的手段。</p>
<p>8、再说一个实现的小细节。对于event_set的回调函数原型，对于不使用的参数可以通过调用宏#define UNUSED(x) ( (void)(x) )来解决gcc在开-Wall时的报错，我之前看到有文章说是用#pragma也行，不过我没试成功</p>
<h2>一致性hash算法</h2>
<p>对于memcache客户端就Cache key映射到哪个memcache server的选择算法，最简单的莫过于根据key计算出的hash值取count(memcache server)的余数。对于小的memcache集群或者cache集群整体挂掉不会对服务产生严重影响的情况，这种映射方法就简单实用。</p>
<p>当然，更好的选择是一致性hash算法。该算法的效果是减少或增加一个memcache节点，只会影响到整个集群的1/n的数据。在实现方法上，主要有两种：</p>
<p>1、将memcache物理节点均匀地分布在整数范围构成的hash环。当增加一个节点时，可以将该节点插入环上的两个节点之间，这样只会失效1/2n的数据，但会使hash环变得不均衡；另一种方法是，重新分布memcache节点在hash环的位置，这样每个节点的数据都会有些缺失，但缺失的总和是一个节点的数据范围。</p>
<p>2、引入虚拟节点的思想，将一个memcache物理节点散落在hash环上的多个虚拟节点，这在均衡性方法效果会更好些。当然，查找的算法复杂度也由O(1)提高到log(N)。Ketama 算法是实现这个思想的第一个也是用得很多的实现，可以从<a href="http://www.last.fm/user/RJ/journal/2007/04/10/rz_libketama_-_a_consistent_hashing_algo_for_memcache_clients">http://www.last.fm/user/RJ/journal/2007/04/10/rz_libketama_-_a_consistent_hashing_algo_for_memcache_clients</a> 得到这个算法的多语言版本实现。</p>
<p>Memagent使用的一致性hash算法实现就是Ketama，但Memagent在代码方面做了简化修改。Ketama的两个核心数据结构是：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">struct</span> dot <span style="color: #009900;">&#123;</span>
&nbsp;
   <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> point<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">// unsigned int范围内的某个点</span>
&nbsp;
   <span style="color: #993333;">int</span> srvid<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//memcache server id</span>
&nbsp;
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">struct</span> ketama <span style="color: #009900;">&#123;</span>
&nbsp;
   <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> numpoints<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">// 一致性hash的虚拟节点数</span>
&nbsp;
   <span style="color: #993333;">struct</span> dot <span style="color: #339933;">*</span>dot<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//一致性hash的虚拟节点列表</span>
&nbsp;
   <span style="color: #993333;">int</span> count<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//memcache server个数</span>
&nbsp;
   <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>name<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">// 各memcache server名称数组</span>
&nbsp;
   <span style="color: #993333;">int</span> <span style="color: #339933;">*</span>weight<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">// 各memcache server权重，实际都是一样的</span>
&nbsp;
   <span style="color: #993333;">int</span> totalweight<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//权重总和</span>
&nbsp;
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<p><strong>struct</strong> dot结构表示hash环上一个虚拟节点，<strong>struct</strong> ketama是算法的全局性数据结构。Ketama 算法涉及到两个函数是：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> create_ketama<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> ketama <span style="color: #339933;">*</span>ring<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> step<span style="color: #009900;">&#41;</span></pre></div></div>

<p>Ring由Memagent之前根据memcache server集群信息构造而来，step取值为500，函数内部再乘以4，表示一个memcache server在hash环上有2000个虚拟节点。</p>
<p>计算虚拟节点的取值及对应的server id的方法如下：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> ring<span style="color: #339933;">-&gt;</span>count<span style="color: #339933;">;</span> i <span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		pct <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span><span style="color: #009900;">&#41;</span> ring<span style="color: #339933;">-&gt;</span>weight<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span><span style="color: #009900;">&#41;</span> ring<span style="color: #339933;">-&gt;</span>totalweight<span style="color: #339933;">;</span>
		ks <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span> floorf<span style="color: #009900;">&#40;</span>pct <span style="color: #339933;">*</span> step <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span><span style="color: #009900;">&#41;</span> ring<span style="color: #339933;">-&gt;</span>count<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* divide by 4 for 4 part */</span>
		<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>k <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> k <span style="color: #339933;">&lt;</span> ks<span style="color: #339933;">;</span> k <span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			snprintf<span style="color: #009900;">&#40;</span>temp<span style="color: #339933;">,</span> <span style="color: #0000dd;">255</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s-%d&quot;</span><span style="color: #339933;">,</span> ring<span style="color: #339933;">-&gt;</span>name<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> k<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			ketama_md5_digest<span style="color: #009900;">&#40;</span>temp<span style="color: #339933;">,</span> digest<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>h <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> h <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> h <span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
					dot<span style="color: #009900;">&#91;</span>cont<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">point</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> digest<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #339933;">+</span>h<span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;&lt;</span> <span style="color: #0000dd;">24</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">|</span> <span style="color: #009900;">&#40;</span> digest<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">+</span>h<span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;&lt;</span> <span style="color: #0000dd;">16</span> <span style="color: #009900;">&#41;</span>
					   		<span style="color: #339933;">|</span> <span style="color: #009900;">&#40;</span> digest<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">+</span>h<span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;&lt;</span>  <span style="color: #0000dd;">8</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">|</span> digest<span style="color: #009900;">&#91;</span>h<span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
					dot<span style="color: #009900;">&#91;</span>cont<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">srvid</span> <span style="color: #339933;">=</span> i<span style="color: #339933;">;</span>
					cont <span style="color: #339933;">++;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p>最后会对得到的dot列表针对point大小做排序处理，以便<span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;">get_server时的二分查找。</span></p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> get_server<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> ketama <span style="color: #339933;">*,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>这个函数就是根据key从struct ketama结构中找到对应的memcache server index。Cache key的hash值计算使用的是16位的md5算法。根据key的hash值查找对应在hash环上的位置，采用的是二分查找。</p>
<h2>小结</h2>
<p>如果你只想要个简单实用的memcache proxy，memagent是个不错的选择。当然，memcache proxy可以做的工作也可以更多，就像另一个memcache proxy实现moxi（<a href="http://labs.northscale.com/moxi/">http://labs.northscale.com/moxi/</a>）提供了更为丰富的功能，我会在接下来的文章中继续介绍moxi。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/01/9.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

