缓存技术1之HTTP 缓存
假设一个网站,需要提高性能,缓存可以放在浏览器,可以放在反向代理服务器,还可以放在应用程序进程内,同时可以放在分布式缓存系统中。
缓存策略图
从用户请求数据到数据返回,数据经过了浏览器,CDN,代理服务器,应用服务器,以及数据库各个环节。每个环节都可以运用缓存技术。
从浏览器/客户端开始请求数据,通过 HTTP 配合 CDN 获取数据的变更情况,到达代理服务器(Nginx)可以通过反向代理获取静态资源。
再往下来到应用服务器可以通过进程内(堆内)缓存,分布式缓存等递进的方式获取数据。如果以上所有缓存都没有命中数据,才会回源到数据库。
缓存的请求顺序是:用户请求→HTTP 缓存→CDN 缓存→代理服务器缓存→进程内缓存→分布式缓存→数据库。
HTTP 缓存
当用户通过浏览器请求服务器的时候,会发起 HTTP 请求,如果对每次 HTTP 请求进行缓存,那么可以减少应用服务器的压力。
当第一次请求的时候,浏览器本地缓存库没有缓存数据,会从服务器取数据,并且放到浏览器的缓存库中,下次再进行请求的时候会根据缓存的策略来读取本地或者服务的信息。
HTTP 缓存流程图
一般信息的传递通过 HTTP 请求头 Header 来传递。目前比较常见的缓存方式有两种,分别是
强制缓存
对比缓存
强制缓存
当浏览器本地缓存库保存了缓存信息,在缓存数据未失效的情况下,可以直接使用缓存数据。否则就需要重新获取数据。
这种缓存机制看上去比较直接,那么如何判断缓存数据是否失效呢?这里需要关注 HTTP Header 中的两个字段 Expires 和 Cache-Control。
Expires 为服务端返回的过期时间,客户端第一次请求服务器,服务器会返回资源的过期时间。如果客户端再次请求服务器,会把请求时间与过期时间做比较。
如果请求时间小于过期时间,那么说明缓存没有过期,则可以直接使用本地缓存库的信息。
反之,说明数据已经过期,必须从服务器重新获取信息,获取完毕又会更新最新的过期时间。
这种方式在 HTTP 1.0 用的比较多,到了 HTTP 1.1 会使用 Cache-Control 替代。
Cache-Control 中有个 max-age 属性,单位是秒,用来表示缓存内容在客户端的过期时间。
例如:max-age 是 60 秒,当前缓存没有数据,客户端第一次请求完后,将数据放入本地缓存。
那么在 60 秒以内客户端再发送请求,都不会请求应用服务器,而是从本地缓存中直接返回数据。如果两次请求相隔时间超过了 60 秒,那么就需要通过服务器获取数据。
对比缓存
需要对比前后两次的缓存标志来判断是否使用缓存。浏览器第一次请求时,服务器会将缓存标识与数据一起返回,浏览器将二者备份至本地缓存库中。浏览器再次请求时,将备份的缓存标识发送给服务器。
服务器根据缓存标识进行判断,如果判断数据没有发生变化,把判断成功的 304 状态码发给浏览器。
这时浏览器就可以使用缓存的数据来。服务器返回的就只是 Header,不包含 Body。
下面介绍两种标识规则:
①Last-Modified/If-Modified-Since 规则
在客户端第一次请求的时候,服务器会返回资源最后的修改时间,记作 Last-Modified。客户端将这个字段连同资源缓存起来。
Last-Modified 被保存以后,在下次请求时会以 Last-Modified-Since 字段被发送。
Last-Modified/If-Modified-Since 规则第一次请求服务器
当客户端再次请求服务器时,会把 Last-Modified 连同请求的资源一起发给服务器,这时 Last-Modified 会被命名为 If-Modified-Since,存放的内容都是一样的。
服务器收到请求,会把 If-Modified-Since 字段与服务器上保存的 Last-Modified 字段作比较:
-
若服务器上的 Last-Modified 最后修改时间大于请求的 If-Modified-Since,说明资源被改动过,就会把资源(包括 Header+Body)重新返回给浏览器,同时返回状态码 200。
-
若资源的最后修改时间小于或等于 If-Modified-Since,说明资源没有改动过,只会返回 Header,并且返回状态码 304。浏览器接受到这个消息就可以使用本地缓存库的数据。
Last-Modified/If-Modified-Since 规则第二次请求服务器
注意:Last-Modified 和 If-Modified-Since 指的是同一个值,只是在客户端和服务器端的叫法不同。
②ETag / If-None-Match 规则
客户端第一次请求的时候,服务器会给每个资源生成一个 ETag 标记。这个 ETag 是根据每个资源生成的唯一 Hash 串,资源如何发生变化 ETag 随之更改,之后将这个 ETag 返回给客户端,客户端把请求的资源和 ETag 都缓存到本地。
ETag 被保存以后,在下次请求时会当作 If-Noe-Match 字段被发送出去。
ETag/If-None-Match 第一次请求服务器
在浏览器第二次请求服务器相同资源时,会把资源对应的 ETag 一并发送给服务器。在请求时 ETag 转化成 If-None-Match,但其内容不变
服务器收到请求后,会把 If-None-Match 与服务器上资源的 ETag 进行比较:
-
如果不一致,说明资源被改动过,则返回资源(Header+Body),返回状态码 200。
-
如果一致,说明资源没有被改过,则返回 Header,返回状态码 304。浏览器接受到这个消息就可以使用本地缓存库的数据。
ETag/If-None-Match 第二次请求服务器
注意:ETag 和 If-None-Match 指的是同一个值,只是在客户端和服务器端的叫法不同。
注:本文摘自51CTO技术栈