大家好,我是IT修真院上海分院第6期的学员,一枚正直纯洁善良的程序员今天给大家分享一下,修真院官网Java任务6中的拓展思考:为什么要使用memcache?memcashe有什么作用?
1.背景介绍
在Web服务开发中,服务端缓存是服务实现中所常常采用的一种提高服务性能的方法。其通过记录某部分计算结果来尝试避免再次执行得到该结果所需要的复杂计算或是查询,从而提高了服务的运行效率。
除了能够提高服务的运行效率之外,服务端缓存还常常用来提高服务的扩展性。因此一些大规模的Web应用,如Facebook,常常构建一个庞大的服务端缓存。而它们所最常使用的就是Memcached。
2.知识剖析
1.Memcached的作用是在内存中划出一块区域来,对一些经常需要访问数据库的数据进行缓存,这样就可以直接在缓存中来读取到指定信息从而不需要频繁读取数据库,起到提高反应速度和减少serveice层压力的作用。
同时,因为我们可以使用多个应用实例来访问同一个缓存,这样就避免了多个应用实例访问多个缓存出现的数据不同步,数据冗杂等问题,从而提升了服务扩展性。
客户端——>应用实例——>绑定专属缓存实例
客户端——>服务器里的tomcat——>独立的memcached缓存
2.Memcached就是一个使用了BSD许可(即开源协议)的服务端缓存实现。但是与其它服务端缓存实现不同的是,其主要由两部分组成:独立运行的Memcached服务实例,以及用于访问这些服务实例的客户端。因此相较于普通服务端缓存实现中各个缓存都运行在应用实例之上的情况,Memcached服务实例则是在应用实例之外独立运行的。
3.由于Memcached缓存实例是独立于各个应用服务器实例运行的,因此应用服务实例可以访问任意的缓存实例。而传统的缓存则与特定的应用实例绑定,因此每个应用实例将只能访问特定的缓存。这种绑定一方面会导致整个应用所能够访问的缓存容量变得很小,另一方面也可能导致不同的缓存实例中存在着冗余的数据,从而降低了缓存系统的整体效率。
4.在运行时,Memcached服务实例只需要消耗非常少的CPU资源,却需要使用大量的内存。因此在决定如何组织您的服务端缓存结构之前,您首先需要搞清当前服务中各个服务实例(单机多实例)的负载情况。如果一个服务器的CPU使用率非常高,却存在着非常多的空余内存,那么我们就完全可以在其上运行一个Memcached实例。而如果当前服务中的所有服务实例都没有过多的空余内存,那么我们就需要使用一系列独立的服务实例来搭建服务端缓存。一个大型服务常常拥有上百个Memcached实例。而在这上百个Memcached实例中所存储的数据则不尽相同。由于这种数据的异构性,我们需要在访问由Memcached所记录的信息之前决定在该服务端缓存系统中到底由哪个Memcached实例记录了我们所想要访问的数据。
5.用户需要通过一个Memcached客户端来完成对缓存服务所记录信息的访问。该客户端知道服务端缓存系统中所包含的所有Memcached服务实例。在需要访问具有特定键值的数据时,该客户端内部会根据所需要读取的数据的键值,如“foo”,以及当前Memcached缓存服务的配置来计算相应的哈希值,以决定到底是哪个Memcached实例记录了用户所需要访问的信息。在决定记录了所需要信息的Memcached实例之后,Memcached客户端将从配置中读取该Memcached服务实例所在地址,并向该Memcached实例发送数据访问请求,以从该Memcached实例中读取具有键值“foo”的信息。在各个论坛的讨论中,这被称为是Memcached的两阶段哈希(Two-stage hash)。
6.这里的服务端是指我们在服务器中下载安装的memcached程序,而客户端则是指我们的web项目中用到的memcached工具类。
7.而对数据的记录也使用了类似的流程:假设用户希望通过服务端缓存记录数据“bar”,并为其指定值“foo”。那么Memcached客户端将首先对用户所赋予的键值“foo”及当前服务端缓存所记录的可用服务实例个数执行哈希计算,并根据哈希计算结果来决定存储该数据的Memcached服务实例。接下来,客户端就会向该实例发送请求,以在其中记录具有键值“foo”的数据“bar”。
8.这样做的好处则在于,每个Memcached服务实例都是独立的,而彼此之间并没有任何交互。在这种情况下,我们可以省略很多复杂的功能逻辑,如各个节点之间的数据同步以及结点之间消息的广播等等。这种轻量级的架构可以简化很多操作。如在一个节点失效的时候,我们仅仅需要使用一个新的Memcached节点替代老节点即可。而在对缓存进行扩容的时候,我们也只需要添加额外的服务并修改客户端配置。
这些记录在服务端缓存中的数据是全局可见的。也就是说,一旦在Memcached服务端缓存中成功添加了一条新的记录,那么其它使用该缓存服务的应用实例将同样可以访问该记录。
9.在Memcached中,每条记录都由四部分组成:记录的键,有效期,一系列可选的标记以及表示记录内容的数据。由于记录内容的数据中并不包含任何数据结构,因此我们在Memcached中所记录的数据需要是经过序列化之后的表示。
序列化主流的三种方式,优点缺点如下,参照自己的需要选择。
①使用Json
优点:跨语言、格式清晰一目了然
缺点:字节数比较大,需要第三方类库
②Object Serialize
优点:java原生方法不依赖外部类库
缺点:字节数比较大,不能跨语言
③Google protobuf
优点:跨语言、字节数比较少,网络传输节省Io
缺点:需要依赖于工具生成代码
一般为方便使用第二种,我们将需要放进缓存的类继承Serializable接口,并且拥有专属serialVersionUID即可
3.常见问题
memcached对java客户端有哪几种,各有什么优缺点,我该怎么选?4.解决方案
Memcached Client目前有3种: Memcached Client for Java, SpyMemcached, XMemcached。
① Memcached Client for Java:
较早推出的memcached JAVA客户端API,应用广泛,运行比较稳定。
②SpyMemcached:
支持异步,单线程的memcached客户端,用到了java1.5版本的concurrent和nio,存取速度会高于前者,但是稳定性不好,测试中常报timeOut等相关异常。
③XMemcached:
同样是基于java nio的客户端,java nio相比于传统阻塞io模型来说,有效率高(特别在高并发下)和资源耗费相对较少的优点。传统阻塞IO为了提高效率,需要创建一定数量的连接形成连接池,而nio仅需要一个连接即可(当然,nio也是可以做池化处理),相对来说减少了线程创建和切换的开销,这一点在高并发下特别明显。因此XMemcached与Spymemcached在性能都非常优秀,在某些方面(存储的数据比较小的情况下)Xmemcached比Spymemcached的表现更为优秀。
由于memcached client for java发布了新版本,性能上有所提高,并且运行稳定,所以建议使用memcached clientfor java。
但XMemcached也使用得比较广泛,而且有较详细的中文API文档,具有如下特点:高性能、支持完整的协议、支持客户端分布、允许设置节点权重、动态增删节点、支持JMX、与Spring框架和Hibernate-memcached的集成、客户端连接池、可扩展性好等。
除此之外还有阿里自己服装的memcached,其注释全都是使用的中文,很适合英语渣使用,但是网上资料比较少,所以这里不考虑。
5.编码实战
6.拓展思考
1.适用memcached的业务场景?
1)如果网站包含了访问量很大的动态网页,因而数据库的负载将会很高。由于大部分数据库请求都是读操作,那么memcached可以显著地减小数据库负载。
2)如果数据库服务器的负载比较低但CPU使用率很高,这时可以缓存计算好的结果( computed objects )和渲染后的网页模板(enderred templates)。
3)利用memcached可以缓存 session数据 、临时数据以减少对他们的数据库写操作。
4)缓存一些很小但是被频繁访问的文件。
5)缓存Web 'services'(非IBM宣扬的Web Services,译者注)或RSS feeds的结果.。
2.不适用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
7.参考文献
https://www.cnblogs.com/jiaosq/p/5812250.html
https://blog.csdn.net/rachel_luo/article/details/8814087
https://www.cnblogs.com/loveis715/p/4681643.html
8.更多思考
1.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最大能存储多大的单个item?
memcached最大能存储1MB的单个item。如果需要被缓存的数据大于1MB,可以考虑在客户端压缩或拆分到多个key中。
3.memcached如何处理容错的?
在节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。
节点失效时,下面列出几种方案供您选择:
1)忽略它! 在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响。
2)把失效的节点从节点列表中移除。做这个操作千万要小心!在默认情况下(余数式哈希算法),客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分key会因为哈希值的改变而被映射到(与原来)不同的节点上。
3)启动热备节点,接管失效节点所占用的IP。这样可以防止哈希紊乱(hashing chaos)。
4)如果希望添加和移除节点,而不影响原先的哈希结果,可以使用一致性哈希算法(consistent hashing)。
5)两次哈希(reshing)。当客户端存取数据时,如果发现一个节点down了,就再做一次哈希(哈希算法与前一次不同),重新选择另一个节点(需要注意的时,客户端并没有把down的节点从节点列表中移除,下次还是有可能先哈希到它)。如果某个节点时好时坏,两次哈希的方法就有风险了,好的节点和坏的节点上都可能存在脏数据(stale data)。
今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖~
技能树.IT修真院
“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。
这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导。
快来与我一起学习吧~http://www.jnshu.com/login/1/22137050