Redis和Memcached对比详解整理
详细地比较Redis与Memcached的区别:
Memcached其本质上就是一个内存key-value数据库,但是不支持数据的持久化,服务器关闭之后数据全部丢失。Memcached使用C语言开发,在大多数像Linux、BSD和Solaris等POSIX系统上,只要安装了libevent即可使用。在Windows下,它也有一个可用的非官方版本(http://code.jellycan.com/memcached/)。
1. memcache的基本配置
1)启动Memcache的服务器端 # /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 12000 -c 256 -P /tmp/memcached.pid -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` 哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的。
2、一致性Hash算法的目的有两点:一是节点变动后其他节点受影响尽可能小;二是节点变动后数据重新分配尽可能均衡 。
3、为什么要运行 memcached ?
如果网站的高流量很大并且大多数的访问会造成数据库高负荷的状况下,使用 memcached 能够减轻数据库的压力。
4、适用memcached的业务场景?
1)如果网站包含了访问量很大的动态网页,因而数据库的负载将会很高。由于大部分数据库请求都是读操作,那么memcached可以显著地减小数据库负载。
2)如果数据库服务器的负载比较低但CPU使用率很高,这时可以缓存计算好的结果( computed objects )和渲染后的网页模板(enderred templates)。
3)利用memcached可以缓存 session数据 、临时数据以减少对他们的数据库写操作。
4)缓存一些很小但是被频繁访问的文件。
5)缓存Web 'services'(非IBM宣扬的Web Services,译者注)或RSS feeds的结果.。
5、不适用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
6.memcached是怎么工作的?
Memcached的高性能源于两阶段哈希(two-stage hash)结构。Memcached就像一个巨大的、存储了很多<key,value>对的哈希表。通过key,可以存储或查询任意的数据。 客户端 可以把数据存储在多台memcached上。当查询数据时,客户端首先参考节点列表计算出key的哈希值(阶段一哈希),进而选中一个节点;客户端将请求发送给选中的节点,然后 memcached节点通过一个内部的哈希算法(阶段二哈希),查找真正的数据(item)并返回给客户端。从实现的角度看,memcached是一个非阻塞的、基于事件的服务器程序。
7、memcached最大的优势是什么?
Memcached最大的好处就是它带来了极佳的水平可扩展性,特别是在一个巨大的系统中。由于客户端自己做了一次哈希,那么我们很容易增加大量memcached到集群中。memcached之间没有相互通信,因此不会增加 memcached的负载;没有多播协议,不会网络通信量爆炸(implode)。
8、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集群的规模,然后您就可以缓存更多的数据。
9、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(很慢,不具扩展性)或者仅仅依赖缓存超时失效机制。
10、memcached的cache机制是怎样的?
Memcached主要的cache机制是LRU(最近最少用)算法+超时失效。当您存数据到memcached中,可以指定该数据在缓存中可以呆多久Which is forever, or some time in the future。如果memcached的内存不够用了,过期的slabs会优先被替换,接着就轮到最老的未被使用的slabs。
11、memcached如何实现冗余机制? 不实现!Memcached应该是应用的缓存层,从设计本身来京就不带有任何冗余机制。如果一个memcached节点失去了所有数据,应该可以从数据源(比如数据库)再次获取到数据。应用系统应该可以容忍节点的失效。如果担心节点失效会大大加重数据库的负担,那么可以采取一些办法。比如您可以 增加更多的节点 (来减少丢失一个节点的影响),热备节点 (在其他节点down了的时候接管IP)等等。
12、memcached如何处理容错的? 在节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。节点失效时,下面列出几种方案供您选择:
1)忽略它! 在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响。
2)把失效的节点从节点列表中移除。做这个操作千万要小心!在默认情况下(余数式哈希算法),客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分key会因为哈希值的改变而被映射到(与原来)不同的节点上。
3)启动热备节点,接管失效节点所占用的IP。这样可以防止哈希紊乱(hashing chaos)。
4)如果希望添加和移除节点,而不影响原先的哈希结果,可以使用一致性哈希算法(consistent hashing)。
5)两次哈希(reshing)。当客户端存取数据时,如果发现一个节点down了,就再做一次哈希(哈希算法与前一次不同),重新选择另一个节点(需要注意的时,客户端并没有把down的节点从节点列表中移除,下次还是有可能先哈希到它)。如果某个节点时好时坏,两次哈希的方法就有风险了,好的节点和坏的节点上都可能存在脏数据(stale data)。
13、如何将memcached中item批量导入导出? 不应该这样做!Memcached是一个非阻塞的服务器。任何可能导致memcached暂停或瞬时拒绝服务的操作都应该值得深思熟虑。向memcached中批量导入数据往往不是您真正想要的!想象看,如果缓存数据在导出导入之间发生了变化,您就需要处理脏数据了;如果缓存数据在导出导入之间过期了,您又怎么处理这些数据呢? 因此,批量导出导入数据并不像想象中的那么有用。不过在一个场景倒是很有用。如果您有大量的从不变化 的数据,并且希望缓存很快热(warm)起来,批量导入缓存数据是很有帮助 的。
14、但是我确实需要把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,等等。
15、memcached是如何做身份验证的? 没有身份认证机制!memcached是运行在应用下层的软件(身份验证应该是应用上层的职责)。memcached的客户端和服务器端之所以是轻量级的,部分原因就是完全没有实现身份验证机制。这样,memcached可以很快地创建新连接,服务器端也无需任何配置。如果您希望限制访问,您可以使用防火墙,或者让memcached监听unix domain socket。
16、memcached的多线程是什么?如何使用它们? 线程就是定律(threads rule)!在Steven Grimm和Facebook的努力下,memcached 1.2及更高版本拥有了多线程模式。多线程模式允许memcached能够充分利用多个CPU,并在 CPU之间共享所有的缓存数据。memcached使用一种简单的锁机制来保证数据更新操作的互斥。相比在同一个物理机器上运行多个memcached实例,这种方式能够更有效地处理multi gets。如果系统的负载并不重,那么不需要启用多线程工作模式。如果您在运行一个拥有大规模硬件的、庞大的网站,将体验到看到多线程的好处。更多信息请参见: 简单地总结一下:命令解析(memcached在这里花了大部分时间)可以运行在多线程模式下。memcached内部对数据的操作是基于很多全局锁的(因此这部分工作不是多线程的)。未来对多线程模式的改进,将移除大量的全局锁,提高memcached在负载极高的场景下的性能。
17. 在设计应用时,可以通过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 时间。
18. 使用分层的缓存 memcached 可以高速处理大量的缓存数据,但是还是要根据系统的情况考虑维护多层的缓存结构。例如除了memcached缓存之外,还可以通过本地缓存(如ehcache、oscache等)建立起多级缓存。例如,可以采用本地缓存缓存一些基本数据,例如少量但访问频繁的数据(如产品分类,连接信息,服务器状态变量,应用配置变量等),缓存这些数据并让他们尽可能的接近处理器是有意义的 , 这样可以帮助减少生成页面的时间,并且在 memcached 失效的情况下可以增加可靠性。
19. 当数据更新时需要更新缓存 用户编辑了自己的信息,当保存信息到数据库时,需要更新缓存中的数据或是简单地删除老的数据。如果马上更新数据,要防止从数据库读取那些刚刚更新过的数据。当用户习惯性地重新载入自己的用户信息来确认是否修改成功时,数据将从缓存中直接取出,这时他们获得了最新的数据。
memcache:
1、memcached的优势是什么?
1) 分布式 。
2)相对应用服务器的内存而言,可以进行单点访问。
3)性能强。
2、不太适合采用Memcached缓存的情况?
1) 如果Value特别大,不太适合。默认编译下Memcache只支持1M的Value。事实上由于存在序列化反序列化的过程,所以从实践的角度来说也不建议把非常大的数据保存在Memcache中。Memcache适合面向输出的内容缓存,而不是面向处理的数据缓存,也就是不太适合把大块数据放进去拿出来 处理之后再放回去,而是适合拿出来就直接给输出了或是拿出来不需要处理直接使用。
2) 如果不允许过期,不太适合。Memcache在默认情况下最大30天过期,而且在内存达到使用限制后它也会回收最近最少使用的数据。
3、清除部分缓存数据的过程?
可采用命名空间(在Memcache的语境下可采用Key前缀的办法代替,例如设置Key为“子系统名称+实体名+实体的ID”)的办法来实现,用以区分不同类型的缓存内容,以便在需要的时候可以清除某一类缓存。
4、Value的组织问题?
主要涉及被缓存的数据的颗粒度,比如要保存一个数据表,是一行数据保存在一个键值还是统一保存为一个键值。如果数据保存的粒度很小的话最好是在获取的时候能够批量获取,在保存的时候也能够批量保存,也就是说对于跨网络的调用次数越少越好。
5、memcache中Key的约定和命名规范?
第一种:一般是项目名称+字符常量(实体名或表名等)+返回PO的id(或者唯一标示都可以)。这种方法代码一般会嵌入到Service中,从而破坏service的业务逻辑,耦合性较高。可以考虑在action层与service层中间加入一层,来降低耦合性。
第二种:可以用spring aop来拦截你要缓存的service,唯一key可以通过类名+方法名+参数名等来组成;这种方法适用于分模块开发 ,因为调用的都是同一个类中的方法,但是拦截器也会在一定程度上影响性能。但是可以提高开发的效率,还有就是不会破坏service层的业务逻辑。
第三种:用sql语句+id(或者查询条件)。这种方法不是很好。
Redis的安装配置
Redis的配置文件