开始讨论缓存以前,让咱们先来讨论讨论另一个问题:理论和实践.从ahuaxuan接触的程序员来看,有的程序员偏实践,有的程序员偏理论,可是这都是很差的行为,理论和实践一样重要,咱们在作不少核心的算法的时候,没有理论根本无从下手,而在咱们多年的实践中,不总结理论就不能加深本身的理解.因此理论和实践同等重要.
缓存是当今各类软件或者硬件系统中不可缺乏的技术之一,因此对每一个程序员来讲都显得异常重要,对ahuaxuan来讲亦是如此.若是说用dfa实现文字过滤是从理论到实践,那么本文即是从实践中总结出得理论.
在讨论缓存功能以前,咱们首先来了解一下缓存这个东西自己.ahuaxuan根据本身的经验把缓存问题细分为4类小问题.
1缓存为何要存在?
2缓存能够存在于什么地方?
3缓存有哪些属性?
4缓存介质?
搞清楚这4个问题,那么咱们就能够随意的经过应用的场景来判断使用何种缓存了.
下面ahuaxuan和你们一一分析这4个问题.
1. 缓存为何要存在?
通常状况下,一个网站,或者一个应用,它的通常形式是,浏览器请求应用服务器,应用服务器作一堆计算后再请求数据库,数据库收到请求后再做一堆计算后把数据返回给应用服务器,应用服务器再做一堆计算后把数据返回给浏览器.这个是一个标准流程.可是随着互连网的普及,上网的人愈来愈多,网上的信息量也愈来愈多,在这两个愈来愈多的状况下,咱们的应用须要支撑的并发量就愈来愈多.而后咱们的应用服务器和数据库服务器所作的计算也愈来愈多,可是每每咱们的应用服务器资源是有限的,数据库每秒中接受请求的次数也是有限的(谁叫俺们的硬盘转速有限呢).若是利用有限的资源来提供尽量大的吞吐量呢,一个办法:减小计算量,缩短请求流程(减小网络io或者硬盘io),这时候缓存就能够大展手脚了.缓存的基本原理就是打破上图中所描绘的标准流程,在这个标准流程中,任何一个环节均可以被切断.请求能够从缓存里取到数据直接返回.这样不但节省了时间,提升了响应速度,并且也节省了硬件资源.可让咱们有限的硬件资源来服务更多的用户.
2 缓存能够存在于什么地方?
Java代码java
浏览器---浏览器和app之间---分过层的app-数据库 node
浏览器---浏览器和app之间---分过层的app-数据库
在上图中,咱们能够看到一次请求的通常流程,下面咱们从新绘制这张图,让咱们的结构稍微复杂一点点.
(将app分层)
浏览器---浏览器和app之间---分过层的app-数据库
理论上来将,请求的任何一个环节都是缓存能够做用的地方.第一个环节,浏览器,若是数据存在浏览器上,那么对用户来讲速度是最快的,由于这个时候根本无需网络请求.第二个环节,浏览器和app之间,若是缓存加在这个地方,那么缓存对app来讲是透明的.并且这个缓存中存放的是完整的页面.第三个节点,app中自己就有几个层次,那么缓存也能够放在不一样的层次上,这一部分是状况或者场景比较复杂的部分.选择缓存时须要谨慎.第四个环节,数据库中也能够有缓存,好比说mysql的querycache.
那么也就是说在整个请求流程的任何一点,咱们均可以加缓存.可是是全部的数据均可以放进缓存的吗.固然不是,须要放进缓存的数据老是有一些特征的,要清楚的判断数据是否能够被缓存,能够被怎样缓存就必需要从数据的变化特征下手.
数据有哪些变化特征?最简单的就是两种,变和不变.咱们都知道,不会变化的数据不须要每次都进行计算.问题是难道全部的数据理论上来说都会变化,变化是世界永恒的主题.也就是说咱们把数据分为变和不变两种是不对的,那么就让咱们再加一个条件:时间.那么咱们就能够把数据特征总结为一段时间内变或者不变.那么根据这个数据特征,咱们就能够在合适的位置和合适的缓存类型中缓存该数据.
3缓存有哪些属性
从面向对象的角度来看,缓存就是一个对象,那么是对象,必然有属性.那么下面咱们来探讨一下缓存有哪些属性.如下列举咱们经常使用到的3个属性.
(1) 命中率
命中率是指请求缓存次数和缓存返回正确结果次数的比例.比例越高,就证实缓存的使用率越高.
命中率问题是缓存中的一个很是重要的问题,咱们都但愿本身缓存的命中率能达到100%,可是每每事与愿违,并且缓存命中率是衡量缓存有效性的重要指标.
(2) 最大元素
缓存中能够存放得最大元素得数量,一旦缓存中元素数量超过这个值,那么将会起用缓存清空策略,根据不一样的场景合理的设置最大元素值每每能够必定程度上提升缓存的命中率.从而更有效的时候缓存.
(3) 清空策略
1 FIFO ,first in first out ,最早进入缓存得数据在缓存空间不够状况下(超出最大元素限制时)会被首先清理出去
2 LFU , Less Frequently Used ,一直以来最少被使用的元素会被被清理掉。这就要求缓存的元素有一个hit 属性,在缓存空间不够得状况下,hit 值最小的将会被清出缓存。
2 LRU ,Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又须要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
4缓存介质
从硬件介质上来将无非就是两种,内存和硬盘(对应应用层的程序来说不用考虑寄存器等问题).可是每每咱们不会从硬件上来划分,通常的划分方法是从技术上划分,能够分红几种,内存,硬盘文件.数据库.
(1) 内存.将缓存放在内存中是最快的选择,任何程序直接操做内存都比操做硬盘要快的多,可是若是你的数据要考虑到break down的问题,由于放在内存中的数据咱们称之为没有持久话的数据,若是硬盘上没有备份,机器down机以后,很难或者没法恢复.
(2) 硬盘.通常来讲,不少缓存框架会结合使用内存和硬盘,好比给内存分配的空间有满了以后,会让用户选择把须要退出内存空间的数据持久化到硬盘.固然也选择直接把数据放一份到硬盘(内存中一份,硬盘中一份,down机也不怕).也有其余的缓存是直接把数据放到硬盘上.
(3) 数据库.说到数据库,可能有的人会想,以前不是讲到要减小数据库查询的次数,减小数据库计算的压力吗,如今怎么又用数据库做为缓存的介质了呢.这是由于数据库又不少种类型,好比berkleydb,这种db不支持sql语句,没有sql引擎,只是key和value的存储结构,因此速度很是的快,在当代通常的pc上,每秒中十几w次查询都是没有问题的(固然这个是根据业务特征来决定的,若是您访问的数据在分布上是均匀的,那ahuaxuan可不能保证这个速度了).
除了缓存介质以外,ahuaxuan根据缓存和应用的耦合程度将其划分为local cache和remote cache.
Local cache是指包含在应用之中的缓存组件.而remote cache指和应用解耦在应用以外的缓存组件.典型的local cache有ehcache,oscache,而remote cache有大名鼎鼎的memcached.
Localcache最大的优势是应用和cache的时候是在同一个进程内部,请求缓存很是快速,彻底不须要网络开销等.因此单应用,不须要集群或者集群状况下cache node不须要相互通知的状况下使用local cache比较合适.这也是java中ehcache和oscache这么流行的缘由.
可是Local cache是有必定的缺点的,通常这种缓存框架(好比java中的ehcache或者oscache)都是local cache.也就是跟着应用程序走的,多个应用程序没法直接共享缓存,应用集群的状况下这个问题更加明显,固然也有的缓存组件提供了集群节点相互通知缓存更新的功能,可是因为这个是广播,或者是环路更新,在缓存更新频繁的状况下会致使网络io开销很是大,严重的时候会影响应用的正常运行.并且若是缓存中数据量较大得状况下使用localcache意味着每一个应用都有一份这么大得缓存,着绝对是对内存的浪费.
因此这个状况下,每每咱们会选择remote cache,好比memcached.这样集群或者分布式的状况下各个应用均可以共享memcached中的数据,这些应用都经过socket和基于tcp/ip协议上层的memcached协议直接链接到memcached,有一个app更新了memcached中的值,全部的应用都能拿到最新的值.虽然这个时候多了不少了网络上的开销,可是每每这种方案要比localcache广播或环路更新cache节点要广泛的多,并且性能也比后者高.因为数据只须要保存一份,因此也提升了内存的使用率.
经过以上分析能够看出,无论是local cache,仍是remote cache在缓存领域都有本身的一席之地,因此ahuaxuan建议在选择或者使用缓存时必定要根据缓存的特征和咱们的业务场景准确判断使用何种缓存.这样才能充分发挥缓存的功能.
Ahuaxuan认为,缓存的使用是架构师的必备技能,好的架构师可以根据数据的类型,业务的场景来准确的判断出使用何种类型的缓存,而且如何使用这种类型的缓存.在缓存的世界里也没有银弹,目前尚未一种缓存能够解决任何的业务场景或者数据类型,若是这种技术出现了,那架构师就又更不值钱了.呵呵.mysql
OSCache
OSCache是个一个普遍采用的高性能的J2EE缓存框架,OSCache能用于任何Java应用程序的普通的缓存解决方案。
OSCache有如下特色:
缓存任何对象,你能够不受限制的缓存部分jsp页面或HTTP请求,任何java对象均可以缓存。
拥有全面的API--OSCache API给你全面的程序来控制全部的OSCache特性。
永久缓存--缓存能随意的写入硬盘,所以容许昂贵的建立(expensive-to-create)数据来保持缓存,甚至能让应用重启。
支持集群--集群缓存数据能被单个的进行参数配置,不须要修改代码。
缓存记录的过时--你能够有最大限度的控制缓存对象的过时,包括可插入式的刷新策略(若是默认性能不须要时)。
官方网站 http://www.opensymphony.com/oscache/
Java Caching System
JSC(Java Caching System)是一个用分布式的缓存系统,是基于服务器的java应用程序。它是经过提供管理各类动态缓存数据来加速动态web应用。
JCS和其余缓存系统同样,也是一个用于高速读取,低速写入的应用程序。
动态内容和报表系统可以得到更好的性能。
若是一个网站,有重复的网站结构,使用间歇性更新方式的数据库(而不是接二连三的更新数据库),被重复搜索出相同结果的,就可以经过执行缓存方式改进其性能和伸缩性。
官方网站 http://jakarta.apache.org/turbine/jcs/
EHCache
EHCache 是一个纯java的在进程中的缓存,它具备如下特性:快速,简单,为Hibernate2.1充当可插入的缓存,最小的依赖性,全面的文档和测试。
官方网站 http://ehcache.sourceforge.net/
JCache
JCache是个开源程序,正在努力成为JSR-107开源规范,JSR-107规范已经不少年没改变了。这个版本仍然是构建在最初的功能定义上。
官方网站 http://jcache.sourceforge.net/
ShiftOne
ShiftOne Java Object Cache是一个执行一系列严格的对象缓存策略的Java lib,就像一个轻量级的配置缓存工做状态的框架。
官方网站 http://jocache.sourceforge.net/
SwarmCache
SwarmCache是一个简单且有效的分布式缓存,它使用IP multicast与同一个局域网的其余主机进行通信,是特别为集群和数据驱动web应用程序而设计的。SwarmCache可以让典型的读操做大大超过写操做的这类应用提供更好的性能支持。
SwarmCache使用JavaGroups来管理从属关系和分布式缓存的通信。
官方网站 http://swarmcache.sourceforge.net
TreeCache / JBossCache
JBossCache是一个复制的事务处理缓存,它容许你缓存企业级应用数据来更好的改善性能。缓存数据被自动复制,让你轻松进行JBoss服务器之间的集群工做。JBossCache可以经过JBoss应用服务或其余J2EE容器来运行一个MBean服务,固然,它也能独立运行。
JBossCache包括两个模块:TreeCache和TreeCacheAOP。
TreeCache --是一个树形结构复制的事务处理缓存。
TreeCacheAOP --是一个“面向对象”缓存,它使用AOP来动态管理POJO(Plain Old Java Objects)
注:AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向方面编程。
官方网站 http://www.jboss.org/products/jbosscache
WhirlyCache 程序员
Whirlycache是一个快速的、可配置的、存在于内存中的对象的缓存。它可以经过缓存对象来加快网站或应用程序的速度,不然就必须经过查询数据库或其余代价较高的处理程序来创建。web
Memcachedredis
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它经过在内存中缓存数据和对象来减小读取数据库的次数,从而提升动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,可是客户端能够用任何语言来编写,并经过memcached协议与守护进程通讯。算法
redissql
redis是一个key-value存储系统。和Memcached相似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操做,并且这些操做都是原子性的。在此基础上,redis支持各类不一样方式的排序。与memcached同样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操做写入追加的记录文件,而且在此基础上实现了master-slave(主从)同步。数据库
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合能够对关系数据库起到很好的补充做用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。apache
Redis支持主从同步。数据能够从主服务器向任意数量的从服务器上同步,从服务器能够是关联其余从服务器的主服务器。这使得Redis可执行单层树复制。从盘能够有意无心的对数据进行写操做。因为彻底实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操做的可扩展性和数据冗余颇有帮助。