<?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>Shining Ray &#187; memcached</title>
	<atom:link href="http://shiningray.cn/tag/memcached/feed" rel="self" type="application/rss+xml" />
	<link>http://shiningray.cn</link>
	<description>一缕阳光</description>
	<lastBuildDate>Mon, 21 Jun 2010 07:11:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Facebook对memcached的提升</title>
		<link>http://shiningray.cn/scaling-memcached-at-facebook.html</link>
		<comments>http://shiningray.cn/scaling-memcached-at-facebook.html#comments</comments>
		<pubDate>Tue, 16 Dec 2008 07:32:22 +0000</pubDate>
		<dc:creator>ShiningRay</dc:creator>
				<category><![CDATA[翻译]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[scalability]]></category>
		<category><![CDATA[UDP]]></category>

		<guid isPermaLink="false">http://shiningray.cn/?p=372</guid>
		<description><![CDATA[原文：Scaling memcached at Facebook 作者：Paul Saab 翻译：ShiningRay 如果你翻阅过一些关于大型网站扩展（Scaling）的资料，那么你可能听说过一个叫memcached的东西。memcached是一个高性能、分布式的内存对象缓存系统。我们Facebook可能是世界上最大的memcached用户了。我们利用memcached来减轻数据库的负担。memcached确实很快，但是我们还要让他更快、更高效。我们使用了超过800台服务器，提供超过28TB的内存来服务于用户。在过去的一年里，随着Facebook的用户量直线上升，我们遇到了一系列的扩展问题。日益增长的需求使得我们必须对操作系统和memcached进行一些修改，以获得足够的性能来为我们的用户提供最好的体验。 因为我们有好几千台机器，每个都运行了几百个Apache进程甚至更多，最终导致到memcached进程的TCP链接有几十万个。这些链接本身并不是什么大问题，但是memcached为每个TCP链接分配内存的方法却很成问题。memcached为每个链接使用单独的缓存进行数据的读写。当达到几十万链接的时候，这些累计起来达好几个G——这些内存其实可以更好地用于存储用户数据。为了收复这些内存，我们实现了一个针对TCP和UDP套接字的每线程共享的链接缓存池。这个改变使每个服务器可以收回几个G的内存。 虽然TCP上我们改进了内存的使用效率，但我们还是转向了UDP，目的是让get（获取）操作能降低网络流量、让multi-get（同时并行地获取几百个键值）能实现应用程序级别的流量控制。我们发现Linux上到了一定负载之后，UDP的性能下降地很厉害。这是由于，当从多个线程通过单个套接字传递数据时，在UDP套接字锁上产生的大量锁竞争导致的。要通过分离锁来修复内核恐怕不太容易。所以，我们使用了分离的UDP套接字来传递回复（每个线程用一个答复套接字）。这样改动之后，我们就可以部署UDP同时后端性能不打折。 另一个Linux中的问题是到了一定负载后，某个核心可能因进行网络软终端处理会饱和而限制了网络IO。在Linux中，网络中断只会总是传递给某个核心，因此所有的接受软终端的网络处理都发生在该内核上。另外，我们还发现某些网卡有过高的中断频率。我们通过引入网络接口的“投机”轮询解决了这两个问题。在该模型中，我们组合了中断驱动和轮询驱动的网络IO。一旦进入网络驱动（通常是传输一个数据包时）以及在进程调度器的空闲循环的时候，对网络接口进行轮询。另外，我们也用到了中断（来控制延迟），不过网络中断用到的数量大大减少（一般通过大幅度提升中断联结阈值interrupt coalescing thresholds）。由于我们在每个核心上进行网络传输，同时由于在调度器的空闲循环中对网络IO进行轮询，我们将网络处理均匀地分散到每个核心上。 最后，当开始部署8核机器的时候，我们在测试中发现了新的瓶颈。首先，memcached的stat工具集依赖于一个全局锁。这在4核上已经很令人讨厌了，在8核上，这个锁可以占用20-30%的CPU使用率。我们通过将stats工具集移入每个线程，并且需要的时候将结果聚合起来。其次，我们发现随着传递UDP数据包的线程数量的增加，性能却在降低。最后在保护每个网络设备的传送队列的锁上发现了严重的争用。数据包是由设备驱动进行入队传输和出队。该队列由Linux的“netdevice”层来管理，它位于IP和设备驱动之间。每次只能有一个数据包加入或移出队列，这造成了严重的争用。我们当中的一位工程师修改了出队算法，实现了传输的批量出队，去掉了队列锁，然后批量传送数据包。这个更正将请求锁的开销平摊到了多个数据包，显著地减少了锁争用，这样我们就能在8核系统上将memcached伸展至8线程。 做了这些修改之后，我们可以将memcached提升到每秒处理20万个UDP请求，平均延迟降低为173微秒。可以达到的总吞吐量为30万UDP请求/s，不过在这个请求速度上的延迟太高，因此在我们的系统中用处不大。对于普通版本的Linux和memcached上的50,000 UDP请求/s而言，这是个了不起的提升。 我们希望尽快将我们的修改集成到官方的memcached仓库中去，我们决定在这之前，先将我们对memcached的修改发布到github上。]]></description>
			<content:encoded><![CDATA[<ul>
<li>原文：<a href="http://www.facebook.com/note.php?note_id=39391378919">Scaling memcached at Facebook</a></li>
<li>作者：<a href="http://www.facebook.com/people/Paul-Saab/500025857">Paul Saab</a></li>
<li>翻译：<a href="http://shiningray.cn/">ShiningRay</a></li>
</ul>
<p>如果你翻阅过一些关于大型网站扩展（Scaling）的资料，那么你可能听说过一个叫<a title="http://danga.com/memcached/" href="http://www.facebook.com/note_redirect.php?note_id=39391378919&amp;h=d7cdfa0dab0355b2485228092a61daec&amp;url=http%3A%2F%2Fdanga.com%2Fmemcached%2F" target="_blank">memcached</a>的东西。memcached是一个高性能、分布式的内存对象缓存系统。我们Facebook可能是世界上最大的memcached用户了。我们利用memcached来减轻数据库的负担。memcached确实很快，但是我们还要让他更快、更高效。我们使用了超过800台服务器，提供超过28TB的内存来服务于用户。在过去的一年里，随着Facebook的用户量直线上升，我们遇到了一系列的扩展问题。日益增长的需求使得我们必须对操作系统和memcached进行一些修改，以获得足够的性能来为我们的用户提供最好的体验。</p>
<p>因为我们有好几千台机器，每个都运行了几百个Apache进程甚至更多，最终导致到memcached进程的TCP链接有几十万个。这些链接本身并不是什么大问题，但是memcached为每个TCP链接分配内存的方法却很成问题。memcached为每个链接使用单独的缓存进行数据的读写。当达到几十万链接的时候，这些累计起来达好几个G——这些内存其实可以更好地用于存储用户数据。为了收复这些内存，我们实现了一个针对TCP和UDP套接字的每线程共享的链接缓存池。这个改变使每个服务器可以收回几个G的内存。</p>
<p>虽然TCP上我们改进了内存的使用效率，但我们还是转向了UDP，目的是让get（获取）操作能降低网络流量、让multi-get（同时并行地获取几百个键值）能实现应用程序级别的流量控制。我们发现Linux上到了一定负载之后，UDP的性能下降地很厉害。这是由于，当从多个线程通过单个套接字传递数据时，在UDP套接字锁上产生的大量锁竞争导致的。要通过分离锁来修复内核恐怕不太容易。所以，我们使用了分离的UDP套接字来传递回复（每个线程用一个答复套接字）。这样改动之后，我们就可以部署UDP同时后端性能不打折。</p>
<p>另一个Linux中的问题是到了一定负载后，某个核心可能因进行网络软终端处理会饱和而限制了网络IO。在Linux中，网络中断只会总是传递给某个核心，因此所有的接受软终端的网络处理都发生在该内核上。另外，我们还发现某些网卡有过高的中断频率。我们通过引入网络接口的“投机”轮询解决了这两个问题。在该模型中，我们组合了中断驱动和轮询驱动的网络IO。一旦进入网络驱动（通常是传输一个数据包时）以及在进程调度器的空闲循环的时候，对网络接口进行轮询。另外，我们也用到了中断（来控制延迟），不过网络中断用到的数量大大减少（一般通过大幅度提升中断联结阈值interrupt coalescing thresholds）。由于我们在每个核心上进行网络传输，同时由于在调度器的空闲循环中对网络IO进行轮询，我们将网络处理均匀地分散到每个核心上。</p>
<p>最后，当开始部署8核机器的时候，我们在测试中发现了新的瓶颈。首先，memcached的stat工具集依赖于一个全局锁。这在4核上已经很令人讨厌了，在8核上，这个锁可以占用20-30%的CPU使用率。我们通过将stats工具集移入每个线程，并且需要的时候将结果聚合起来。其次，我们发现随着传递UDP数据包的线程数量的增加，性能却在降低。最后在保护每个网络设备的传送队列的锁上发现了严重的争用。数据包是由设备驱动进行入队传输和出队。该队列由Linux的“netdevice”层来管理，它位于IP和设备驱动之间。每次只能有一个数据包加入或移出队列，这造成了严重的争用。我们当中的一位工程师修改了出队算法，实现了传输的批量出队，去掉了队列锁，然后批量传送数据包。这个更正将请求锁的开销平摊到了多个数据包，显著地减少了锁争用，这样我们就能在8核系统上将memcached伸展至8线程。</p>
<p>做了这些修改之后，我们可以将memcached提升到每秒处理20万个UDP请求，平均延迟降低为173微秒。可以达到的总吞吐量为30万UDP请求/s，不过在这个请求速度上的延迟太高，因此在我们的系统中用处不大。对于普通版本的Linux和memcached上的50,000 UDP请求/s而言，这是个了不起的提升。</p>
<p>我们希望尽快将我们的修改集成到官方的memcached仓库中去，我们决定在这之前，先将我们对memcached的修改发布到<a title="http://github.com/fbmarc/facebook-memcached" href="http://www.facebook.com/note_redirect.php?note_id=39391378919&amp;h=ad011a56d1398e90d074fe748116d967&amp;url=http%3A%2F%2Fgithub.com%2Ffbmarc%2Ffacebook-memcached" target="_blank">github</a>上。</p>
]]></content:encoded>
			<wfw:commentRss>http://shiningray.cn/scaling-memcached-at-facebook.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Rails内置缓存引擎与线程安全</title>
		<link>http://shiningray.cn/rails-built-in-cache-engine-and-thread-safety.html</link>
		<comments>http://shiningray.cn/rails-built-in-cache-engine-and-thread-safety.html#comments</comments>
		<pubDate>Tue, 16 Dec 2008 04:00:29 +0000</pubDate>
		<dc:creator>ShiningRay</dc:creator>
				<category><![CDATA[翻译]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[thread safety]]></category>
		<category><![CDATA[线程安全]]></category>

		<guid isPermaLink="false">http://shiningray.cn/?p=368</guid>
		<description><![CDATA[升级到Rails 2.1之后，使用Rails内置的缓存之后，发现使用mem_cache_store总是报错，于是干脆研究了Rails内置缓存引擎的代码。阅读的结果发现，Rails的内置引擎只应该应用于进程模式，尤其是mem_cache_store，因为mem_cache_store是每进程建立一个到memcached的链接，即便是读取，也需要写入套接字，所以为了同步，必须使用锁。因此即使在读取缓存的时候，也会出现争用的情况。mem_cache_store也必须像Rails2.2中的ActiveRecord一样实现一个到memcached的线程池，或者使用异步链接，否则是发挥不出memcached的效率的。 我研究了另外几个cache_store， memory_store则根本连锁机制都没有，但对应有个多线程的synchronized_memory_store，使用了Monitor； drb_store没有用过，可能Drb本身有一些同步机制，但估计也可能会出现与mem_cache_store一样的问题； file_store应该是在多线程中应该比较理想的，因为使用了文件系统自身的同步机制，使用了File.atomic_write，无论是多线程还是多进程都能共享同一个file_store。 所以，Rails的线程安全还有很长一段路要走。 PS：前面的我说的我遇到的mem_cache_store的错误是Rails.cache.fetch误加了:raw =&#62; true 参数。]]></description>
			<content:encoded><![CDATA[<p>升级到Rails 2.1之后，使用Rails内置的缓存之后，发现使用mem_cache_store总是报错，于是干脆研究了Rails内置缓存引擎的代码。阅读的结果发现，Rails的内置引擎只应该应用于进程模式，尤其是mem_cache_store，因为mem_cache_store是每进程建立一个到memcached的链接，即便是读取，也需要写入套接字，所以为了同步，必须使用锁。因此即使在读取缓存的时候，也会出现争用的情况。mem_cache_store也必须像Rails2.2中的<code>ActiveRecord</code>一样实现一个到memcached的线程池，或者使用异步链接，否则是发挥不出memcached的效率的。</p>
<p>我研究了另外几个cache_store，</p>
<ul>
<li>memory_store则根本连锁机制都没有，但对应有个多线程的synchronized_memory_store，使用了<code>Monitor</code>；</li>
<li>drb_store没有用过，可能Drb本身有一些同步机制，但估计也可能会出现与mem_cache_store一样的问题；</li>
<li>file_store应该是在多线程中应该比较理想的，因为使用了文件系统自身的同步机制，使用了<code>File.atomic_write</code>，无论是多线程还是多进程都能共享同一个file_store<code>。</code></li>
</ul>
<p>所以，Rails的线程安全还有很长一段路要走。</p>
<p>PS：前面的我说的我遇到的mem_cache_store的错误是<code>Rails.cache.fetch</code>误加了<code>:raw =&gt; true</code> 参数。</p>
]]></content:encoded>
			<wfw:commentRss>http://shiningray.cn/rails-built-in-cache-engine-and-thread-safety.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails + Memcached = Undefined Class/Module?</title>
		<link>http://shiningray.cn/rails-memcached-undefined-classmodule.html</link>
		<comments>http://shiningray.cn/rails-memcached-undefined-classmodule.html#comments</comments>
		<pubDate>Mon, 10 Dec 2007 08:28:49 +0000</pubDate>
		<dc:creator>ShiningRay</dc:creator>
				<category><![CDATA[备忘]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://shiningray.cn/2007/12/10/rails-memcached-undefined-classmodule/</guid>
		<description><![CDATA[问题描述： 当使用memcached并将Model对象保存在其中时，若要取出这个缓存对象时，可能会找不到Model的类，并抛出“Undefined Class/Module SomeClass”的错误。 例如： if not (genres = Cache.get(key)) genres = Genre.find(:all, :condition =&#62; "platform_id = 1") Cache.put(key, genres, 60*60*24) # cache for 1 day end 解决方案 要解决这个问题，可以在引用到该对象之间，先引用其类。比如，在前面的代码前面加入要引用的类Genre： Genre if not (genres = Cache.get(key)) genres = Genre.find(:all, :condition =&#62; "platform_id = 1") Cache.put(key, genres, 60*60*24) # cache for 1 day end 还有更好地方法是在Controller的before_filter中加载所依赖的所有Model： before_filter :preload_models [...]]]></description>
			<content:encoded><![CDATA[<p><strong>问题描述：</strong><br />
当使用memcached并将Model对象保存在其中时，若要取出这个缓存对象时，可能会找不到Model的类，并抛出“Undefined Class/Module SomeClass”的错误。<br />
例如：</p>
<pre class="code" lang="ruby">if not (genres = Cache.get(key))
  genres = Genre.find(:all, :condition =&gt; "platform_id = 1")
  Cache.put(key, genres, 60*60*24) # cache for 1 day
end</pre>
<p><strong>解决方案</strong><br />
要解决这个问题，可以在引用到该对象之间，先引用其类。比如，在前面的代码前面加入要引用的类Genre：</p>
<pre class="code" lang="ruby">
Genre
if not (genres = Cache.get(key))
  genres = Genre.find(:all, :condition =&gt; "platform_id = 1")
  Cache.put(key, genres, 60*60*24) # cache for 1 day
end</pre>
<p>还有更好地方法是在Controller的before_filter中加载所依赖的所有Model：</p>
<pre class="code" lang="ruby">before_filter  :preload_models
def preload_models
  Model1
  Model2
  ...
  ...
  ...
  Model9
end</pre>
<p><strong>结论</strong><br />
这个问题应该是Rails的一个Bug，不知道在2.0中有没有解决。我猜测是因为Rails中很多类信息是lazy load的，而从memcached中取出时没有附带类信息，也不知道如何加载，而通过上面的方法预先加载所需的类和其相关的类的信息，便解决了这个问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://shiningray.cn/rails-memcached-undefined-classmodule.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
