有趣生活

当前位置:首页>科技>缓存容量预估5W1H分析法帮你系统掌握缓存

缓存容量预估5W1H分析法帮你系统掌握缓存

发布时间:2026-07-21阅读(1)

导读来,先上文章的目录,让大家可以对缓存这块知识先建立一个系统性的认知,然后我会按点逐个击破,读者们也可以按需阅读哈!文章目录一、什么是缓存(What)维基百科....

来,先上文章的目录,让大家可以对 缓存 这块知识先建立一个系统性的认知,然后我会按点逐个击破,读者们也可以按需阅读哈!

文章目录

一、什么是缓存(What)

维基百科对缓存的定义是:

In computing, a cache is a hardware or software component that stores data so that future requests for that data can be served faster; the data stored in a cache might be the result of an earlier computation or a copy of data stored elsewhere.

简而言之,缓存就是存储数据副本或计算结果的组件,以便后续可以更快地访问。

有缓存 VS 无缓存

在计算中,缓存是一个高速数据存储层,其中存储了数据的子集,且通常是短暂性存储,这样日后再次请求该数据时,直接读缓存会比重新计算结果或读数据存储更快。通过缓存,你可以高效地重用之前检索或计算的数据。

二、为什么要使用缓存(Why)

从定义上可以看出所谓缓存其实是其他数据的副本,使用缓存是为了更快地检索或计算数据。

1.硬件层面:如CPU中的高速缓存

CPU VS 内存

从上图可以看出CPU(蓝色)和内存(粉红色)之间存在巨大的性能差距。

在CPU访问数据和指令遵循计算机系统的局部性原理:

  • 时间局部性:CPU 通常使用的许多数据会被多次使用。
  • 空间局部性:CPU 使用的许多数据通常在物理上接近以前使用的数据。

使用高速缓存可以弥补CPU和内存之间的性能差异,减少 CPU 浪费计算时间等待内存数据。

2.软件层面
  • 为缓解 CPU 压力而做缓存:比如把方法运行结果存储起来、把原本要实时计算的内容提前算好、把一些公用的数据进行复用,这可以节省 CPU 算力,顺带提升响应性能。
  • 为缓解 I/O 压力而做缓存:比如把原本对网络、磁盘等较慢介质的读写访问变为对内存等较快介质的访问,将原本对单点部件(如数据库)的读写访问变为到可扩缩组件(如缓存中间件)的访问,顺带提升响应性能。
3.产品层面

是否可以解决用户的痛点问题决定着用户会不会一开始尝试使用某款产品,是否有极致的用户体验影响用户会不会持续使用某款产品。在业务中使用缓存的目的就是通过扩大系统吞吐量、减少时延和响应时间来优化用户体验,适当的性能优化可以提升体验,增强用户粘性。

在现有的互联网应用中,缓存的使用是一种能够提升服务快速响应的关键技术,也是产品经理无暇顾及的非功能需求,需要在设计技术方案时对业务场景,具有一定的前瞻性评估后,决定在技术架构中是否需要引入缓存解决这种这种非功能需求。

三、什么时候使用缓存(When)

缓存不是架构设计的必选项,也不是业务开发中的必要功能点,只有在业务出现性能瓶颈,进行优化性能的时候才需要考虑使用缓存来提升系统性能。并非所有的业务场景都适合用缓存,读多写少、不要求一致性、时效要求越低、访问频率越高、对最终一致性和数据丢失有一定程度的容忍的场景才适合使用缓存,缓存并不能解决所有的性能问题,倘若滥用缓存会带来额外的维护成本,使得系统架构更复杂更难以维护。

虽然缓存适用于各种各样的案例,但要充分利用缓存,需要进行一定的规划。所以在决定是否缓存一段数据时,请考虑以下问题:

  • 使用缓存值是否安全? 相同的数据在不同的上下文中可能有不同的一致性要求。例如电商系统中,在线结账期间,必须知道商品的确切价格,因此不适合使用缓存,但在其他页面上,价格晚几分钟更新不会给用户带来负面影响。
  • 对于该数据而言,缓存是否高效? 某些应用程序会生成不适合缓存的访问模式;例如,扫描频繁变化的大型数据集的键空间。在这种情况下,保持缓存更新可能会抵消缓存带来的所有优势。
  • 数据结构是否适合缓存?例如:以单条数据库记录形式缓存数据通常足以提供显著的性能优势。但有些时候,数据最好以多条记录组合在一起的格式进行缓存。缓存以简单的键值形式存储,因此您可能还需要以多种不同格式缓存数据记录,以便按记录中的不同属性进行访问。

另外把缓存当做存储来使用是一件极其致命的做法,这种错误的认识,将缓存引入系统的那一刻起就意味着已经让系统走上了危险的局面,只有对缓存的使用边界有深刻的理解,才能尽可能减少引入缓存带来的副作用。

四、谁会使用缓存(Who)

其实缓存的思想随处可见,日常生活中人们都会有意无意地用到。比如你会把常看的书放到书桌上,这样你可以更快地拿到它们,而受限于桌面空间,不常看的书就要放在空间更大的书柜里了,等到要看的时候再从书柜里拿出来放到书桌上。这里的书桌其实就是一种缓存介质了。

对于程序员来说,缓存更是家常便饭了。有哪些程序员会用到缓存技术呢?

1.硬件开发工程师:比如CPU缓存、GPU缓存和数字信号处理器(DSP)缓存等。

2.软件开发工程师:

  • 客户端开发:比如第4章节讲到的页面、浏览器、APP缓存技术都和客户端息息相关。
  • 后端开发:比如服务端本地缓存、redis和memcached充当数据库缓存、静态页面缓存等。
  • 分布式开发:现在分布式大行其道,分布式缓存必然是分布式开发中绕不开的一环,6.10节的分布式缓存也是我们要重点讲解的。
  • 操作系统开发:操作系统内核负责管理磁盘缓存,比较典型的就有主存中的页面缓存技术。
五、哪些地方会使用缓存(Where)1.缓存分类

按照不同的维度,可以对缓存分门别类,如下图所示。

缓存分类

下面我着重按照 缓存所处链路节点的位置 来系统梳理出不同类型的缓存应用。

(1)客户端缓存

HTTP 协议的无状态性决定了它必须依靠客户端缓存来解决网络传输效率上的缺陷。由于每次请求都是独立的,服务端不保存此前请求的状态和资源,所以也不可避免地导致其携带有重复的数据,造成网络性能降低。HTTP 协议对此问题的解决方案便是客户端缓存。

常见的客户端缓存有如下几种:

1)页面缓存

页面缓存是指将静态页面获取页面中的部分元素缓存到本地,以便下次请求不需要重复资源文件,h5很好的支持的离线缓存的功能,具体实现可通过页面指定manifest文件,当浏览器访问一个带有manifest属性的文件时,会先从应用缓存中获取加载页面的资源文件,并通过检查机制处理缓存更新的问题。

2)APP缓存

APP可以将内容缓存到内存或者本地数据库中,例如在一些开源的图片库中都具备缓存的技术特性,当图片等资源文件从远程服务器获取后会进行缓存,以便下一次不再进行重复请求,并可以减少用户的流量费用。

客户端缓存是前端性能优化的一个重要方向,毕竟客户端是距离“用户”最近的地方,是一个可以充分挖掘优化潜力的地方。

3)浏览器缓存

浏览器缓存通常会专门开辟内存空间以存储资源副本,当用户后退或者返回上一步操作时可以通过浏览器缓存快速的获取数据,减少页面加载时间和带宽使用。在 HTTP 从 1.0 到 1.1,再到 2.0 版本的每次演进中,逐步形成了现在被称为“状态缓存”、“强制缓存”(许多资料中简称为“强缓存”)和“协商缓存”的 HTTP 缓存机制。在HTTP 1.1中通过引入e-tag标签并结合expire、cache-control两个特性能够很好的支持浏览器缓存。

下面我们用思维导图理解 强制缓存 和 协商缓存,请注意体会梳理思路!

浏览器缓存

对于Etag的补充说明:

HTTP 服务器可以根据自己的意愿来选择如何生成这个标识,比如 Apache 服务器的 Etag 值默认是对文件的索引节点(INode),大小和最后修改时间进行哈希计算后得到的。

Etag 是 HTTP 中一致性最强的缓存机制,比如,Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在 1 秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间;又或者如果某些文件会被定期生成,可能内容并没有任何变化,但 Last-Modified 却改变了,导致文件无法有效使用缓存,这些情况 Last-Modified 都有可能产生资源一致性问题,只能使用 Etag 解决。

Etag 却又是 HTTP 中性能最差的缓存机制,体现在每次请求时,服务端都必须对资源进行哈希计算,这比起简单获取一下修改时间,开销要大了很多。Etag 和 Last-Modified 是允许一起使用的,服务器会优先验证 Etag,在 Etag 一致的情况下,再去对比 Last-Modified,这是为了防止有一些 HTTP 服务器未将文件修改日期纳入哈希范围内。

扩展知识:内容协商机制

到这里为止,HTTP 的协商缓存机制已经能很好地处理通过 URL 获取单个资源的场景,为什么要强调“单个资源”呢?在 HTTP 协议的设计中,一个 URL 地址是有可能能够提供多份不同版本的资源,比如,一段文字的不同语言版本,一个文件的不同编码格式版本,一份数据的不同压缩方式版本,等等。因此针对请求的缓存机制,也必须能够提供对应的支持。为此,HTTP 协议设计了以 Accept(Accept、Accept-Language、Accept-Charset、Accept-Encoding)开头的一套请求 Header 和对应的以 Content-(Content-Language、Content-Type、Content-Encoding)开头的响应 Header,这些 Headers 被称为 HTTP 的内容协商机制。与之对应的,对于一个 URL 能够获取多个资源的场景中,缓存也同样也需要有明确的标识来获知根据什么内容来对同一个 URL 返回给用户正确的资源。这个就是 Vary Header 的作用,Vary 后面应该跟随一组其他 Header 的名字,比如:

复制1HTTP/1.1 200 OK2Vary: Accept, User-Agent1.2.

以上响应的含义是应该根据 MIME 类型和浏览器类型来缓存资源,获取资源时也需要根据请求 Header 中对应的字段来筛选出适合的资源版本。

(2)网络缓存

网络缓存位于客户端以及服务端中间,通过代理的方式解决数据请求的响应,降低数据请求的回源率。回源率又分为以下两种:

  • 回源流量比:回源流量是代理服务器节点请求源服务器资源时产生流量。回源流量比=回源流量/(回源流量 用户请求访问的流量),比值越低,性能越好。
  • 回源请求数比:指代理服务器节点对于没有缓存、缓存过期(可缓存)和不可缓存的请求占全部请求记录的比例。

网络缓存常见的代理形式分为两种:web代理缓存、边缘缓存。

在介绍网络缓存之前我们先了解下前置知识----两种服务器代理方式:正向代理、反向代理。

正向代理其实就是:客户端通过代理服务器与源服务器进行非直接连接。客户端可以感知到代理服务器的存在,对源服务器透明(源服务器感知不到客户端的存在),如下图所示:

正向代理

通信时客户端和代理服务器要设置好代理协议,比如Socks协议或者是HTTP协议(可以设置4.1节浏览器缓存中的HTTP Header)。

那正向代理有什么作用呢?

  • 提高访问速度:通常代理服务器都设置一个较大的缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
  • 控制对内部资源的访问:如某大学FTP(前提是该代理地址在该资源的允许访问范围之内)使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
  • 过滤、调整内容:例如限制对特定计算机的访问、压缩请求包、改变请求包的语言格式等。
  • 隐藏真实IP:通过代理服务器隐藏自己的IP,但更安全的方法是利用特定的工具创建代理链(如:Tor)。
  • 突破网站的区域限制:通过代理服务器访问一些被限制的网站。

反向代理就是:客户端通过代理服务器与源服务器进行非直接连接。客户端只会得知反向代理的IP地址,而不知道在代理服务器后面的服务器集群的存在。如下图所示:

反向代理

反向代理有什么作用呢?

  • 对于静态内容及短时间内有大量访问请求的动态内容提供缓存服务。
  • 对客户端隐藏服务器(集群)的IP地址。
  • 安全:作为应用层防火墙,为服务器提供基于Web的攻击行为(例如DoS/DDoS)的防护,更容易排查恶意软件等
  • 为后端服务器(集群)统一提供加密和SSL加速(如SSL终端代理)。
  • 负载均衡:若服务器集群中有机器负荷较高,反向代理通过URL重写,把请求转移到低负荷机器获取与所需相同的资源。深入了解负载均衡强烈推荐看这篇干货:​老生常谈的负载均衡,你真的懂了吗?​​
  • 对一些内容进行压缩,以节约带宽或为带宽不佳的网络提供正常服务。
  • 提供HTTP访问认证。
  • 介绍完2种服务器代理形式后,我们来说下两种网络缓存形式。

1)web代理缓存:web代理缓存通常是指正向代理,会将资源文件和热点数据放在代理服务器上,当新的请求到来时,如果在代理服务器上能获取数据,则不需要重复请求到应用服务器上。

2)边缘缓存:和正向代理一样,反向代理同样可以用于缓存,例如nginx就提供了缓存的功能。进一步,如果这些反向代理服务器能够做到和用户请求来自同一个网络,那么获取资源的速度进一步提升,这类的反向代理服务器可以称之为边缘缓存。常见的边缘缓存就是内容分发网络(Content Delivery Network),简称CDN。可以将图片等静态资源文件放到CDN上。

那什么CDN呢?

如果把某个互联网系统比喻为一家跨国企业,那内容分发网络就是它遍布世界各地的分销机构,如果现在有客户要买一块 CPU,那订机票飞到美国加州英特尔总部肯定是不合适的,到本地电脑城找个装机店铺才是普遍的做法,在此场景中,内容分发网络就相当于电脑城里的本地经销商。

那CDN的主要工作过程有哪些呢?主要包括路由解析、内容分发、​​负载均衡​​(干货文章,建议点击阅读)、CDN的利用场景。

路由解析

一次没有内容分发网络参与的DNS域名解析过程如下:

无论是使用浏览器抑或是在程序代码中访问某个网址域名,比如以www.wallbig.club.cn为例,如果没有缓存的话,都会先经过 DNS 服务器的解析翻译,找到域名对应的 IP 地址才能开始通信,这项操作是操作系统自动完成的,一般不需要用户程序的介入。不过,DNS 服务器并不是一次性地将“www.wallbig.club.cn”直接解析成 IP 地址,需要经历一个递归的过程。首先 DNS 会将域名还原为“www.wallbig.club.cn.”,注意最后多了一个点“.”,它是“.root”的含义。早期的域名必须带有这个点才能被 DNS 正确解析,如今几乎所有的操作系统、DNS 服务器都可以自动补上结尾的点号,然后开始如下解析步骤:

  • 客户端先检查本地的 DNS 缓存,查看是否存在并且是存活着的该域名的地址记录。DNS 是以存活时间(Time to Live,TTL)来衡量缓存的有效情况的,所以,如果某个域名改变了 IP 地址,DNS 服务器并没有任何机制去通知缓存了该地址的机器去更新或者失效掉缓存,只能依靠 TTL 超期后的重新获取来保证一致性。后续每一级 DNS 查询的过程都会有类似的缓存查询操作。
  • 客户端将地址发送给本机操作系统中配置的本地 DNS(Local DNS),这个本地 DNS 服务器可以由用户手工设置,也可以在 DHCP 分配时或者在拨号时从 PPP 服务器中自动获取到。
  • 本地 DNS 收到查询请求后,会按照“是否有www.wallbig.club.cn的权威服务器”→“是否有wallbig.club.cn的权威服务器”→“是否有club.cn的权威服务器”→“是否有cn的权威服务器”的顺序,依次查询自己的地址记录,如果都没有查询到,就会一直找到最后点号代表的根域名服务器为止。这个步骤里涉及了两个重要名词:

权威域名服务器(Authoritative DNS):是指负责翻译特定域名的 DNS 服务器,“权威”意味着这个域名应该翻译出怎样的结果是由它来决定的。DNS 翻译域名时无需像查电话本一样刻板地一对一翻译,根据来访机器、网络链路、服务内容等各种信息,可以玩出很多花样,权威 DNS 的也有很多灵活应用,后面也会讲到。

根域名服务器(Root DNS)是指固定的、无需查询的顶级域名(Top-Level Domain)服务器,可以默认为它们已内置在操作系统代码之中。全世界一共有 13 组根域名服务器(注意并不是 13 台,每一组根域名都通过任播的方式建立了一大群镜像,根据维基百科的数据,迄今已经超过 1000 台根域名服务器的镜像了)。13 这个数字是由于 DNS 主要采用 UDP 传输协议(在需要稳定性保证的时候也可以采用 TCP)来进行数据交换,未分片的 UDP 数据包在 IPv4 下最大有效值为 512 字节,最多可以存放 13 组地址记录,由此而来的限制。

现在假设本地 DNS 是全新的,上面不存在任何域名的权威服务器记录,所以当 DNS 查询请求按步骤 3 的顺序一直查到根域名服务器之后,它将会得到“cn的权威服务器”的地址记录,然后通过“cn的权威服务器”,得到“club.cn的权威服务器”的地址记录,以此类推,最后找到能够解释www.wallbig.club.cn的权威服务器地址。

通过“www.wallbig.club.cn的权威服务器”,查询www.wallbig.club.cn的地址记录,地址记录并不一定就是指 IP 地址,在 RFC 规范中有定义的地址记录类型已经多达数十种,比如 IPv4 下的 IP 地址为 A 记录,IPv6 下的 AAAA 记录、主机别名 CNAME 记录,等等。

下面画个图,方便大家理解这个解析过程:

没有CDN参与的用户访问解析过程

前面提到过,每种记录类型中还可以包括多条记录,以一个域名下配置多条不同的 A 记录为例,此时权威服务器可以根据自己的策略来进行选择,典型的应用是智能线路:根据访问者所处的不同地区(比如华北、华南、东北)、不同服务商(比如电信、联通、移动)等因素来确定返回最合适的 A 记录,将访问者路由到最合适的数据中心,达到智能加速的目的。

那如果有CDN参与的话,路由解析的具体工作过程又是哪样的呢?

  • 架设好“wallbig.club”的服务器后,将服务器的 IP 地址在你的 CDN 服务商上注册为“源站”,注册后你会得到一个 CNAME,即本例中的“wallbig.club.cdn.dnsv1.com.”。
  • 将得到的 CNAME 在你购买域名的 DNS 服务商上注册为一条 CNAME 记录。
  • 当第一位用户来访你的站点时,将首先发生一次未命中缓存的 DNS 查询,域名服务商解析出 CNAME 后,返回给本地 DNS,至此之后链路解析的主导权就开始由内容分发网络的调度服务接管了。
  • 本地 DNS 查询 CNAME 时,由于能解析该 CNAME 的权威服务器只有 CDN 服务商所架设的权威 DNS,这个 DNS 服务将根据一定的均衡策略和参数,如拓扑结构、容量、时延等,在全国各地能提供服务的 CDN 缓存节点中挑选一个最适合的,将它的 IP 代替源站的 IP 地址,返回给本地 DNS。
  • 浏览器从本地 DNS 拿到 IP 地址,将该 IP 当作源站服务器来进行访问,此时该 IP 的 CDN 节点上可能有,也可能没有缓存过源站的资源,这点将在下面的“内容分发”小节讨论。
  • 经过内容分发后的 CDN 节点,就有能力代替源站向用户提供所请求的资源。

为了读者更生动地理解以上步骤,我画个时序图,建议和上面的图对比来看:

CDN路由解析过程

DNS 系统多级分流的设计使得 DNS 系统能够经受住全球网络流量不间断的冲击,但也并非全无缺点。典型的问题是响应速度,当极端情况(各级服务器均无缓存)下的域名解析可能导致每个域名都必须递归多次才能查询到结果,显著影响传输的响应速度。

专门有一种被称为“DNS 预取”(DNS Prefetching)的前端优化手段用来避免这类问题:如果网站后续要使用来自于其他域的资源,那就在网页加载时生成一个 link 请求,促使浏览器提前对该域名进行预解释,比如下面代码所示:

复制<link rel="dns-prefetch" href="//domain.not-wallbig.club">1.

而另一种可能更严重的缺陷是 DNS 的分级查询意味着每一级都有可能受到中间人攻击的威胁,产生被劫持的风险。要攻陷位于递归链条顶层的(比如根域名服务器,cn 权威服务器)服务器和链路是非常困难的,它们都有很专业的安全防护措施。但很多位于递归链底层或者来自本地运营商的 Local DNS 服务器的安全防护则相对松懈,甚至不少地区的运营商自己就会主动进行劫持,专门返回一个错的 IP,通过在这个 IP 上代理用户请求,以便给特定类型的资源(主要是 HTML)注入广告,以此牟利。

为此,最近几年出现了另一种新的 DNS 工作模式:HTTPDNS(也称为 DNS over HTTPS,DoH)。它将原本的 DNS 解析服务开放为一个基于 HTTPS 协议的查询服务,替代基于 UDP 传输协议的 DNS 域名解析,通过程序代替操作系统直接从权威 DNS 或者可靠的 Local DNS 获取解析数据,从而绕过传统 Local DNS。这种做法的好处是完全免去了“中间商赚差价”的环节,不再惧怕底层的域名劫持,能够有效避免 Local DNS 不可靠导致的域名生效缓慢、来源 IP 不准确、产生的智能线路切换错误等问题。

内容分发

在 DNS 服务器的协助下,无论是对用户还是服务器,内容分发网络都可以是完全透明的,在两者都不知情的情况下,由 CDN 的缓存节点接管了用户向服务器发出的资源请求。后面随之而来的问题是缓存节点中必须有用户想要请求的资源副本,才可能代替源站来响应用户请求。这里面又包括了两个子问题:“如何获取源站资源”和“如何管理(更新)资源”。

CDN 获取源站资源的过程被称为“内容分发”,“内容分发网络”的名字正是由此而来,可见这是 CDN 的核心价值。目前主要有以下两种主流的内容分发方式:

  • 主动分发(Push):分发由源站主动发起,将内容从源站或者其他资源库推送到用户边缘的各个 CDN 缓存节点上。这个推送的操作没有什么业界标准可循,可以采用任何传输方式(HTTP、FTP、P2P,等等)、任何推送策略(满足特定条件、定时、人工,等等)、任何推送时间,只要与后面说的更新策略相匹配即可。由于主动分发通常需要源站、CDN 服务双方提供程序 API 接口层面的配合,所以它对源站并不是透明的,只对用户一侧单向透明。主动分发一般用于网站要预载大量资源的场景。比如双十一之前一段时间内,淘宝、京东等各个网络商城就会开始把未来活动中所需用到的资源推送到 CDN 缓存节点中,特别常用的资源甚至会直接缓存到你的手机 APP 的存储空间或者浏览器的localStorage上。
  • 被动回源(Pull):被动回源由用户访问所触发全自动、双向透明的资源缓存过程。当某个资源首次被用户请求的时候,CDN 缓存节点发现自己没有该资源,就会实时从源站中获取,这时资源的响应时间可粗略认为是资源从源站到 CDN 缓存节点的时间,再加上资源从 CDN 发送到用户的时间之和。因此,被动回源的首次访问通常是比较慢的(但由于 CDN 的网络条件一般远高于普通用户,并不一定就会比用户直接访问源站更慢),不适合应用于数据量较大的资源。被动回源的优点是可以做到完全的双向透明,不需要源站在程序上做任何的配合,使用起来非常方便。这种分发方式是小型站点使用 CDN 服务的主流选择,如果不是自建 CDN,而是购买阿里云、腾讯云的 CDN 服务的站点,多数采用的就是这种方式。

对于“CDN 如何管理(更新)资源”这个问题,同样没有统一的标准可言,尽管在 HTTP 协议中,关于缓存的 Header 定义中确实是有对 CDN 这类共享缓存的一些指引性参数,比如“浏览器”小节HTTP header参数Cache-Control的 s-maxage,但是否要遵循,完全取决于 CDN 本身的实现策略。

现在,最常见的做法是超时被动失效与手工主动失效相结合。超时失效是指给予缓存资源一定的生存期,超过了生存期就在下次请求时重新被动回源一次。而手工失效是指 CDN 服务商一般会提供给程序调用来失效缓存的接口,在网站更新时,由持续集成的流水线自动调用该接口来实现缓存更新。

负载均衡

负载均衡就是以统一的接口对外提供服务,但构建和调度服务集群对用户保持透明。深入了解负载均衡强烈推荐看这篇干货:老生常谈的负载均衡,你真的懂了吗?

CDN的应用场景
  • 加速静态资源:这是 CDN 最普遍的应用场景。
  • 安全防御:CDN 在广义上可以视作网站的堡垒机,源站只对 CDN 提供服务,由 CDN 来对外界其他用户服务,这样恶意攻击者就不容易直接威胁源站。CDN 对某些攻击手段的防御,如对DDoS 攻击的防御尤其有效。但需注意,将安全都寄托在 CDN 上本身是不安全的,一旦源站真实 IP 被泄漏,就会面临很高的风险。
  • 协议升级:不少 CDN 提供商都同时对接(代售 CA 的)SSL 证书服务,可以实现源站是 HTTP 协议的,而对外开放的网站是基于 HTTPS 的。同理,可以实现源站到 CDN 是 HTTP/1.x 协议,CDN 提供的外部服务是 HTTP/2 或 HTTP/3 协议、实现源站是基于 IPv4 网络的,CDN 提供的外部服务支持 IPv6 网络,等等。
  • 状态缓存:CDN 不仅可以缓存源站的资源,还可以缓存源站的状态,比如源站的 301/302 转向就可以缓存起来让客户端直接跳转、还可以通过 CDN 开启HSTS、可以通过 CDN 进行OCSP 装订加速 SSL 证书访问等。有一些情况下甚至可以配置 CDN 对任意状态码(比如 404)进行一定时间的缓存,以减轻源站压力,但这个操作应当慎重,在网站状态发生改变时去及时刷新缓存。
  • 修改资源:CDN 可以在返回资源给用户的时候修改它的任何内容,以实现不同的目的。比如,可以对源站未压缩的资源自动压缩并修改 Content-Encoding,以节省用户的网络带宽消耗、可以对源站未启用客户端缓存的内容加上缓存 Header,自动启用客户端缓存,可以修改CORS的相关 Header,将源站不支持跨域的资源提供跨域能力等。
  • 访问控制:CDN 可以实现 IP 黑/白名单功能,根据不同的来访 IP 提供不同的响应结果,根据 IP 的访问流量来实现 QoS 控制、根据 HTTP 的 Referer 来实现防盗链等。
  • 注入功能:CDN 可以在不修改源站代码的前提下,为源站注入各种功能。
六、缓存必知必会1.缓存击穿

缓存击穿是一个失效的热点Key被并发集中访问,导致请求全部打在数据库上。图如下:

缓存击穿

解决方案:

(1)热点key缓存不失效:对热点key可以设置永不过期。

(2)使用互斥锁或堵塞队列:这样可以控制数据库的线程访问数,减小数据库的压力,但也会让系统吞吐率有所下降。实现流程如下:

  • 阻塞当前 Key 的请求
  • 从后端存储恢复数据
  • 在Key 对应的Value 还未恢复的过程中, 如果有其他请求继续获取该 Key, 同样阻塞该请求
  • 当key 从后端恢复后,依次唤醒该 Key 对应阻塞的请求

(3)用堵塞队列来实现的话可以参考Golang官方库singleflight

热点数据由代码来手动管理,缓存击穿是仅针对热点数据被自动失效才引发的问题,对于这类数据,可以直接由开发者通过代码来有计划地完成更新、失效,避免由缓存策略来自动管理。

2.缓存雪崩

某个时刻热点数据出现大规模的缓存失效,大量的请求全部打到数据库,导致数据库瞬时压力过载从而拒绝服务甚至是宕机。

缓存雪崩

分析:造成缓存雪崩的关键在于在同一时间大规模的key失效。诱因可能是:

(1)大量热点数据设置了相同或相近的过期时间。

(2)缓存组件不可用,比如redis宕机了。

解决方案:

(1)打散缓存失效时间:主要是通过对key的TTL增加随机数去尽量规避,过期时间则需要根据业务场景去设置。

(2)使用多级缓存:这里有个github开源库:hybridcache可以借鉴下

(3)兜底逻辑使用熔断机制。防止过多请求同时打到DB。

在触发熔断机制后返回预先配置好的兜底数据,减少过多请求压倒DB导致服务不可用。

熔断检测 数据兜底

(4)组件高可用:

  • 对于redis这样的缓存组件,可以搭建Redis集群(集群模式或哨兵模式),提高Redis的可用性,尽量规避单点故障导致缓存雪崩。

redis哨兵模式

Redis基于一个Master主节点多Slave从节点的模式和Redis持久化机制,将一份数据保持在多个实例中,从而实现增加副本冗余量,又使用哨兵机制实现主备切换, 在master故障时,自动检测,将某个slave切换为master,最终实现Redis高可用

  • 提高数据库的容灾能力,可以使用分库分表,读写分离的策略。
3.缓存穿透

缓存穿透是指用户查询数据库没有的数据,缓存中自然也不会有。那先查缓存再查数据相当于进行了两次无效操作。大量的无效请求将给数据库带来极大的访问压力,甚至导致其过载拒绝服务。下图中红色箭头标出了每一次用户请求到来都会经过的两次无效查询。

缓存穿透

分析:造成缓存穿透的原因可能是:

(1)空数据查询(黑客攻击),空数据查询通常指攻击者伪造大量不存在的数据进行访问(比如不存在的商品信息、用户信息)

(2)缓存污染(网络爬虫),缓存污染通常指在遍历数据等情况下冷数据把热数据驱逐出内存,导致缓存了大量冷数据而热数据被驱逐。

解决方案:

(1)对于空数据查询:

1)使用布隆过滤器高效判断key是否存在,流程如如下:

布隆过滤器方案

虽然不能完全避免数据穿透的现象,但已经可以将99%的穿透查询给屏蔽在Redis层了,极大的降低了底层数据库的压力,减少了资源浪费(布隆过滤器用bitmap实现)。如果想拥有更高的空间利用率和更小的误判,替代的方案是使用布谷鸟过滤器。如果想了解这两种过滤器的相关细节,强烈推荐看这篇文章:​​作为一名后台开发,你必须知道的两种过滤器​​

由于布隆过滤器存在“误报”和“漏报”,而且实现也比较复杂,对于空数据查询其实还有一种简单粗暴的策略:

2)缓存空值,流程图如下:

当碰到查询结果为空的key时,放一个空值到缓存中,下次再访问就知道此key是无效的,避免无效查询数据库。但这样花费额外的空间来存储空值。

(2)对于缓存污染:关键点是能识别出只访问一次或者访问次数很少的数据。然后使用淘汰策略去删除冷数据,下面以redis为例:

TAGS标签:  缓存  容量  预估  5w1H  分析法  缓存容量预估5W1H

Copyright © 2024 有趣生活 All Rights Reserve吉ICP备19000289号-5 TXT地图HTML地图XML地图