- 某个请求能够通过缓存得到响应,称为缓存命中。
- 命中率越高,缓存利用率越高。
- 缓存的最大空间通常在内存中,当缓存存放的数据量超过最大空间,需要淘汰部分数据来存放新的数据。
- FIFO:先进先出,先进入缓存的数据在缓存空间不够时会优先被清除。
- LFU:最少使用策略。根据元素被使用次数判断,释放使用次数少的元素。
- LRU:最近使用策略。根据元素上一次使用的时间戳,清除最远使用时间戳的元素。
- 其他:过期时间、随机请理、优先请理大对象。
- 对于浏览器发送的网络请求来说,在真正发起请求之前,浏览器会根据HTTP协议头的内容对缓存进行查找;
- 查找的优先级如下:
- Service Worker
- Memory Cache
- Disk Cache
- 网络请求
-
service worker操作的缓存有别于浏览器内部的Memory Cache或Disk Cache的。
-
这个缓存时永久性的,即使关闭tab或者浏览器也会一直保存着。
-
清除缓存:手动调用cache.delete(resource)、容量超过限制、浏览器被清除数据。
-
如果service worker无法找到缓存,则会使用fetch方法进行资源的获取,这时候就继续往下一个缓存模式查找了。
-
经过service worker的fetch请求获取的资源,即使没有命中worker缓存或者通过网络请求获取的资源,也会标注成from serviceWorker
-
内存中的缓存,所有的网络请求资源都会被浏览器自动加入到memory cache种,因为数量很大,所以memory cache只能是短期存储。
-
当tab被关闭时,memory cache就失效了。
-
极端情况下,当缓存过多,可能会在tab关闭之前,某些缓存就被清除了。
-
所有的请求资源分为两块:
-
preloader:浏览器请求HTML后会进行解析,当发现js或css等需要解析执行的文件时,会使用CPU进行解析执行。preloader要做的事情就是让浏览器能够一边解析执行js或css,一边请求下一批网络资源。
这些preloader请求来的资源就会被放在memory cach中,共后续解析执行使用。
-
preload:预加载资源。显式指定预加载的资源也会被放在memory cache中。
-
-
这种机制使得当有相同的请求重复出现时,只需要请求一次网络即可。
-
在匹配缓存时,除了匹配URL,还会匹配文件类型,CORS中的域名规则等。所以不同类型的缓存资源是不同的,即使src相同。
-
memory cache的缓存内容中,浏览器会忽视max-age、no-cache等头部配置,继续加入缓存中。
-
实在不想要缓存,可以添加no-store选项,这样memory cache也不会进行缓存了。
- disk cache 也叫做HTTP cache,是持久化的硬盘存储,是实际存在于文件系统中的,而且它允许资源跨站点使用。
- disk cache会严格根据HTTP头信息的各类字段来判断哪些资源是可以缓存、哪些不可以缓存的;那些事可用的、哪些是过时的。
- 命中缓存后,浏览器会从硬盘中都读取资源,快于网络请求。
- 绝大部分缓存来自于disk cache
- 浏览器也会定期检查缓存自动清理。
- 如果在上述三个位置都没有找到缓存,则浏览器会发送网络请求去获取内容,然后把资源添加到缓存中:
- 根据service worker的handler决定是否存入cache storage
- 根据http头的相关字段决定是否缓存进disk
- memory保存一份资源的引用,方便下次使用。
这里的分类主要都属于disk cache,因为它比较遵守http的头信息来进行相应的缓存。
强缓存-
当客户端请求后,会先访问缓存数据库,查找缓存。如果存在直接返回;不存在就请求真的服务器,响应后写入缓存数据库。
-
强制缓存直接减少请求数,是提升最大的缓存策略。
-
如果考虑用缓存来优化网页性能的话,优先考虑强制缓存。
-
有两个字段可以造成强制缓存:
- Expires:这是HTTP1.0字段,是一个时间点,表示缓存的到期时间。但是,由于客户端可以自己修改时间,可能导致浏览器判断失效。另外误差也可能导致缓存失效。
- cache-control:HTTP1.1字段,表示资源缓存的最大有效时间,这是个相对时间。
-
cache-control字段常用值:
max-age:即最大有效时间,在上面的例子中我们可以看到
must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。
no-cache:虽然字面意思是“不要缓存”,但实际上还是要求客户端缓存内容的,只是是否使用这个内容由后续的对比来决定。
no-store: 真正意义上的“不要缓存”。所有内容都不走缓存,包括强制和对比。
public:所有的内容都可以被缓存 (包括客户端和代理服务器, 如 CDN)
private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。
-
max-age=0和no-cache两者是一样的吗?
前者是应该重新验证,后者是必须重新验证,但浏览器一般都视为同一种情况。
-
自从 HTTP/1.1 开始,Expires 逐渐被 Cache-control 取代。Cache-control 是一个相对时间,即使客户端时间发生改变,相对时间也不会随之改变,这样可以保持服务器和客户端的时间一致性。而且 Cache-control 的可配置性比较强大。
-
cache-control的优先级要高于expires,为了兼容HTTP1.0和HTTP1.1,一般都会同时设置。
对比缓存
-
当强制缓存超过时间后,就需要进行对比缓存,这个过程由服务器巨顶。
-
具体流程:浏览器请求缓存,得到一个标识。浏览器拿这个标识发送给服务器,如果缓存未失效,则返回304状态码,继续使用;否则返回新的数据和缓存规则,浏览器响应数据后,写入缓存数据库中。
-
对比缓存返回的仅仅是一个状态码(如果缓存仍生效),这样节省了响应体体积,缩短了网络传输的时间。
-
对比缓存有两个字段:
- Last-Modified:服务器告知客户端资源最后一次修改的时间。
- If-Modified-since:下一次请求相同资源时,将上次的last-modified字段的值写入到请求头。服务器将两者对比后,根据状态返回响应的状态码和文件。
-
缺陷:
- 如果更新速度时秒以下的,那么缓存不能被使用,因为他的时间单位最低为秒。
- 如果文件是动态生成的,那么更新时间永远是生成时间,这样就没办法达到缓存的目的。
-
为了解决上述缺陷,又提出了Etag和If-None-Match字段。
Etag:根据文件内容生成的hash值,其比较流程和上面的字段一致。
-
整个请求下来,最差的情况浏览器会执行这个过程:
- 调用Service Worker的fetch事件响应
- 查看memory cache
- 查看disk cache
- 发送网络请求,等待网络响应
- 把相应内容存入disk cache(Http允许存的)
- 把响应内容的引用存入memory cache
- 把相应内容存入Service worker的cache storage(如果调用了cache.put())
-
在分布式环境或系统下,将一些热门的数据存储到离用户近、离应用近的位置,并存储到读写速度尽量快的地方,以减少远程数据传输的延迟。
-
优点:本身是一个独立的应用,与本地应用隔离,多个应用可以共享缓存。
-
缺点:由于本地节点需要与其通信,导致依赖网络,受到服务器限制,并且要实现本地缓存与服务器集群同步,难度和性能开销都很大。
-
适用场景:对于多个实例的服务,或者数据变化频率较高的场景,可以使用分布式缓存。
- ISP:网络访问的第一跳,数据可以缓存在这里。
- 反向代理:反向代理位于服务器之前,将数据缓存在反向代理里面,用户请求反向代理时就可以直接使用缓存进行 响应。
- 数据库缓存:拥有自己的查询缓存机制。
- CPU多级缓存:解决运算速度与主存IO速度不匹配的问题。使用MESI等缓存一致性协议来保证多核CPU缓存数据的一致性。
- 内容分发网络,一种互连的网络系统。
- 利用靠近用户的服务器从而将一些静态资源分发给用户。
- 优点:
- 数据传输更快
- 通过部署多台服务器,提高系统整体的带宽性能。
- 多台服务器看成是冗余机制,从而具有较高的可用性。
- 对某个一定不存在的数据进行请求,该请求会穿透缓存到达数据库。
- 解决:
- 对不存在的数据缓存一个空数据
- 对这类请求进行过滤。
- 指的是由于数据没有加载到缓存中、缓存数据同一时间内大面积失效、缓存的服务器宕机,导致大量请求都到达了数据库,导致数据库崩溃。
- 解决方案:
- 观察用户行为,合理设置缓存时间,防止大面积失效。
- 使用分布式缓存,每个节点存储缓存的部分数据,保证有一个宕机时其他仍可以使用。
- 使用缓存预热,避免系统刚启动,大量数据还未进行缓存。
- 要求数据更新的同时,缓存也同步更新。
- 解决:
- 在数据更新时立即缓存
- 读取缓存前先判断缓存是否是最新的,不是的话进行缓存更新。
- 由于缓存一致性需要付出的代价很大, 尽量缓存对数据一致性要求不高的数据,允许脏数据的存在。
- 为了满足业务而添加了大量缓存节点,导致性能下降了。
- 原因:缓存系统通常使用hash函数,将key映射到对应的缓存结点。如果节点过多,键值会分布到更多的节点上,导致客户端一次批量操作涉及多个网络操作,从而涉及节点的操作,因此节点就下降了。
- 解决:
- 优化批量数据操作的命令。
- 减少网络通信的次数。
- 降低接入的成本,使用长连接、连接池,NIO等。
- 将数据计算哈希值后,根据哈希值分配到不同节点。
- hash(key)%N
- 当节点数量N发生变化后,几乎所有的数据都需要进行重新分布,导致大量数据的迁移。
- 将数据划分成多个连续的部分,根据ID或时间分不到不同的节点。
- 优点:
- 保持数据原有的顺序
- 能准确控制每台服务器的存储量,使得存储空间能够最大化被利用。
-
DHT,distribute hash table,目的是为了克服传统哈希在服务器上,当节点数量变化时大量数据迁移的问题。
-
原理:将哈希空间看成一个哈希环。每个服务器节点都配置到哈希环上, 数据对象通过哈希运算后得到哈希值后,存放到哈希环顺时针的大于等于该哈希值的节点上。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRJEnXJJ-1632641561430)(https://raw.githubusercontent.com/huangyivi/mygraph/master/20210721095910.jpeg)]
-
优势:在增加或删除结点时只会影响相邻的节点。
-
例如:下图中新增节点 X,只需要将它前一个节点 C 上的数据重新进行分布即可,对于节点 A、B、D 都没有影响。
-
虚拟节点:一致性哈希表数据分布很不均匀,系欸但存储的数据量有很大的差异。通过增加虚拟节点,然后将虚拟节点映射到真实节点上。虚拟节点远远多于真实节点,这样可以使得数据分布得更加均匀。
- 访问某个节点时,将该节点提出并从原链表删除,然后将其添加到头部,这样能保证链表尾部是最近没用过的节点。



