[https://www.youtube.com/watch?v=HiBDZgTNpXY](https://www.youtube.com/watch?v=HiBDZgTNpXY)

服务端缓存

CDN

**CDN** 全称是 Content Delivery Network/Content Distribution Network,翻译过的意思是 **内容分发网络** 。

我们可以将内容分发网络拆开来看:

  • 内容:指的是静态资源比如图片、视频、文档、JS、CSS、HTML。
  • 分发网络:指的是将这些静态资源分发到位于多个不同的地理位置机房中的服务器上,这样,就可以实现静态资源的就近访问比如北京的用户直接访问北京机房的数据。

所以,简单来说,CDN 就是将静态资源分发到多个不同的地方以实现就近访问,进而加快静态资源的访问速度,减轻服务器以及带宽的负担。

  • 全站加速(不同云服务商叫法不同,腾讯云叫 ECDN、阿里云叫 DCDN)既可以加速静态资源又可以加速动态资源,内容分发网络(CDN)主要针对的是 静态资源

CDN 工作原理是什么?

静态资源是如何被缓存到 CDN 节点中的?
你可以通过 **预热** 的方式将源站的资源同步到 CDN 的节点中。这样的话,用户首次请求资源可以直接从 CDN 节点中取,无需回源。这样可以降低源站压力,提升用户体验。

如果不预热的话,你访问的资源可能不在 CDN 节点中,这个时候 CDN 节点将请求源站获取资源,这个过程是大家经常说的 回源

  • 回源:当 CDN 节点上没有用户请求的资源或该资源的缓存已经过期时,CDN 节点需要从原始服务器获取最新的资源内容,这个过程就是回源。当用户请求发生回源的话,会导致该请求的响应速度比未使用 CDN 还慢,因为相比于未使用 CDN 还多了一层 CDN 的调用流程。
  • 预热:预热是指在 CDN 上提前将内容缓存到 CDN 节点上。这样当用户在请求这些资源时,能够快速地从最近的 CDN 节点获取到而不需要回源,进而减少了对源站的访问压力,提高了访问速度。
如何找到最合适的 CDN 节点?
GSLB (Global Server Load Balance,全局负载均衡)是 CDN 的大脑,负责多个 CDN 节点之间相互协作,最常用的是基于 DNS 的 GSLB。

CDN 会通过 GSLB 找到最合适的 CDN 节点,更具体点来说是下面这样的:

  1. 浏览器向 DNS 服务器发送域名请求;
  2. DNS 服务器向根据 CNAME( Canonical Name ) 别名记录向 GSLB 发送请求;
  3. GSLB 返回性能最好(通常距离请求地址最近)的 CDN 节点(边缘服务器,真正缓存内容的地方)的地址给浏览器;
  4. 浏览器直接访问指定的 CDN 节点。

CDN 原理示意图

为了方便理解,上图其实做了一点简化。GSLB 内部可以看作是 CDN 专用 DNS 服务器和负载均衡系统组合。CDN 专用 DNS 服务器会返回负载均衡系统 IP 地址给浏览器,浏览器使用 IP 地址请求负载均衡系统进而找到对应的 CDN 节点。

GSLB 是如何选择出最合适的 CDN 节点呢? GSLB 会根据请求的 IP 地址、CDN 节点状态(比如负载情况、性能、响应时间、带宽)等指标来综合判断具体返回哪一个 CDN 节点的地址。

Redis缓存

+ Redis现在常用于分布式缓存

缓存更新问题

[输入密码 · 语雀](https://www.yuque.com/snailclimb/mf2z3k/sy238z)

旁路缓存:

旁路缓存删除缓存失败的解决方案:

读写穿透

在上面的Cache Aside套路中,我们的应用代码需要维护两个数据存储,一个是缓存(Cache),一个是数据库(Repository)。所以,应用程序比较啰嗦。而Read/Write Through套路是把更新数据库(Repository)的操作由缓存自己代理了,所以,对于应用层来说,就简单很多了。可以理解为,应用认为后端就是一个单一的存储,而存储自己维护自己的Cache。

Read Through

Read Through 套路就是在查询操作中更新缓存,也就是说,当缓存失效的时候(过期或LRU换出),Cache Aside是由调用方负责把数据加载入缓存,而Read Through则用缓存服务自己来加载,从而对应用方是透明的。

Write Through

Write Through 套路和Read Through相仿,不过是在更新数据时发生。当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由Cache自己更新数据库(这是一个同步操作)

缓存更新的套路 | 酷 壳 - CoolShell(这里介绍的比较通俗易懂)

Write Behind Caching Pattern

在更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会异步地批量更新数据库。这个设计的好处就是让数据的I/O操作飞快,但是,其带来的问题是,数据不是强一致性的。

缓存击穿

**缓存中没有但数据库中有的数据**
  • 解决方法:

1、设置热点数据永远不过期。

2、接口限流与熔断,降级。重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些 服务 不可用时候,进行熔断,失败快速返回机制。

3、加互斥锁

  • 服务熔断是故障扩散导致的服务雪崩
  • 降级:是为了保护核心服务,关掉其他服务以腾出资源给主要服务。

4.后台刷新:后台定义一个job (定时任务)专门主动更新缓存数据。比如,一个缓存中的数据过期时间是30分钟,那么job每隔29分钟定时刷新数据,确保缓存中的数据始终是最新的

5.

熔断:

缓存穿透

**缓存和数据库中都没有的数据**
  • 解决办法:
  1. 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  2. 缓存空对象
  3. 布隆过滤器
1
2
3
不行
布隆过滤器不能删除,存在误判性,布隆过滤器通常用作缓存穿透问题的第一道防线,用于过滤掉大部分的无效请求。对于布隆过滤器判断为存在的请求,仍然需要进一步验证和处理。
可以举一个极端的例子:就是布隆过滤器使用久了,其中的bit为几乎全为1了,某个请求大量的过来了,这个时候布隆过滤器发现其可能存在于数据库中,就放行了该请求。但是其数据库中没有该数据,就会导致让数据库宕机。

缓存雪崩

**数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机**。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
  • 解决方法

1.过期时间随机化

2.加锁排队

3.二级缓存

缓存预热

启动系统的时候将数据刷到缓存中

缓存污染

缓存中一些只会被访问一次或者几次的的数据,被访问完后,再也不会被访问到,但这部分数据依然留存在缓存中,消耗缓存空间。

缓存污染会随着数据的持续增加而逐渐显露,随着服务的不断运行,缓存中会存在大量的永远不会再次被访问的数据。缓存空间是有限的,如果缓存空间满了,再往缓存里写数据时就会有额外开销,影响Redis性能。这部分额外开销主要是指写的时候判断淘汰策略,根据淘汰策略去选择要淘汰的数据,然后进行删除操作。

服务器本地缓存

Coffine

客户端缓存

Nginx缓存:

浏览器缓存:

http缓存:

HTTP 缓存会存储与请求关联的响应,并将存储的响应复用于后续请求。

有两种不同类型的缓存:私有缓存共享缓存

  • 私有缓存是绑定到特定客户端的缓存——通常是浏览器缓存。由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应。

另一方面,如果个性化内容存储在私有缓存以外的缓存中,那么其他用户可能能够检索到这些内容——这可能会导致无意的信息泄露。

  • 共享缓存位于客户端和服务器之间,可以存储能在用户之间共享的响应。共享缓存可以进一步细分为代理缓存托管缓存
    • 代理还实现了缓存以减少网络流量。这通常不由服务开发人员管理,因此必须由恰当的 HTTP 标头等控制。然而,在过去,过时的代理缓存实现——例如没有正确理解 HTTP 缓存标准的实现——经常给开发人员带来问题。
    • 托管缓存由服务开发人员明确部署,以降低源服务器负载并有效地交付内容。示例包括反向代理、CDN 和 service worker 与缓存 API 的组合。