简介
网站性能第一优化定律:优先考虑使用缓存优化性能。合理的使用缓存,对网站的性能优化的意义重大。以下对于缓存,都是指http缓存。
缓存的优点
使用缓存能节约带宽,能降低后端服务器的访问压力,如果把缓存放在离用户越近的地方,那能极大的加快响应的速度。
哪些数据应该被缓存
网站数据访问遵循二八定律,即80%的访问落在20%的数据上,缓存主要用来存放那些读写比高,变化少的数据。根据数据性质有分为私有数据和公共数据,私有数据指例如用户账号密码信息等数据或带有用户cookie的数据,此类数据一般不缓存,对于公共数据,一般缓存热区数据,热区数据指那些经常被访问到的数据,缓存下来后,命中率高。热区数据需要通过“热身”生成,而“热身”是需要时间的,所以在大型站点中上线缓存服务器前,为了加快缓存热身,会复制线上流量对缓存做压测,构建热区数据,然后再上线。
并且对于动态生成的数据,一般也不缓存,当然不是所有的动态数据都不能缓存,有些动态数据其实是可以静态化的,在生产环境中,把动态数据转成静态,也是一种有效的优化手段。
缓存的特征
前面说了,并不是所有数据都应该被缓存,被缓存的数据一般都具有以下的特征
- 时间局部性
时间局部性是指,一个数据被访问过后,可能很快的将会被再次访问。此类缓存往往命中率高。 - 空间局部性
空间局部性是指,一个数据被访问时,该数据周边的数据也可能会被访问到,所以预加载到缓存中,加快速度。
缓存的有效性
缓存的有效性一般使用缓存命中率来指标衡量,缓存命中率计算公式:
缓存命中率=hit/(hit+mixx)
hit=缓存被命中
miss=缓存没命中
衡量缓存命中率的方法有2个
页面命中率:从命中的页面数量衡量
字节命中率:基于大小进行衡量
缓存的有效判断机制
数据被缓存下来后,并不是一直都是有效的,缓存作用仅仅是为了加速,当用户有请求来了以后,我们应该确保回应的缓存有效的,对于http缓存是否有效,一般用以下两种方法判断缓存是否有效。过期时间和条件式请求。过期时间容易理解,就是缓存设置一个过期时间,一但过期,则清除,而条件式请求是指,当请求到来以后,如果本地有缓存的话,先发报文到后端服务器,询问该缓存是否有效,如果有效,则用次缓存回复给客户端。不过一般都是把2个判断机制联合起来使用,即缓存如果没到期,直接使用缓存响应,如果缓存到期之后,发送条件式请求给后端,询问该缓存是否继续生效。
http报文首部控制缓存的字段
http报文分为“请求报文”和“响应报文”,2种报文对于缓存的控制是有区别的。
前面说了缓存的有效判断机制可以是过期时间和条件式请求。
过期时间:Expires
对于HTTP/1.0,对于缓存的控制只有Expires字段,由响应报文返回该字段内容,内容是以绝对时间,例如:
如图,由服务器响应的报文种,指定了该数据能缓存到2027年。
后来在HTTP/1.1种增加了Cache-Control字段,能更灵活的控制缓存。
请求报文的Cache-Control
请求报文关于缓存的字段作用是用于通知缓存服务器如果使用缓存来响应请求
Cache-Control常见的指令
cache-request-directive =
"no-cache" #当字段内容包含no-cache时,表示不能用缓存响应该请求
"max-age" #请求报文的max-age通常用于条件式请求,即向服务器询问该缓存是否可用.
响应报文的Cache-Control
响应报文关于缓存的字段作用是指示如何存储服务器的响应的内容。
Cache-Control常见的指令
cache-response-directive =
"no-cache" #可缓存,但响应给客户端之前需要revalidation,即必须发出条件式请求进行缓存有效性验正;
"no-store" #不允许存储响应内容于缓存中;
"public" #用于指示该资源是公共数据
"private" #用于指示该资源是私有数据
"max-age" #用于指示该资源能被缓存多久,相对时间
条件式请求(新鲜度检查)
条件式请求通常用于向服务器询问该资源是否有效,常见的条件式询问指令有2个,能用于请求报文和响应报文种,但它们的意思是不一样的.
Last-Modityed/If-Last-Modityed
通常,在服务器回复的响应报文种,会携带该资源的时间戳,如图:
如果客户端要发送条件式请求时,在请求报文中,Cache-Control设置为:max-age=0,并且在首部中添加If-Last-Modityed字段,内容是服务器响应时的Last-Modityed值.意思就是要求服务器把该资源的最后修改时间和客户端提供的时间是否一致,如果一致,则返回状态码304(not modityed),如果有更新,则发送状态码200,并且把新资源响应给客户端.
Etag/If-None-Match
在服务器响应的报文中,也可以使用Etag标记,Etag是hash出来的,所以是第一无二的.如图:
如果客户端要发送条件式请求时,在请求报文中,Cache-Control设置为:max-age=0,并且在首部中添加If-None-Match字段,服务器会匹配客户端发来的和本地的Etag是否一致,如果一致,则返回304
有了时间戳为什么还需要Etag呢?
1、一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的变化时秒为单位的,这种修改无法判断。因此需要Etag来判断。
3、某些服务器不能精确的得到文件的最后修改时间;
如果Last-Modified与ETag一起使用时,优先验证ETag;为了兼容HTTP/1.0,报文还有Expires字段,但它的优先级低于Last-Modified.
总结:优先级
ETag>Last-Modified>Expires
http缓存总结
当浏览器第一次发送http请求时,本地一般没有改资源的缓存,所以请求会发到服务器上获取对应资源,服务器在构建响应报文时,通过Cache-Control向客户端说明对于该资源的缓存控制,要如何进行,客户端根据响应报文,下次再请求该资源时,如果该缓存未过期,则直接从缓存中读取,如果过期,发送条件式请求到服务器询问该资源是否有效,如果有效,服务器返回304,缓存继续有效,如果失效,则响应200,和新的资源.