这是我阅读《HTTP权威指南》的总结和思考中,一系列文章的一篇,目录在这里
为什么需要缓存
缓存主要解决了四个问题
- 冗余数据传输: 节约了网络费用
- 带宽瓶颈: 降低了传输时延(=文件大小/带宽)
- 瞬间拥塞: 对于一些突发时间, 降低了对服务器的要求, 避免了网络崩溃
- 距离时延: 降低了传播时延(距离/光纤速度)
缓存结构
缓存分为两种:
- 私有缓存: 浏览器的临时文件
- 公有缓存: 特殊的代理服务器
拓扑结构又有两种:
- 层级结构: 越高层次缓存越大, 服务的用户越多, 私有缓存可以认为是第一级缓存
- 网状缓存/对等缓存: 多个不同组织之间共用缓存, 可以查询对等组织的缓存
缓存处理步骤
对于一个代理缓存服务器, 其处理缓存主要由7步构成, 核心在于新鲜度检测与更新
接收、解析、查找
- 缓存服务器监测到客户端输入,读取数据,在全部报文抵达前开始处理
- 将请求报文分片解析,格式化为易于分析的数据结构
- 在自身的存储(内存或者磁盘)中快速寻找该资源副本,如果不存在就访问服务器申请
新鲜度检测
新鲜度检测是缓存处理的核心,如果一个资源的副本不够新鲜,就要根据一定的策略向服务器查询该副本是否变化
文档过期
Cache-Control(HTTP/1.1): max-age: 定义一个以秒为最大单位的文档使用期限
1Cache-Control: max-age=484200Expires(HTTP/1.0+): 定义一个过期日期,依靠对本机日期(需要精确)和改日期比较确定是否过期
1Expires: Fri, 05 Jul 2002, 05:00:00 GMT
再验证
如果同时携带两者,必须同时满足才可以发送304
If-Modified-Since:
:服务器通过比较文件的修改日期和该头部的日期,确定是返回304还是200+文件实体 1If-Modified-Since: Sat, 29 Jun 2002, 14:30:00 GMTIf-None-Match:
:因为只用时间可能: 秒不够精确、未发生实际修改、服务器无法判断修改日期。所以资源返回一个 ETag
标签来标示是否修改123456//RequestIf-None-Match: "v2.6"//Response304 Not ModifiedETag: "v2.6"Expires: ......(date)
响应、发送、日志
- 缓存创建响应,其中
Date
首部使用原始服务器的值让客户端知道这是一个缓存 - 发送创建的响应
- 缓存服务器记录与缓存相关数据,如命中率等
缓存控制策略
控制策略
服务器通过Cache-Control
和Expires
首部来控制客户端的缓存策略
- no-Store: 不允许存储本地缓存文件,每次从服务器下载
- no-Cache: 允许存储缓存,但是每次都必须与原是服务器进行再验证
- max-age: 之前讨论过,表示新鲜度维持时间,=0类似于no-Cache
- must-revalidate: 有些缓存允许返回过期资源副本,设置该头部后,缓存只允许提供新鲜的副本,过期副本必须验证
- Expires: 之前讨论过,依赖于服务器时间,不推荐使用
试探新鲜度
如果没有设置新鲜度(max-age或Expires):
通常使用一些试探算法进行猜测,如LM算法1新鲜度 = LM因子(比如0.2) * (资源获取时间 - 资源最后修改时间)
如果无法获得最后修改日期,就只能直接设置为1小时或一天了
客户端新鲜度控制
客户端也可以通过Cache-Control
请求来强化或者放松对过期时间的限制
Cache-Control: max-stale (=<s>)
缓存可以提供过期文件,如果有参数s,最多过期s时间Cache-Control: min-fresh = <s>
缓存在未来s秒内要保持新鲜Cache-Control: max-age = <s>
缓存无法返回缓存时间大于s的资源no-Cache
orno-Store
必须再验证 or 必须尽快删除存储only-if-cached
只有缓存存在副本,才获取一份副本