Web项目开发中用到的缓存技术

在WEB开发中用来应付高流量最有效的办法就是用缓存技术,能有效的提升服务器负载性能,用空间换取时间。
缓存通常用来php

  • 存储频繁访问的数据
  • 临时存储耗时的计算结果
  • 内存缓存减小磁盘IO

使用缓存的2个主要缘由:css

  • 下降延迟:缓存离客户端更近,所以,从缓存请求内容比从源服务器所用时间更少,呈现速度更快,网站就显得更灵敏。
  • 下降网络传输:副本被重复使用,大大下降了用户的带宽使用,其实也是一种变相的省钱(若是流量要付费的话),同时保证了带宽请求在一个低水平上,更容易维护了。

 

在WEB开发中,缓存能够分为:

 

1、数据库端缓存

  • 数据库的缓存通常由数据库提供,能够对表创建高速缓存。数据库中,用户可能屡次执行相同的查询语句,为了提升查询效率,数据库会在内存划分一个专门的区域,用来存放用户最近执行的查询,这块区域就是缓存。(参考MYSQL缓存)
  • “空间换时间”,好比建一个表来存储另一个表某个类型的数据的总条数,在每次更新数据的时候同事更新 数据表和统计条数的表。在须要获取某个类型的数据的条数的时候,就不须要select count去查询,直接查询统计表就能够了,这样能够提升查询的速度和数据库的性能。
  • 数据库查询缓存,每次访问页面的时候,都会先检测相应的缓存数据是否存在,若是不存在,就链接数据库,获得数据,并把查询结果序列化后保存到文件中,之后一样的查询结果就直接从缓存表或文件中得到。用的最广的例子看Discuz的搜索功能,把结果ID缓存到一个表中,下次搜索相同关键字时先搜索缓存表。举个经常使用的方法,多表关联的时候,把附表中的内容生成数组保存到主表的一个字段中,须要的时候数组分解一下,这样的好处是只读一个表,坏处就是两个数据同步会多很多步骤,数据库永远是瓶颈,用硬盘换速度,是这个的关键点。

 

2、应用层缓存

应用层缓存这块跟开发人员关系最大,也是平时常常接触的。html

  • 缓存数据库的查询结果,减小数据的压力。这个在大型网站是必须作的。
  • 缓存磁盘文件的数据。好比经常使用的数据能够放到内存,不用每次都去读取磁盘,特别是密集计算的程序,好比中文分词的词库。
  • 缓存某个耗时的计算操做,好比数据统计。

应用层缓存的架构也能够分几种:前端

  • 嵌入式,也就是缓存和应用在同一个机器。好比单机的文件缓存,java中用hashMap来缓存数据等等。这种缓存速度快,没有网络消耗。
  • 分布式缓存,把缓存的数据独立到不一样的机器,经过网络来请求数据,好比经常使用的memcache就是这一类。

比较常见的应用层分布式缓存容器,Memcache、共享文件服务器、MemcacheDb、Tokyo Tyrant。 php里面也有好比x-cache,apc等的基于进程的缓存,这种缓存比分布式缓存速度快,可是限于跟应用的一个机器。 java实现的缓存也比较多,好比oscache,jcache ,ehcached等等。java

 

3、前端缓存(服务端缓存)

咱们这里说的前端缓存能够理解为通常使用的cdn技术,利用squid等作前端缓冲技术,主要仍是针对静态文件类型,好比图片,css,js,html等静态文件。
通常针对静态资源如CSS,JS,图片等使用缓存,缘由以下:node

  • 请求更快:经过将内容缓存在本地浏览器或距离最近的缓存服务器(如CDN),在不影响网站交互的前提下能够大大加快网站加载速度。
  • 节省带宽:对于已缓存的文件,能够减小请求带宽甚至无需请求网络。
  • 下降服务器压力:在大量用户并发请求的状况下,服务器的性能受到限制,此时将一些静态资源放置在网络的多个节点,能够起到均衡负载的做用,下降服务器的压力。

前端比较经常使用的就是squid,Varnish Cache,ncache等等。Varnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang (vg.no) 使用3台Varnish代替了原来的12台squid,性能比之前更好。web

 

4、客户端缓存(浏览器缓存)

客户端缓存依赖于浏览器的实现,目前通常的浏览器都实现了基于http都信息来缓存相应的文件。浏览器端的缓存,可让用户请求一次以后,下一次不在从服务器端请求数据,直接从本地缓存读取,能够减轻服务器负担也能够加快用户的访问速度。
浏览器缓存分为强缓存和协商缓存:数据库

  • 强缓存:浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存若是命中,浏览器直接从本身的缓存中读取资源,不会发请求到服务器。好比某个css文件,若是浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;
  • 协商缓存:当强缓存没有命中的时候,浏览器必定会发送一个请求到服务器,经过服务器端依据资源的另一些http header验证这个资源是否命中协商缓存,若是协商缓存命中,服务器会将这个请求返回(304),可是不会返回这个资源的数据,而是告诉客户端能够直接从缓存中加载这个资源,因而浏览器就又会从本身的缓存中去加载这个资源;若未命中请求,则将资源返回客户端,并更新本地缓存数据(200)。

强缓存与协商缓存区别:强缓存不发请求到服务器,协商缓存会发请求到服务器。apache

 

如何设置缓存
1. HTML Meta标签控制缓存(非HTTP协议定义)
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
上述代码的做用是告诉浏览器当前页面不被缓存,每次访问都须要去服务器拉取。这种方法使用上很简单,但只有部分浏览器能够支持,并且全部缓存代理服务器都不支持,由于代理不解析HTML内容自己。segmentfault

2. HTTP头信息控制缓存

HTTP头信息发送在HTML代码以前,只能被浏览器和一些中间缓存能看到,一个典型的HTTP 1.1协议返回的头信息看上去像这样:

HTTP/1.1 200 OK
Date: Fri, 30 Oct 1998 13:19:41 GMT
Server: Apache/1.3.3 (Unix)
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: "3e86-410-3596fbbc"
Content-Length: 1040
Content-Type: text/html

头信息空一行后是HTML代码的输出。

HTTP头信息控制缓存是经过Expires(强缓存)、Cache-control(强缓存)、Last-Modified/If-Modified-Since(协商缓存)、Etag/If-None-Match(协商缓存)实现,下面详细介绍。
1)Expires是http1.0提出的一个表示资源过时时间的header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2016 23:55:55 GMT,读取缓存数据条件:缓存过时时间(服务器的)< 当前时间(客户端的)。
尽管Expires头颇有用,但它有必定的局限性。首先,由于牵扯到时间,Web服务器端的时钟必须和缓存的同步,不然极可能实现不了预期的结果——缓存把前女朋友当初现女朋友,把现女朋友看成过去式——那就悲剧了。另一个问题是,你很容易忘记给某内容设置了一个特定时间,若是返回内容的时候没有更新这个过时时间,则每一个请求都是上访到服务器,反而增长了负载和响应时间。
缺点:Expires是较老的强缓存管理header,因为它是服务器返回的一个绝对时间,这样存在一个问题,若是客户端的时间与服务器的时间相差很大(好比时钟不一样步,或者跨时区),那么偏差就很大,因此在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代。
2)Cache-Control(缓存控制)HTTP头信息,是HTTP 1.1引入了新的头信息,描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,因此相比较Expires,Cache-Control的缓存管理更有效,安全一些。读取缓存数据条件:上次缓存时间(客户端的)+max-age < 当前时间(客户端的)。Cache-Control值能够是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age

各个消息中的指令含义以下:

  • max-age=[秒]:表示在这个时间范围内缓存是新鲜的无需更新。相似Expires时间,不过这个时间是相对的,而不是绝对的。也就是某次请求成功后多少秒内缓存是新鲜的。(指示客户机能够接收生存期不大于指定时间(以秒为单位)的响应。上次缓存时间(客户端的)+max-age(64200s)<客户端当前时间)
  • s-maxage=[秒]:相似max-age, 除了仅应用于共享缓存(如代理)。
  • min-fresh指示客户机能够接收响应时间小于当前时间加上指定时间的响应。
  • max-stale指示客户机能够接收超出超时期间的响应消息。若是指定max-stale消息的值,那么客户机能够接收超出超时期指定值以内的响应消息。
  • public:指示响应可被任何缓存区缓存。通常而言,须要认证HTTP请求内容会自动私有化(不会被缓存Add)。
  • private:指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这容许服务器仅仅描述当前用户的部分响应消息,此响应消息对于其余用户的请求无效。(容许缓存专门为某一个用户存储响应,比方说在浏览器中;共享缓存通常不会,例如在代理中。)
  • no-cache:指示请求或响应消息不能缓存,该选项并非说能够设置”不缓存“,而是须要和服务器确认。(每次在释放缓存副本以前都强制发送请求给源服务器进行验证,这在确保认证有效性上很管用(和public结合使用)或者保证内容必须是即时的,不得无视缓存的全部优势,如国内的微博、twitter等的刷新显示Add。)
  • no-store:在请求消息中发送将使得请求和响应消息都不使用缓存,彻底不存下来。(强制缓存在任何状况下都不要保留任何副本。)
  • must-revalidate:告诉缓存,我给你准备了一些关于新鲜度的信息,在表现的时候要严格遵循之。HTTP容许缓存在某些特定状况下返回过时数据,指定了这个属性,相对于告诉缓存,你丫必须严格遵循个人规则。
  • proxy-revalidate:相似must-revalidate,除了只能应用于代理缓存。

注意:这两个header能够只启用一个,也能够同时启用,当response header中,Expires和Cache-Control同时存在时,Cache-Control优先级高于Expires。

3)Last-Modified/If-Modified-Since:Last-Modified/If-Modified-Since要配合Cache-Control使用。
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:当资源过时时(强缓存失效),发现资源具备Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
缺点:Last-Modified标注的最后修改只能精确到秒级,若是某些文件在1秒钟之内,被修改屡次的话,它将不能准确标注文件的修改时间(没法及时更新文件)
若是某些文件会被按期生成,当有时内容并无任何变化,但Last-Modified却改变了,致使文件无法使用缓存,有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形(没法使用缓存)。
HTTP1.1中Etag解决了上述问题。
4)Etag/If-None-Match:Etag/If-None-Match也要配合Cache-Control使用。
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的惟一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后获得的。
If-None-Match:当资源过时时(使用Cache-Control标识的max-age),发现资源具备Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的惟一标识符,可以更加准确的控制缓存。Last-Modified与ETag一块儿使用时,服务器会优先验证ETag。
yahoo的Yslow法则中则提示谨慎设置Etag:须要注意的是分布式系统里多台机器间文件的last-modified必须保持一致,以避免负载均衡到不一样机器致使比对失败,Yahoo建议分布式系统尽可能关闭掉Etag(每台机器生成的etag都会不同,由于除了 last-modified、inode 也很难保持一致)。

 

缓存的更新和过时

咱们这几只讲应用层的缓存。在应用层的缓存因为应经有新的数据加入,数据的修改,数据的删除等等操做,而在某些时间,咱们须要这些操做及时的生效(因为用了缓存,可能会致使修改后缓存没有更新,而页面也没有变化),因此出现缓存的更新和过时的概念。

缓存的过时包含

  • 时间过时:咱们在缓存数据的时候咱们能够指定数据缓存的最大时间,若是超过这个时间,咱们就认为缓存是失效的。
  • 基于规则的过时:咱们在缓存中存储了某些数据来标明数据的版本。好比存取的时间,更新的时间,数据的版本信息等等,而后比较这些信息是否有变化来判断是否过时。

缓存的更新

  • 被动:当缓存失效的时候咱们的应用程序从新从主存储器中取数据,而后从新放回缓存中。
  • 主动:当数据一更新的时候,咱们的应用主动的去更新咱们的缓存内容。
  • 被动和主动结合(基于版本):当数据以更新的时候,咱们更新一个数据被更新的标志。而后根据上面讲到的“基于规则的过时”来更新数据。

 

如何评价缓存的好坏

速度:固然,咱们使用缓存的目的之一就是要提升咱们应用的速度。若是使用缓存后速度更慢那就没有缓存的必要了。取缓存的速度应 当是很是快的,由于缓存的工做仅仅是取出一个曾经存储好的数据。因此影响缓存速度的因素可能跟缓存所才采用的存储方式有关系,还有可能印象速度的就是分布 式缓存的网络消耗,一样,缓存服务器在并发很大的时候也有可能不堪重负出现瓶颈,变得缓慢。
好比目前凤凰论坛使用的帖子缓存的响应时间在亚毫秒级,也就是还不足1ms的响应时间,这个速度是至关快的。
及时性:咱们使用缓存的重要一点就是对咱们的数据的更新须要缓存也及时的更新。这点很是重要,关系到页面显示的正确性,用户体验等。
命中率:命中率直接关系到缓存所起到的做用的大小。若是命中率过低就至关于没有使用缓存,或者咱们的缓存的规则有问题,重视命中不到缓存。


如何有效的使用缓存

哪些地方须要缓存

  • 页面的打开速度很是慢,每一次都要进行大量的计算,从数据库取一个比较耗时操做的数据。
  • 频繁的读取操做,每次请求都要从数据库读取数据,而这些数据的更新并非很频繁,致使数据库的压力很是大。
  • 频繁的写入操做(须要写到数据库),好比页面点击量,投票数的操做。这些操做能够暂时利用缓存,而后按期的写到数据库。

选择什么缓存
缓存如此有用,那么这么多的缓存产品,咱们如何选择呢?下面咱们主要就经常使用的php方面来讲。

  • 访问量不是特别大,web前端机器只有一台,对数据库端的内容缓存可使用文件缓存,这种方式很是简单也比较有效,不须要对服务器作特别的配置。也可使用apc,x-cached等提供的内存缓存,也很是有效,它比磁盘缓存速度快,可是由于是内存缓存,因此缓存的容量有限。
  • 访问量比较大,web前端机器通常超过一台甚至更多,咱们通常采用分布式的缓存。咱们通常选择memcache做为咱们的缓存,memcache是一个基于内存的分布式缓存,它的速度和效率很是高。

其实这里也可使用共享的磁盘缓存,可是基于咱们目前所处的环境和对于可靠性,高并发的要求,咱们不建议或者说不考虑使用共享磁盘做为缓存。

 


================PHP中9大缓存技术总结===================

一、全页面静态化缓存
也就是将页面所有生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程。此种方式,在CMS系统中比较常见,好比dedecms;

二、页面部分缓存
该种方式,是将一个页面中不常常变的部分进行静态缓存,而常常变化的块不缓存,最后组装在一块儿显示;可使用相似于ob_get_contents的方式实现,也能够利用相似ESI之类的页面片断缓存策略,使其用来作动态页面中相对静态的片断部分的缓存(ESI技术,请baidu,此处不详讲)。该种方式能够用于如商城中的商品页。

三、数据缓存
顾名思义,就是缓存数据的一种方式;好比,商城中的某个商品信息,当用商品id去请求时,就会得出包括店铺信息、商品信息等数据,此时就能够将这些数据缓存到一个php文件中,文件名包含商品id来建一个惟一标示;下一次有人想查看这个商品时,首先就直接调这个文件里面的信息,而不用再去数据库查询;其实缓存文件中缓存的就是一个php数组之类。Ecmall商城系统里面就用了这种方式。

四、查询缓存
其实这跟数据缓存是一个思路,就是根据查询语句来缓存;将查询获得的数据缓存在一个文件中,下次遇到相同的查询时,就直接先从这个文件里面调数据,不会再去查数据库;但此处的缓存文件名可能就须要以查询语句为基点来创建惟一标示;
按时间变动进行缓存:其实,这一条不是真正的缓存方式;上面的二、三、4的缓存技术通常都用到了时间变动判断;就是对于缓存文件您须要设一个有效时间,在这个有效时间内,相同的访问才会先取缓存文件的内容,可是超过设定的缓存时间,就须要从新从数据库中获取数据,并生产最新的缓存文件;好比,我将咱们商城的首页就是设置2个小时更新一次。

五、按内容变动进行缓存
这个也并不是独立的缓存技术,需结合着用;就是当数据库内容被修改时,即刻更新缓存文件。好比,一我的流量很大的商城,商品不少,商品表必然比较大,这表的压力也比较重;咱们就能够对商品显示页进行页面缓存;当商家在后台修改这个商品的信息时,点击保存,咱们同时就更新缓存文件;那么,买家访问这个商品信息时,实际上访问的是一个静态页面,而不须要再去访问数据库。
试想,若是对商品页不缓存,那么每次访问一个商品就要去数据库查一次,若是有10万人在线浏览商品,那服务器压力就大了;

六、内存式缓存
提到这个,可能你们想到的首先就是Memcached;memcached是高性能的分布式内存缓存服务器。 通常的使用目的是,经过缓存数据库查询结果,减小数据库访问次数,以提升动态Web应用的速度、 提升可扩展性。它就是将须要缓存的信息,缓存到系统内存中,须要获取信息时,直接到内存中取;比较经常使用的方式就是 key–>value方式。

七、apache缓存模块
apache安装完之后,是不容许被cache的。若是外接了cache或squid服务器要求进行web加速的话,就须要在htttpd.conf里进行设置,固然前提是在安装apache的时候要激活mod_cache的模块。
安装apache时:./configure –enable-cache –enable-disk-cache –enable-mem-cache

八、php APC缓存扩展
Php有一个APC缓存扩展,windows下面为php_apc.dll,须要先加载这个模块,而后是在php.ini里面进行配置:

[apc] 
extension=php_apc.dll 
apc.rfc1867 = on 
upload_max_filesize = 100M 
post_max_size = 100M 
apc.max_file_size = 200M 
upload_max_filesize = 1000M 
post_max_size = 1000M 
max_execution_time = 600 ; 每一个PHP页面运行的最大时间值(秒),默认30秒 
max_input_time = 600 ; 每一个PHP页面接收数据所需的最大时间,默认60 
memory_limit = 128M ; 每一个PHP页面所吃掉的最大内存,默认8M

 

九、Opcode缓存
PHP的缓冲器、加速器,有eaccelerator, apc, phpa,xcache。
首先php代码被解析为Tokens,而后再编译为Opcode码,最后执行Opcode码,返回结果;因此,对于相同的php文件,第一次运行时能够缓存其Opcode码,下次再执行这个页面时,直接会去找到缓存下的opcode码,直接执行最后一步,而再也不须要中间的步骤了。比较知名的是XCache、Turck MM Cache、PHP Accelerator等。



文章参考:

http://www.cnblogs.com/sunli/archive/2009/11/24/1609444.html
https://segmentfault.com/a/1190000006741200
https://my.oschina.net/leejun2005/blog/369148
http://www.oschina.net/news/41397/web-cache-knowledge
http://www.open-open.com/lib/view/open1479181086120.html
http://www.jb51.net/article/49714.htm
http://www.php100.com/html/php/lei/2015/0919/8969.html

 

版权声明:本文采用署名-非商业性使用-相同方式共享(CC BY-NC-SA 3.0 CN)国际许可协议进行许可,转载请注明做者及出处。
本文标题:Web项目开发中用到的缓存技术
本文连接:http://www.cnblogs.com/sochishun/p/7326752.html
本文做者:SoChishun (邮箱:14507247#qq.com | 博客:http://www.cnblogs.com/sochishun/)发表日期:2017年8月9日

相关文章
相关标签/搜索