·
什么是memcached?
Memcached
是高性能的,分布式的内存对象缓存系统,用于在动态
Web
应用中减少数据库负载,提升访问速度。
Danga Interactive
为提升
Danga Interactive
的速度研发了
Memcached
。目前,
LiveJournal.com
每天已经在向一百万用户提供多达两千万次的页面访问。而这些,是由一个由
web
服务器和数据库服务器组成的集群完成的。
Memcached
几乎完全放弃了任何数据都从数据库读取的方式,同时,它还缩短了用户查看页面的速度、更好的资源分配方式,以及
Memcache
失效时对数据库的访问速度。
·
从哪里可以获得memcached?
mecached
可以从它的官方网站下载:
http://www.danga.com/memcached/download.bml.
·
如何安装memcached?
详细讲解,请参考下面网站
http://blog.ajohnstone.com/archives/installing-memcached/.
·
什么场合运行memcached?
用到共享内存的任何地方,你都可以使用
memcached
!
memcached
可以在
linux,BSD,windows
上运行,它通常只占用很少的
CPU
,当有空闲内存的时候可以被触发。
·
为什么可能想要运行memcached?
如果你有一个高访问量的网站,而这个网站是从一个有着很多读线程数据库动态读取产生,数据库负荷很重,
Memcached
可以帮助你减轻数据库的负载。
·
如何存取memcached?
通常,你都是通过客户端库,从你的应用程序访问一个或多个
memcached
服务器。用于
Perl, C, C#, PHP, Python, Java, Ruby, and Postgresql
存储过程和触发器的客户端库,请参考以下网站:
http://www.socialtext.net/memcached/index.cgi?clients or
http://danga.com/memcached/apis.bml
你也可以编写自己的客户端库,
memcached
协议文档在下面网站可以找到:
http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt
·
如何把memcached当作数据库使用?
如果你想使用
memcached
作为数据存储不是一个缓存
,
你应该使用一个数据库
. MySQL
的集群具有一些跟
memcached
相同的特性及
(
但是不容易安装
)
并可以设置为一个可靠的数据库
.
能否遍历
memcached
服务器上所有项目?
不能,
memcached
不支持,也没有计划支持这个特性。这将是一个相对缓慢和容易阻塞的操作(跟现在
memcached
操作正比)。
Memcached
是一个缓存系统,而不是一个数据库。
Tugela
是一个
mecached
驱动的系统,但
memcached
相比有点慢,但有点像一个数据库。
当然,作为一个软件,你也可以配置使其支持这个特性。但是对于除了开发或测试服务器,它的处理速度将会很慢,并且会阻塞服务器。所以99.9%真正的开发将不会采用这种功能。
集群架构问题
·
Memcached
如何工作?
Memcached
神奇之处在于它的两阶段散列方法。通过查询键值对,
memcached
工作起来就像一张巨大的散列表。给出一个键
,
你可以设置或者取得任意数据
.
在这样一个
memcached
查找时
,
首先客户端对整个服务器列表进行散列,
客户端一旦选定了一个服务器
,
客户端发出的请求
,
服务器就为客户端进行内部键值匹配,查找实际数据项
.
举个例子,如果我们有三个客户端
1,2,3
和三台服务器
A
,
B
,
C
:
客户端
1
想要设置把键名为“
foo
”的值设为“
barbaz
”。客户端
1
将对整个服务器列表(
A
,
B
,
C
)进行散列,假设最后选定了服务器
B
。客户端
1
直接连接服务器
B
,并把键名为“
foo”
的值设为“
barbaz
”。接着客户端
2
想要获得键名为“
foo
”的值。客户端
2
执行和客户端相同的客户端库,并拥有整个服务器列表(
A
,
B
,
C
)。客户端
2
能够通过与客户端
1
相当的散列方法算出键名为
”foo”
的键值对存在于服务器
B
上。这样它就可直接从服务器上进行查询,得出键名为“
foo”
的值为“
brabaz
”
.
不同的客户端实现以不同的方式把数据存入
memcached
(
如
perl Storable, php serialize, java hibernate, JSON,
等等)。尽管客户端的散列算法也有所不同,但对于服务器的实现都是一样的。
最后
, memcached
被实现为一个基于事件的非阻塞服务器
.
这个架构用于解决
c10k
问题和和相似规模问题。
·
这样做有什么好处?
仔细阅读上面内容(
Memcached
是怎样工作的呢?)一个大的好处就是当处理巨大的系统时候
,
正是
memcached
的功能极大地缩小了规模。
既然客户端属于散列的一层,这样在服务器上增加节点就变成简单的事情了。不存在超负荷或者容易出错的多协议。内存耗尽?增加节点。
CPU
完全被占全?增加节点。有空闲内存?增加节点。
Memcached
部是能正常工作。
基于memcached基本的规则,很容易构建各种不同的缓存架构。希望FAQ其它部分的讲解比较详尽
。
·
什么是memcached的缓冲
memcached
缓存结构基于
LRU
算法(最近最少使用算法)加上过期超时算法。
当你往
memcached
存储某个对象
,
你可能会声明这个对象在缓存中的有效时间。你可以状态多久的有效期应在快取记忆体
.
这是永远如此
,
还是在未来的一段时间
.
如果服务器是内存耗尽
,
过期的对象最先被清除,接着是最久没使用过的对象。
·
Memcached
是如何冗余的?
它没有,很惊讶!
memcached
是为你应用程序提供的一个缓冲层。它不会有任何的冗余数据。如果一个节点丢失了它所有数据,你仍可以从数据源再次读取数据。特别要注意,当丢失
memcached
实例的时候,你的应用程序能够恢复。不要指望
memcached
为你丑陋的设计修复一切的错误。如果你担心出错时,数据库用法上有太多的难题,你有一些选择。如果你可以增加更多的节点(减轻丢失一个节点的影响),
hotspares,(
当崩溃时接管
IP
地址
)
等。
·
Memcached
如何容错?
Memcached
不会处理容错。当
memcached
节点出错时,没有中心的机制去做任何事情。出错处理完全取决于用户。出现节点错误时,有许多选择你可以采取。
1.
不理会错误!有成千上万个节点,你可以等到能够修复问题或者替代出错节点时候才处理丢失一个节点的影响。
2.
从你的列表中删除死亡的节点。要非常小心,在默认情况下,增加和删除一个服务器都会使缓存全部失效。既然用于散列的服务器列表已经发生改变,大部分的键可能会被散列到跟原来不同的服务器上。这就好像在同一时间,重新启动所有的节点。
3.
使用一个有与死亡节点的
IP
地址,启动一个
hotspare
避免散列混乱。
4.使用一致的散列算法增加和删除服务器节点修复问题。一致的散列算法可参考其它文献,现在客户端还相当的年经。
·
如何从memcached转储或装载数据到memcached?
没有必要!memcached就是我们所说的无阻塞服务器。任何可能造成服务器停顿并且不能马上回应都是很小心的被通过。从转储中加载你的缓存常常不是你想要的。假设你数据在转储和装载缓存中发生任何变化,那你现在就得处理过时的数据。那么你又如何管理这些在转储之前就要过期的item?
它并不像你想得那样有用。曾有一个case,如果你有大量从未改变的数据,并且你希望你的缓存toasty warm, 那么你就可以从转储种加载你的缓存。虽然这不是一个典型的案例,但是它经常出现,并且这种特性很可能会出现在未来的。
·
memcached
的认证机制如果工作?
Memcached
没有认证机制。
memcached
使你的应用变得柔软,弱化。缺乏完整的认证使客户和服务器变得轻量级。新的连接很快,并且服务器段的配置不存在。
如果你想限制权限,你可能需要使用防火墙,或者通过UNIX域套接字建立memcached 监听。
·
什么是Memcached线程,为什么我们要使用它们?
线程统治! 感谢Steven Grimm和Facebook, memcached 1.2和更高版本具有一个线程运行模式。 我不会详细介绍,因为我可能弄错。线程系统允许memcached不仅仅利用的是一个单CPU和在它们之间共享缓存。 当某些values、items需要更新时,它通过一个非常简单的锁机制来实现。 这样有助于愈多愈有效, 相对在同一物理服务器运行多节点就可以获取性能。
如果你没有重量级加载的设置,你也许并不需要配置多线程。如果你在运行一个具有庞大的硬件的庞大网站,你可能会从这里看到受益。
·
我可能会碰到哪些memcached的限制?
你可能会看到的memcached的简单限制就是键(key)和item的限制。最大键长为250个字符。可以接受的储存数据不能超过1MB,因为这是典型slab 的最大值
[1]。
·
什么是二进制协议? 我应该注意它吗?
最佳信息在ML的这个thread上:
http://lists.danga.com/pipermail/memcached/2007-July/004636.html由于写作尚未定型,还没有完成的客户端发布。
二进制协议,尝试使用一个更有效率、可靠的协议来帮助加速用于客户机/服务器协议的CPU时间。根据Facebook的测试, 在memcached中,解析ASCII协议是CPU时间的最大消耗者。那为什么不改进它?
·
memcached
内存如何分配工作? 为何不考虑使用malloc /免费! ? 它到底为什么要使用slabs! ?
实际上,这是一个编译时间的选择。你真的很想使用内置式的slab分配器。起初memcached也确实任何事都使用malloc/免费,但是这并不能很好进行操作系统的内存管理。你获取了碎片,你的操作系统就会比运行memcached进程要花费更多的时间来寻找连续的内存块来满足malloc()。如果你不同意,当然你完全可以尝试!只要不要抱怨。
Slab配置器就是用来解决这点的。内存被内部划分为内存块给服务器并被循环使用,因为内存被分为不同的大小的slab,所以如果你的items没有合适地匹配服务器选择加入的slab,你就浪费了内存。这点已被Steven Grimm做出了相当大的效率改善。
一些关于slab 改进(power of n vs power of 2)的比较老的posts和一些权衡版本都在以下的邮件名单(ML)上:
http://lists.danga.com/pipermail/memcached/2006-May/002163.htmlhttp://lists.danga.com/pipermail/memcached/2007-March/003753.html
·
客户端类
·
什么客户端类可供memcached使用?
参照以上的如何存取memcached。
·
我能否在memcached上使用不同的客户端类获得相同的数据?
从技术角度上,可以,但是你可能会碰到如下两个问题:
1、不同的类连载数据很可能不同,例如, Perl的Cache::Memcached可能会使用可储存的来系列化复杂结构(如哈希引用,对象等)。 这一格式使用其它语言客户端的API极有可能不可读。如果你存储的是复杂数据并且需要对于多种API都是可读的,那你可能就要考虑用一种格式存储简单的字符串,而这种格式是可轻易被外部类进行解析,例如或者XML。
2、同样你的数据可能从一个客户端被压缩,而不是从另一个。
3、不同的类的散列键可能就不同。如果您要连接多个服务器,你的键有可能根据语言API实施的算法进行散列然后储存。极有可能的是,不同的客户端类使用不同的策略来做决策,
所以向服务器A
运行的来自Perl
的键极有可能终止在来自Python
的服务器B
,等等。Perl API
也允许你使用不同的方式来权重你的服务
[MS1] 器,这也可能是一个因素。
·
什么是"稳定散列(consistent hashing)"客户端?
Consistent hashing 算法是一种新的方法来处理memcached客户端的哈希系统的第一层。
一个很好的发布 (和类包) 阐述了它的用法已经由
last.fm发布出来了。
管理memcached集群
Memcached 选择
内存分配
Hashing/Key 分配
Item 到期
·
什么时候到期缓存items可以从缓存中删除?
Memcached使用的一种懒惰到期的方法,即它不使用额外的cpu 到期items。当一个item被请求(GET请求),它就会返回给客户端之前检查到期时间来确定item是否有效。
同样地,当添加一个新的item到缓存中,如果缓存是满的,它就会在替换最少使用的items之前查找缓存中到期的items来进行替换。
·
名称空间
Memcached不支持名称空间。但是,有一些选择可以模拟它们。
·
使用键前缀模拟名称空间
如果你只是想避免不同数据类型的键开头
,
那你只要使用一个有用的字符串来作为你的前缀。例如,
" user_12345 "
,
" article_76890 "
。
·
通过名称空间删除
memcached不支持任何类型的通配符删除或通过名称空间删除(因为没有名称空间), 但是有一些招数,可以用来模拟这点。但是它们确实需要额外的访问memcached服务器。
在PHP中,例如使用一个叫做foo的名称空间:
$ns_key = $memcache->get("foo_namespace_key");
//
如果没有set,初始化它if($ns_key===false) $memcache->set("foo_namespace_key", rand(1, 10000));
$my_key = "foo_".$ns_key."_12345";
清除名称空间
:
$memcache->increment("foo_namespace_key");
应用设计
·
当我设计应用时,关于缓存,我应该考虑一些什么东西?
通用设计方法
(相反地,在这里名称空间/session/等等,应该移走或者被链接)
* 简单的查询结果缓存
WIP: 将查询结果纳入MC,不用考虑更新。
* 简单的基于行的查询结果缓存
WIP: 同上,但是会将行和行块打破成不同的键
* 缓存相关而不是SQL数据!
WIP: 数据的重型视觉处理是可缓存的!试一试!
* 当你的数据更新时更新memcache
WIP
* 竞态条件和失效数据
WIP:
两者同时更新? Uh oh.
* 如
何避免偶尔更新
[MS2]
How to prevent clobbering updates
WIP:
尝试添加锁机制。试图避免这个问题。
* 使用add命令的仿真锁
WIP:
尝试添加
一个退避时间
,
或都不要。如果代码
仿真
GET_LOCK()
就更好了。
* 预热你的缓存
WIP:
加载你认为可能会活跃的
数据,通过步行
[MS3]
或者其他方法来行使你的应用。
Load data you think would be active, by walking or otherwise exercizing your application.
* 效仿名称空间的方式
WIP:
将上述东西拉下来,
讨论屏幕设计。
* 存储清单数据
WIP:
最近有很多很好的ML(mailing list)讨论。
* 在memcache 中存储session 数据
WIP:
链接外部文章
,
谈论更多的选择。
* 用get_multi 批处理你的请求
WIP:
做尽可能少的请求来决定你需要用来建立这页的大多数剩余GET请求
,然后在一个
单命令下获取全部。
可以引用
brad
关于客户端改善的 ML post来说明这点。
FAQ 思路
为缓存队列创建键 amemcached 程式是否意识到彼此? 当一个memcached服务器在集群内外反复时获取stale entries。
(ting stale entries when a memcached server flaps in and out of the cluster
)
除了 Linux外,你还知道其他什么memcached可以使用的平台? (Solaris, AIX, HPUX, SCO)?
参考文献:
[
1] http://hi.baidu.com/hecheng/blog/item/22550923d681604c925807bc.html