基本问题 算法
一、memcached的基本设置
1)启动Memcache的服务器端
# /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 12000 -c 256 -P /tmp/memcached.pid sql
-d选项是启动一个守护进程,
-m是分配给Memcache使用的内存数量,单位是MB,我这里是10MB,
-u是运行Memcache的用户,我这里是root,
-l是监听的服务器IP地址,若是有多个地址的话,我这里指定了服务器的IP地址192.168.0.200,
-p是设置Memcache监听的端口,我这里设置了12000,最好是1024以上的端口,
-c选项是最大运行的并发链接数,默认是1024,我这里设置了256,按照你服务器的负载量来设定,
-P是设置保存Memcache的pid文件,我这里是保存在 /tmp/memcached.pid, 数据库
2)若是要结束Memcache进程,执行: 缓存
# kill `cat /tmp/memcached.pid` 安全
哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据惟一且极其紧凑的数值表示形式。若是散列一段明文并且哪怕只更改该 服务器
段落的一个字母,随后的哈希都将产生不一样的值。要找到散列为同一个值的两个不一样的输入,在计算上是不可能的。 网络
二、一致性Hash算法的目的有两点:一是节点变更后其余节点受影响尽量小;二是节点变更后数据从新分配尽量均衡 。 session
三、为何要运行 memcached ? 多线程
若是网站的高流量很大而且大多数的访问会形成数据库高负荷的情况下,使用 memcached 可以减轻数据库的压力。 并发
四、适用memcached的业务场景?
1)若是网站包含了访问量很大的动态网页,于是数据库的负载将会很高。因为大部分数据库请求都是读操做,那么memcached能够显著地减少数据库负载。
2)若是数据库服务器的负载比较低但CPU使用率很高,这时能够缓存计算好的结果( computed objects )和渲染后的网页模板(enderred templates)。
3)利用memcached能够缓存session数据、临时数据以减小对他们的数据库写操做。
4)缓存一些很小可是被频繁访问的文件。
5)缓存Web 'services'(非IBM宣扬的Web Services,译者注)或RSS feeds的结果.。
五、不适用memcached的业务场景?
1)缓存对象的大小大于1MB
Memcached自己就不是为了处理庞大的多媒体(large media)和巨大的二进制块(streaming huge blobs)而设计的。
2)key的长度大于250字符
3)虚拟主机不让运行memcached服务
若是应用自己托管在低端的虚拟私有服务器上,像vmware, xen这类虚拟化技术并不适合运行memcached。Memcached须要接管和控制大块的内存,若是memcached管理的内存
被OS或 hypervisor交换出去,memcached的性能将大打折扣。
4)应用运行在不安全的环境中
Memcached为提供任何安全策略,仅仅经过telnet就能够访问到memcached。若是应用运行在共享的系统上,须要着重考虑安全问题。
5)业务自己须要的是持久化数据或者说须要的应该是database
六、可以遍历memcached中全部的item吗?
不能,这个操做的速度相对缓慢且阻塞其余的操做(这里的缓慢时相比memcached其余的命令)。memcached全部非调试(non-debug)命令,例如add, set, get, fulsh等不管
memcached中存储了多少数据,它们的执行都只消耗常量时间。任何遍历全部item的命令执行所消耗的时间,将随着memcached中数据量的增长而增长。当其余命令由于等待(遍历所
有item的命令执行完毕)而不能获得执行,于是阻塞将发生。
集群的相关问题
七、memcached是怎么工做的?
Memcached的高性能源于两阶段哈希(two-stage hash)结构。Memcached就像一个巨大的、存储了不少<key,value>对的哈希表。经过key,能够存储或查询任意的数据。 客户端
能够把数据存储在多台memcached上。当查询数据时,客户端首先参考节点列表计算出key的哈希值(阶段一哈希),进而选中一个节点;客户端将请求发送给选中的节点,而后
memcached节点经过一个内部的哈希算法(阶段二哈希),查找真正的数据(item)并返回给客户端。从实现的角度看,memcached是一个非阻塞的、基于事件的服务器程序。
八、memcached最大的优点是什么?
Memcached最大的好处就是它带来了极佳的水平可扩展性,特别是在一个巨大的系统中。因为客户端本身作了一次哈希,那么咱们很容易增长大量memcached到集群中。memcached
之间没有相互通讯,所以不会增长 memcached的负载;没有多播协议,不会网络通讯量爆炸(implode)。
九、memcached和MySQL的query cache相比,有什么优缺点?
缺点:
1)相比MySQL的query cache,把memcached引入应用中须要很多的工做量。MySQL的query cache,能够自动地缓存SQL查询的结果,被缓存的SQL查询能够被反复、快速的执行。
优势:
1)当修改表时,MySQL的query cache会马上被刷新(flush)。当写操做很频繁时,MySQL的query cache会常常让全部缓存数据都失效。
2)在多核CPU上,MySQL的query cache会遇到扩展问题(scalability issues)。在多核CPU上,query cache会增长一个全局锁(global lock), 因为须要刷新更多的缓存数据,速度
会变得更慢。
3)在MySQL的query cache中,是不能存储任意的数据的(只能是SQL查询结果)。利用memcached,咱们能够搭建出各类高效的缓存。好比,能够执行多个独立的查询,构建出一个
用户对象(user object),而后将用户对象缓存到memcached中。而query cache是SQL语句级别的,不可能作到这一点。在小的网站中,query cache会有所帮助,但随着网站规模的
增长,query cache的弊将大于利。
4)query cache可以利用的内存容量受到MySQL服务器空闲内存空间的限制。给数据库服务器增长更多的内存来缓存数据,当然是很好的。可是,有了memcached,只要您有空闲的内
存,均可以用来增长memcached集群的规模,而后您就能够缓存更多的数据。
十、memcached和服务器的local cache(好比PHP的APC、mmap文件等)相比,有什么优缺点?1)首先,local cache面临着严重的内存限制,可以利用的内存容量受到(单台)服务器空闲内存空间的限制。
2)local cache有一点比memcached和query cache都要好,那就是它不但能够存储任意的数据,并且没有网络存取的延迟。所以,local cache的数据查询更快。考虑把highly
common的数据放在local cache中吧。若是每一个页面都须要加载一些数量较少的数据,能够考虑把它们放在local cached。
3)local cache缺乏集体失效(group invalidation)的特性。在memcached集群中,删除或更新一个key会让全部的观察者觉察到。可是在local cache中, 咱们只能通知全部的服务器
刷新cache(很慢,不具扩展性)或者仅仅依赖缓存超时失效机制。
十一、memcached的cache机制是怎样的?
Memcached主要的cache机制是LRU(最近最少用)算法+超时失效。当您存数据到memcached中,能够指定该数据在缓存中能够呆多久Which is forever, or some time in the
future。若是memcached的内存不够用了,过时的slabs会优先被替换,接着就轮到最老的未被使用的slabs。
十二、memcached如何实现冗余机制?
不实现!Memcached应该是应用的缓存层,从设计自己来京就不带有任何冗余机制。若是一个memcached节点失去了全部数据,应该能够从数据源(好比数据库)再次获取到数据。应
用系统应该能够容忍节点的失效。若是担忧节点失效会大大加剧数据库的负担,那么能够采起一些办法。好比您能够增长更多的节点(来减小丢失一个节点的影响),热备节点(在其余节
点down了的时候接管IP)等等。
1三、memcached如何处理容错的?
在节点失效的状况下,集群没有必要作任何容错处理。若是发生了节点失效,应对的措施彻底取决于用户。
节点失效时,下面列出几种方案供您选择:
1)忽略它! 在失效节点被恢复或替换以前,还有不少其余节点能够应对节点失效带来的影响。
2)把失效的节点从节点列表中移除。作这个操做千万要当心!在默认状况下(余数式哈希算法),客户端添加或移除节点,会致使全部的缓存数据不可用!由于哈希参照的节点列表变化
了,大部分key会由于哈希值的改变而被映射到(与原来)不一样的节点上。
3)启动热备节点,接管失效节点所占用的IP。这样能够防止哈希紊乱(hashing chaos)。
4)若是但愿添加和移除节点,而不影响原先的哈希结果,可使用一致性哈希算法(consistent hashing)。
5)两次哈希(reshing)。当客户端存取数据时,若是发现一个节点down了,就再作一次哈希(哈希算法与前一次不一样),从新选择另外一个节点(须要注意的时,客户端并无把down
的节点从节点列表中移除,下次仍是有可能先哈希到它)。若是某个节点时好时坏,两次哈希的方法就有风险了,好的节点和坏的节点上均可能存在脏数据(stale data)。
1四、如何将memcached中item批量导入导出?
不该该这样作!Memcached是一个非阻塞的服务器。任何可能致使memcached暂停或瞬时拒绝服务的操做都应该值得深思熟虑。向memcached中批量导入数据每每不是您真正想要
的!想象看,若是缓存数据在导出导入之间发生了变化,您就须要处理脏数据了;若是缓存数据在导出导入之间过时了,您又怎么处理这些数据呢?
所以,批量导出导入数据并不像想象中的那么有用。不过在一个场景却是颇有用。若是您有大量的从不变化 的数据,而且但愿缓存很快热(warm)起来,批量导入缓存数据是颇有帮助
的。
1五、可是我确实须要把memcached中的item批量导出导入,怎么办??
若是须要批量导出和导入,最可能的缘由通常是从新生成缓存数据须要消耗很长的时间或者数据库坏了让您饱受痛苦。
若是一个memcached节点down了让您很痛苦,那么必须对数据库作一些优化工做。好比处理"惊群"问题( memcached节点都失效了,反复的查询让数据库不堪重负)或者存在优化不
好的查询等。Memcached 并非逃避优化查询的借口和方案。
这里给出一些提示:
使用MogileFS(或者CouchDB等相似的软件)在存储item,把item计算出来并dump到磁盘上。MogileFS能够很方便地覆写item,并提供快速地访问。甚至能够把MogileFS中的item
缓存在memcached中,这样能够加快读取速度。 MogileFS+Memcached的组合能够加快缓存不命中时的响应速度,提升网站的可用性。
从新使用MySQL。MySQL的 InnoDB主键查询速度很是快。若是大部分缓存数据均可以放到VARCHAR字段中,那么主键查询的性能将更好。从memcached中按key查询几乎等价于
MySQL的主键查询:将key 哈希到64-bit的整数,而后将数据存储到MySQL中。您能够把原始(不作哈希)的key存储都普通的字段中,而后创建二级索引来加快查询...key被动地失效,
批量删除失效的key,等等。
没有身份认证机制!memcached是运行在应用下层的软件(身份验证应该是应用上层的职责)。memcached的客户端和服务器端之因此是轻量级的,部分缘由就是彻底没有实现身份验
证机制。这样,memcached能够很快地建立新链接,服务器端也无需任何配置。若是您但愿限制访问,您可使用防火墙,或者让memcached监听unix domain socket。
1七、memcached的多线程是什么?如何使用它们?
线程就是定律(threads rule)!在Steven Grimm和Facebook的努力下,memcached 1.2及更高版本拥有了多线程模式。多线程模式容许memcached可以充分利用多个CPU,并在
CPU之间共享全部的缓存数据。memcached使用一种简单的锁机制来保证数据更新操做的互斥。相比在同一个物理机器上运行多个memcached实例,这种方式可以更有效地处理multi
gets。若是系统的负载并不重,那么不须要启用多线程工做模式。若是您在运行一个拥有大规模硬件的、庞大的网站,将体验到看到多线程的好处。更多信息请参见:
http://code.sixapart.com/svn/memcached/trunk/server/doc/threads.txt 。
简单地总结一下:命令解析(memcached在这里花了大部分时间)能够运行在多线程模式下。memcached内部对数据的操做是基于不少全局锁的(所以这部分工做不是多线程的)。未
来对多线程模式的改进,将移除大量的全局锁,提升memcached在负载极高的场景下的性能。
1八、memcached能接受的key的最大长度是多少?
memcached能接受的key的最大长度是250个字符。须要注意的是,250是memcached服务器端内部的限制。若是使用的Memcached客户端支持"key的前缀"或相似特性,那么key
(前缀+原始key)的最大长度是能够超过250个字符的。推荐使用较短的key,这样能够节省内存和带宽。
1九、memcached对item的过时时间有什么限制?
item对象的过时时间最长能够达到30天。memcached把传入的过时时间(时间段)解释成时间点后,一旦到了这个时间点,memcached就把item置为失效状态,这是一个简单但
obscure的机制。
20、memcached最大能存储多大的单个item?
memcached最大能存储1MB的单个item。若是须要被缓存的数据大于1MB,能够考虑在客户端压缩或拆分到多个key中。
2一、为何单个item的大小被限制在1M byte以内?
简单的回答:由于内存分配器的算法就是这样的。
详细的回答:
1)Memcached的内存存储引擎,使用slabs来管理内存。内存被分红大小不等的slabs chunks(先分红大小相等的slabs,而后每一个slab被分红大小相等chunks,不一样slab的chunk大小
是不相等的)。chunk的大小依次从一个最小数开始,按某个因子增加,直到达到最大的可能值。若是最小值为400B,最大值是1MB,因子是1.20,各个slab的chunk的大小依次是:
slab1 - 400B;slab2 - 480B;slab3 - 576B ...slab中chunk越大,它和前面的slab之间的间隙就越大。所以,最大值越大,内存利用率越低。Memcached必须为每一个slab预先分配内
存,所以若是设置了较小的因子和较大的最大值,会须要为Memcached提供更多的内存。
2)不要尝试向memcached中存取很大的数据,例如把巨大的网页放到mencached中。由于将大数据load和unpack到内存中须要花费很长的时间,从而致使系统的性能反而很差。若是
确实须要存储大于1MB的数据,能够修改slabs.c:POWER_BLOCK的值,而后从新编译memcached;或者使用低效的malloc/free。另外,可使用数据库、MogileFS等方案代替
Memcached系统。
2二、能够在不一样的memcached节点上使用大小不等的缓存空间吗?若是这么作以后,memcached可以更有效地使用内存吗?
Memcache客户端仅根据哈希算法来决定将某个key存储在哪一个节点上,而不考虑节点的内存大小。所以,能够在不一样的节点上使用大小不等的内存做为缓存空间。可是通常能够这样作
:拥有较多内存的节点上能够运行多个memcached实例,每一个实例使用的内存跟其余节点上的实例相同。
2三、什么是二进制协议,是否须要关注?
二进制协议尝试为端提供一个更有效的、可靠的协议,减小客户端/服务器端因处理协议而产生的CPU时间。根据Facebook的测试,解析ASCII协议是memcached中消耗CPU时间最多的
环节。
2四、memcached的内存分配器是如何工做的?为何不适用malloc/free!?为什么要使用slabs?
实际上,这是一个编译时选项。默认会使用内部的slab分配器,并且确实应该使用内建的slab分配器。最先的时候,memcached只使用malloc/free来管理内存。然而,这种方式不能与
OS的内存管理之前很好地工做。反复地malloc/free形成了内存碎片,OS最终花费大量的时间去查找连续的内存块来知足malloc的请求,而不是运行memcached进程。slab分配器就是
为了解决这个问题而生的。内存被分配并划分红chunks,一直被重复使用。由于内存被划分红大小不等的slabs,若是item的大小与被选择存放它的slab不是很合适的话,就会浪费一些内存。
2五、memcached是原子的吗?
全部的被发送到memcached的单个命令是彻底原子的。若是您针对同一份数据同时发送了一个set命令和一个get命令,它们不会影响对方。它们将被串行化、前后执行。即便在多线程模
式,全部的命令都是原子的。然是,命令序列不是原子的。若是首先经过get命令获取了一个item,修改了它,而后再把它set回memcached,系统不保证这个item没有被其余进程
(process,未必是操做系统中的进程)操做过。memcached 1.2.5以及更高版本,提供了gets和cas命令,它们能够解决上面的问题。若是使用gets命令查询某个key的item,
memcached会返回该item当前值的惟一标识。若是客户端程序覆写了这个item并想把它写回到memcached中,能够经过cas命令把那个惟一标识一块儿发送给memcached。若是该item
存放在memcached中的惟一标识与您提供的一致,写操做将会成功。若是另外一个进程在这期间也修改了这个item,那么该item存放在memcached中的惟一标识将会改变,写操做就会
失败。
性能和客户端库方面的问题
2六、memcached没有个人database快,为何?
在一对一比较中,memcached可能没有SQL查询快。可是,这不是memcached的设计目标。Memcached的目标是可伸缩性。当链接和请求增长的时候,memcached的性能将比
大多数数据库查询好。能够先在高负载的环境(并发的链接和请求)中测试您的代码,而后再决定memcached是否适合您。
2七、使用不一样的客户端库,能够访问到memcached中相同的数据吗?
从技术上说,是能够的。可是可能会遇到下面三个问题:
1)不一样的库采用不一样的方式序列化数据。举个例子,perl的Cache::Memcached使用Storable来序列化结构复杂的数据(好比hash references, objects, 等)。其余语言的客户端库很
可能不能读取这种格式的数据。若是您要存储复杂的数据而且想被多种客户端库读取,那么您应该以简单的string格式来存储,而且这种格式能够被JSON、XML等外部库解析。
2)从某个客户端来的数据被压缩了,从另外一个客户端来的却没被压缩。
3)各个客户端库可能使用不一样的哈希算法(阶段一哈希)。在链接到多个memcached服务器端的状况下,客户端库根据自身实现的哈希算法把key映射到某台memcached上。正是由于
不一样的客户端库使用不一样的哈希算法,因此被Perl客户端库映射到memcached A的key,可能又会被Python客户端库映射到memcached B,等等。Perl客户端库还容许为每台
memcached指定不一样的权重(weight),这也是致使这个问题的一个因素。
这里有一篇文章很好地解释了它的用处:http://www.last.fm/user/RJ/journal/2007/04/10/392555 。
客户端能够经过"前缀"来给key设置一个域(命名空间)。例如,在一个共享主机的环境中,能够将客户姓名做为"前缀",为key建立一个特定的域。在存储数据的时候,"前缀"能够用在
key上,可是不该该参与哈希计算。目前,memcached本身尚未实现针对复杂结构数据的序列化方法,JSON则是一种被普遍使用的对象序列化格式。
哈希 / 键分布
2九、何时失效的数据项会从缓存中删除?
memcached 使用懒失效,当客户端请求数据项时, memcached 在返回数据前会检查失效时间来肯定数据项是否已经失效。一样地,当添加一个新的数据项时,若是缓存已经满了, memcached 就会先替换失效的数据项,而后才是缓存中最少使用的数据项。
命名空间
30、memcached 不支持命名空间。如下提供几种模仿命名空间的方式:
1)用键的前缀模仿命名空间:在真实的键以前加入有意义的前缀。
2)用命名空间删除数据项:尽管 memcached 不支持使用任何类型的通配符或命名空间来完成删除操做,可是能够采用一些技巧来替代:
在 PHP 中使用一个叫 foo 的命名空间:$ns_key = $memcache->get("foo_namespace_key");
// if not set, initialize it
if($ns_key=false) $memcache->set("foo_namespace_key", rand(1, 10000));
$my_key = "foo_".$ns_key."_12345";
清除命名空间:$memcache->increment("foo_namespace_key");
应用设计
3一、在设计应用时,能够经过Memcached缓存那些内容?
1)缓存简单的查询结果:查询缓存存储了给定查询语句对应的整个结果集,最合适缓存那些常常被用到,但不会改变的 SQL 语句对查询到的结果集,好比载入特定的过滤内容。
$key = md5('SELECT * FROM rest_of_sql_statement_goes_here');
if ($memcache->get($key)) {
` return $memcache->get($key);`
}else {
` // Run the query and transform the result data into your final dataset form`
` $result = $query_results_mangled_into_most_likely_an_array`
` $memcache->set($key, $result, TRUE, 86400); // Store the result of the query for a day`
` return $result;`
}
记住,若是查询语句对应的结果集改变,该结果集不会展示出来。这种方法不老是有用,但它确实让工做变得比较快。
2)缓存简单的基于行的查询结果:基于行的缓存会检查缓存数据key的列表,那些在缓存中的行能够直接被取出,不在缓存中的行将会从数据库中取出并以惟一的键为标识缓存起来,最
后加入到最终的数据集中返回。随着时间的推移,大多数数据都会被缓存,这也意味着相比与数据库,查询语句会更多地从 memcached 中获得数据行。若是数据是至关静态的,咱们可
以设置一个较长的缓存时间。
基于行的缓存模式对下面这种搜索状况特别有用:数据集自己很大或是数据集是从多张表中获得,而数据集取决于查询的输入参数可是查询的结果集之间的有重复部分。
好比,若是你有用户 A , B , C , D , E 的数据集。你去点击一张显示用户 A , B , E 信息的页面。首先, memcached 获得 3 个不一样的键,每一个对应一个用户去缓存中查找,所有未
命中。而后就到数据库中用 SQL 查询获得 3 个用户的数据行,并缓存他们。
如今,你又去点击另外一张显示显示 C , D , E 信息的页面。当你去查找 memcached 时, C , D 的数据并无被命中,但咱们命中了 E 的数据。而后从数据库获得 C , D 的行数据,缓
存在 memcached 中。至此之后,不管这些用户信息怎样地排列组合,任何关于 A , B , C , D , E 信息的页面均可以从 memcached 获得数据了。
3)缓存的不仅是 SQL 数据,能够缓存最终完成的部分显示页面,以节省CPU计算时间
例如正在制做一张显示用户信息的页面,你可能获得一段关于用户的信息(姓名,生日,家庭住址,简介),而后你可能会将 XML 格式的简介信息转化为 HTML 格式或作其余的一些工
做。相比单独存储这些属性,你可能更愿意存储通过渲染的数据块。那时你就能够简单地取出被预处理后的 HTML 直接填充在页面中,这样节省了宝贵的 CPU 时间。
3二、使用分层的缓存
memcached 能够高速处理大量的缓存数据,可是仍是要根据系统的状况考虑维护多层的缓存结构。例如除了memcached缓存以外,还能够经过本地缓存(如ehcache、oscache等)建
立起多级缓存。例如,能够采用本地缓存缓存一些基本数据,例如少许但访问频繁的数据(如产品分类,链接信息,服务器状态变量,应用配置变量等),缓存这些数据并让他们尽量的
接近处理器是有意义的 , 这样能够帮助减小生成页面的时间,而且在 memcached 失效的状况下能够增长可靠性。
3三、当数据更新时须要更新缓存
用户编辑了本身的信息,当保存信息到数据库时,须要更新缓存中的数据或是简单地删除老的数据。若是立刻更新数据,要防止从数据库读取那些刚刚更新过的数据。当用户习惯性地从新
载入本身的用户信息来确认是否修改为功时,数据将从缓存中直接取出,这时他们得到了最新的数据。
3四、模拟带锁的添加命令
若是你实在须要锁,你能够经过“添加”命令模仿锁的功能。尽管在未命中的状况下它不是那么有用,但若是你用它缓存日常的数据(应用服务器池的元数据)那仍是有用的。
好比,你要更新键 A 。
1. 添加一个 "lock:A" 的键,这个键有一个持续几秒的过时时间(足够长以使你能完成计算和更新,也不要很长,由于若是锁进程挂了,这个键不会当即释放)
2. 若是添加操做成功了,你就拥有了锁:从缓存获取键 A 的数据;利用客户端程序更改数据;更新缓存键 A 的数据;删除键 "lock:A" 。若是你不须要当即再次更新,就让它存活直到失效。
3. 若是添加操做失败,说明有人获取了锁。这时让应用作些合适的事,好比返回老数据,等待后重试,或是其余的。
以上这些操做相似 MySQL 将 GET_LOCK 的 timeout 值设置成 0 。没有办法在 memcached 中经过互斥锁模拟 GET_LOCK() 的 timeout 操做。
3五、预热你的缓存
若是你有一个很高访问率的站点,而且你正想加入故障恢复功能或是其余全新的功能,你最终可能会碰到空缓存的问题。一开始缓存是空的,而后一大群人点击你的站点,在填充缓存的过
程中,你的数据库可能会承受不住压力。为了解决这一问题,你能够试试任何可行的方法来 " 温暖 " 你的Memcached。方法:能够写一些脚原本缓存通用的页面;也能够写一个命令行工
具来填充缓存。你能够在高峰时刻在缓存里填充一些内容。