为了搞清楚CDN的原理,我头都秃了...

2021-05-20 11:48:28 浏览数 (1)

作者:winty的帆宝宝

原文地址:https://juejin.cn/post/6944420222757503006

今天下班前忽然发现维护的项目网站打不开了,打开控制台一看,原来是资源请求的响应头设置了2个 access-control-allow-origin 导致的。(我寻思这东西就算设置重了不应该也能覆盖么)

image.png

image.png

image.png

解决完问题后,我有了以下疑惑:

  • 请求头和响应头中key的大小写真的有影响么,到底是怎么处理header中的key和value;
  • 运营人员修改配置后,为什么我们访问的节点没有刷新到,什么情况下节点的缓存会刷新;
  • cdn可提供下载加速服务,那它是怎么实现加速的?
  • cdn有哪些优点?

下面我们就带着问题进行探索。Let's Go~

问题一:请求头和响应头中key的大小写真的有影响么?header中的key和value是怎么被处理的?

image.png

image.png

上面做了个小实验,设置了2个类型相同的 key,content-type;它们唯一不同的大小写。可以看到结果,只保留了一个key,value值被拼接起来了。

域名解析的背景

在以前,人们用IP进行互访,后来发现IP太多不好记忆,便有了域名,比如 www.baidu.com,你一看就知道是百度搜索引擎,而不需要管他的服务器IP是多少,但是在最开始通信的时候,电脑路由器不认识域名,只认得IP啊,要怎么去获得对应的IP呢,这时候有了域名解析,就是去请求网络上的DNS服务器,让他们来告诉你这个域名对应的IP是多少。

常见的DNS解析服务商有:阿里云解析,万网解析,DNSPod,新网解析,Route53(AWS),Dyn,Cloudflare等。

CDN加速前

image.png

cdn加速前,域名解析过程如下:浏览器dns缓存 -> 系统dns缓存(Hosts文件) -> 路由器dns缓存 -> 本地DNS服务器(ISP运营服务提供商) -> 本地DNS服务器请求根域名服务器(13个,不是只有13台服务器,分布在世界各地),拿到dns记录 -> 本地DNS服务器根据拿到顶级域名服务器的ip,去请求顶级域名服务器(如.com顶级域名服务器) -> 本地DNS服务器根据拿到二级域名服务器的ip,去请求二级域名服务器 -> …… -> 直到X级域名服务器返回我们目标域名对应的ip地址后,本地DNS服务器缓存该dns记录,然后返回路由器 -> ……(层层缓存后,返回dns记录结果) -> 我们的客户端拿到ip地址,利用该ip地址,封装并发起http/http2请求。

备注:前面4个是递归查询,一旦缓存可用,就直接返回,不会再进行后续步骤,后面是迭代查询,最终获取ip地址,才会返回。

不使用cdn时,利用ip发起请求的过程,如广州的用户要请求一个在北京的 IP 地址,过程如下: 广州用户 -> 广州服务器 -> 湖南服务器 -> 湖北服务器 -> 北京服务器

这样传递数据,就很浪费时间,那如果广州服务器就缓存了数据或资源呢,那不就可以就近获取了。这便是cdn的部分策略了。

备注:TLD,意为顶级域名。 域名层级如下图:

image.png

CDN的工作原理和缓存策略

CDN概念

CDN(Content Delivery Network,内容分发网络)是构建在现有互联网基础之上的一层智能虚拟网络,通过在网络各处部署节点服务器,实现将源站内容分发至所有CDN节点,使用户可以就近获得所需的内容。 简单的说,CDN的工作原理就是将您源站的资源缓存到位于全球各地的CDN节点上,用户请求资源时,就近返回节点上缓存的资源,而不需要每个用户的请求都回您的源站获取,避免网络拥塞、缓解源站压力,保证用户访问资源的速度和体验。

CDN的优点如下:

  • CDN服务缩短了用户查看内容的访问延迟,提高了用户访问网站的响应速度;(终端用户内容获取延时高,比如服务器在北京,而用户在广州)
  • 解决了源站网络带宽小、用户访问量大、网点分布不均等问题,缓解了源站的压力;(中心服务器负载过高,因为所有客户端发起的请求都会打到服务器上)
  • 缓解甚至消除了不同运营商之间互联的瓶颈造成的影响;
  • 减轻了各省的出口带宽压力;
  • 缓解了骨干网的压力;
  • 优化了网上热点内容的分布;

备注:第3~5点详见参考链接[4],第6点举个例子,热点内容的服务器都在北京,如果我想获取热点内容,我就需要发送请求到北京的服务器,但若有了cdn,我只需要就近服务器获取热点内容,这样就分摊优化热点内容的分布了。

CDN节点缓存策略

CDN通过在现有网络中增加一层新的缓存节点,将源站的资源发布到最接近用户的网络节点,使得客户端在请求时直接访问到就近的CDN节点并命中该资源,减少回源情况,提高网站访问速度。 CDN缓存节点可分为L1节点(一级节点)和L2节点(二级节点),请求的流程是:客户端-->CDN_L1-->CDN_L2-->源站。CDN的L1节点分布在全国各省市,L2节点分布在几个大区下,可以把L2节点理解为汇聚式节点,简单架构如下图所示。

image.png

CDN节点缓存策略如下:

  1. 客户端向CDN节点发起连接请求,当L1节点有缓存资源时,会命中该资源,直接将数据返回给客户端。当L1节点无缓存资源时,会向L2节点请求对应资源,如果L2节点有缓存资源,则将资源同步到L1节点,并返回给用户;如果L2节点无缓存资源,则直接回客户源站获取资源,并按照配置的缓存策略进行缓存。
  2. 为了方便理解,再举一个例子,假设有杭州移动节点L1-hz和宁波移动节点L1-nb两个L1节点,这两个L1节点都回源到同一个L2这个节点,源站在北京。这几个CDN节点初始的时候都没有用户的缓存资源。当ABC三个用户依次请求同一个图片的时候,过程如下:
    1. 杭州移动用户A被CDN调度到杭州移动L1-hz节点,L1-hz由于没有缓存,则回源到L2,L2由于也没有缓存,则回源到北京源站,请求到数据以后再返回给L1-hz,L1再返回给用户A。
    2. 用户A请求完以后,L1-hz和L2节点都有了缓存资源。此时杭州移动用户B也开始访问这个图片,用户B也被分配到了L1-hz节点,由于L1-hz已经有这个图片的缓存了,因此不需要再去回源了,而是直接返回缓存给用户B。
    3. 宁波移动用户C此时也访问了同一个图片,用户C被分配到了宁波移动节点L1-nb,由于L1-nb还没有缓存,就会回源到L2,而L2已经有缓存,因此L2会直接返回缓存数据给L1-nb,然后L1-nb再返回给用户B。此过程存在L1-nb向L2回源的过程,而L2不需要再去回源到源站了。
    4. 通过CDN加速,杭州用户A和B可以直接从杭州节点读取缓存数据,宁波用户C可以直接从宁波节点读取数据,不需要每一次都去请求北京服务器了,提高了用户侧的访问速度,降低了服务器压力。

备注:

  • 其中,cdn缓存服务器还会根据不同运营商做区分,因为跨运营商需要在交换点进行转换,如果同个运营商则不需要转换,尽量会选择同一运营商的cdn缓存服务器来获取数据或回源。
  • CDN缓存一般分3层,客户端、CDN Cache L1、CDN Cache L2,当然也可以只有2层。
CDN工作原理

通过以下案例,可以进一步了解CDN的工作原理。 假设加速域名为www.a.com, 接入CDN网络,开始使用加速服务后,当终端用户(北京)发起HTTP请求时,处理流程如下图所示。

image.png

  1. 当终端用户(北京)向www.a.com 下的某资源发起请求时,首先向LDNS(本地DNS)发起域名解析请求。
  2. LDNS检查缓存中是否有www.a.com 的IP地址记录。如果有,则直接返回给终端用户;如果没有,则向授权DNS查询。
  3. 当授权DNS解析www.a.com 时,返回域名CNAME www.a.tbcdn.com 对应IP地址(实际就是DNS调度系统的ip地址)。
  4. 域名解析请求发送至DNS调度系统,DNS调度系统为请求分配最佳节点IP地址。
  5. LDNS获取DNS返回的解析IP地址。
  6. 用户获取解析IP地址。
  7. 用户向获取的IP地址发起对该资源的访问请求。
    1. 如果该IP地址对应的节点已缓存该资源,则会将数据直接返回给用户,例如,图中步骤7和8,请求结束。
    2. 如果该IP地址对应的节点未缓存该资源,则节点向源站发起对该资源的请求。获取资源后,结合用户自定义配置的缓存策略,将资源缓存至节点,例如,图中的北京节点,并返回给用户,请求结束。
什么资源可以被加速

在HTTP请求的资源,请求可以分为静态请求和动态请求。

  • 静态请求
    • 静态请求是指在不同请求中访问到的数据都相同的静态文件。例如:图片、视频、网站中的文件(html、css、js)、软件安装包、apk文件、压缩包文件等。
    • CDN加速的本质是缓存加速,将您服务器上存储的静态内容缓存在CDN节点上,当您访问这些静态内容时,无需访问服务器源站,就近访问CDN节点即可获取相同内容,从而达到加速的效果,同时减轻服务器源站的压力。
  • 动态请求
    • 动态请求是指在不同请求中访问到的数据不相同的动态内容。例如:网站中的文件(asp、jsp、php、perl、cgi)、API接口、数据库交互请求等。
    • 当客户端访问这些动态内容时,每次都需要访问用户的服务器,由服务器动态生成实时的数据并返回给客户端。因此CDN的缓存加速不适用于加速动态内容,CDN无法缓存实时变化的动态内容。对于动态内容请求,CDN节点只能转发回源站服务器,没有加速效果。
  • 如果用户的网站或App应用有较多动态内容,例如需要对各种API接口进行加速,则需要使用全站加速。全站加速能同时加速动态和静态内容,加速方式如下:
    • 静态内容使用CDN加速。
    • 动态内容通过路由优化、传输优化等动态加速技术以最快的速度访问您的服务器源站获取数据。从而达到全站加速的效果。

备注:(以下为个人见解) 动态请求中,路由优化是指请求路径优化为最短传输路径(不用经过太多服务器);传输优化是指同时部署多个运营商的服务器(比如电信、联通、移动都部署上),避免跨运营商间的请求转换。

CDN的缓存策略

静态内容可以在CDN上缓存多久,这个是根据CDN的缓存策略的。用户通过亚马逊云/阿里云/腾讯云控制台按照文件类型和目录设置缓存时间,针对静态资源配置指定目录和文件后缀名的缓存过期时间和优先级,资源过期后,自动从CDN节点删除。

CDN网络的组成要素

对于普通的Internet用户,每个CDN节点就相当于一个放置在它周围的网站服务器. 通过对dns的接管,用户的请求被透明地指向离他最近的节点,节点中CDN服务器会像网站的原始服务器一样,响应用户的请求。由于它离用户更近,因而响应时间必然更快。

image.png

从上面图中 虚线圈起来的那块,就是CDN层,这层是位于 用户端 和 站点服务器群 之间。

  • DNS智能调度系统(比如f5的3DNS)
    • DNS智能调度系统是CDN服务中的关键系统。当用户访问加入CDN服务的网站时,域名解析请求将最终由 “智能调度DNS”负责处理。它通过一组预先定义好的策略,将当时最接近用户的节点地址提供给用户,使用户可以得到快速的服务。同时DNS智能调度系统需要与分布在各地的CDN节点保持通信,跟踪各节点的「健康状态、容量」等信息,确保将用户的请求分配到就近可用的节点上。
  • 缓存功能服务
    • 负载均衡设备(如lvs, F5的BIG/IP)
    • 内容Cache服务器(如squid)
    • 共享存储

名词解释

A记录:解析域名到IP

A记录,即Address记录,它并不是一个IP或者一个域名,我们可以把它理解为一种指向关系:域名 www.xx.com → 222.222.222.222 也就是当你访问这些域名或者主机名的时候,DNS服务器上会通过A记录会帮你解析出相应的IP地址,以达到后续访问目的。 所以A记录是IP解析,直接将域名或主机名指向某个IP。

CNAME:解析域名到另外一个域名

CNAME记录,也叫别名记录,相当于给A记录中的域名起个小名儿,比如www.xx.com的小名儿就叫www.yy.com好了,然后CNAME记录也和A记录一样,是一种指向关系,把小名儿www.yy.com指向了www.xx.com,然后通过A记录,www.xx.com又指向了对应的IP:www.yy.com → www.xx.com → 111.111.111.111 这样一来就能通过它的小名儿直接访问111.111.111.111了。

这时候有人问:这不多了一步嘛,不嫌麻烦?

假如这个时候我又想给原域名取几个小名儿,分别叫www.cc.com和www.kk.com那么存在下列指向关系: www.yy.com → www.xx.com → 111.111.111.111 www.cc.com → www.xx.com → 111.111.111.111 www.kk.com → www.xx.com → 111.111.111.111

突然服务器的IP地址因为一些不可描述的原因要换了,不再是111.111.111.111了,换成了333.333.333.333,这时候你发现,只要把www.xx.com的指向修改一下即可: 域名 www.xx.com → 333.333.333.333

这时候你又发现了,原来他的小名儿不需要做更改,直接就能访问服务器,因为他们都只指向了www.xx.com,服务器IP改动与否,它们不管。

那么假如不用CNAME,直接做A记录会怎样? www.yy.com → 111.111.111.111 www.cc.com → 111.111.111.111 www.xx.com → 111.111.111.111 www.kk.com → 111.111.111.111 那么当111.111.111.111更改的时候,全部相关A记录指向关系都要做更改,这时会很麻烦。

CNAME的应用

比较多的是用在CDN加速上。 举个例子:假如你公司中的一台IP为1.1.1.1的服务器,注册了域名为www.dd.com,要对外提供客户访问。随着公司越做越大,访问量也越来越多,服务器顶不住了,你去找CDN提供商购买CDN加速服务,这个时候他们要求你的域名做个CNAME指向他们给你的一个域名叫www.xdd.com,当用户访问www.dd.com的时候,本地DNS会获得CDN提供的CNAME域名:www.xdd.com,然后再次向DNS调度系统发出请求,通过DNS调度系统的智能分析,把这个www.xdd.com指向一个(离用户最近的)CDN提供商的服务器IP,让用户就近取到想要的资源(如访问网站),这样就可以大大降低了延迟。

回源

当 cdn 缓存服务器中没有符合客户端要求的资源的时候,缓存服务器会请求上一级缓存服务器,以此类推,直到获取到,如果最后还是没有,就会回到我们自己的服务器(简称源站)去获取资源。

回源的时机:

  • 没有资源;
  • 资源过期;
  • 访问的资源是不可缓存的;
回源host

回源host:回源host决定回源请求访问到源站上的具体某个站点。

例子1:源站是域名源站为www.a.com, 回源host为www.b.com, 那么实际回源是请求到 www.a.com 解析到的IP, 对应的主机上的站点www.b.com

例子2:源站是IP源站为1.1.1.1, 回源host为www.b.com,那么实际回源的是1.1.1.1对应的主机上的站点 www.b.com

协议回源

指回源时使用的协议和客户端访问资源时的协议保持一致,即如果客户端使用 HTTPS 方式请求资源,当CDN节点上未缓存该资源时,节点会使用相同的 HTTPS 方式回源获取资源;同理如果客户端使用 HTTP 协议的请求,CDN节点回源时也使用HTTP协议。

TTL

TTL,Time-To-Live,意思为一条域名解析记录在DNS服务器中的存留时间。当各地的DNS服务器接受到解析请求时,就会向域名指定的NS服务器(NS,Name Server,名称服务器,DNS是最著名的NS服务器)发出解析请求从而获得解析记录;在获得这个记录之后,记录会在DNS服务器中保存一段时间,这段时间内如果再接到这个域名的解析请求,DNS服务器将不再向NS服务器发出请求,而是直接返回刚才获得的记录;而这个记录在DNS服务器上保留的时间,就是TTL值。

TTL的数值应该如何设置?

  • 增大TTL值,减少域名解析时间。
    • 一般情况下,域名解析的各个记录可能很长一段时间内都不会有变化。我们可以增大域名记录的TTL值让记录在各地DNS服务器中缓存的时间加长,这样在更长的一段时间内,我们访问这个网站时,本地ISP的DNS服务器就不需要向域名的DNS服务器发出解析请求,而直接从缓存中返回域名解析记录。不过需要注意的是,如果TTL设置的值过大,当您的网站更换空间时,旧的记录要很久才会更新,有时会造成网站的重要变动不能及时更新。
  • 减小TTL值,及时更新网络。
    • 更换空间99.9%会有DNS记录更改的问题,因为缓存的问题,新的域名记录在有的地方可能生效了,但在有的地方可能等上一两天甚至更久才生效。结果就是有的人可能访问到了新服务器,有的人访问到了旧服务器。这时我们可以减TTL值,让DNS服务器中的缓存尽快刷新。减少TTL值的操作必须在主机调整/网络调整之前提前进行。这样才能保证在主机/网络调整完成后,能够在最小时间内实现更新。不过如果数值设置太小,会使DNS频繁刷新,有时会造成访问不稳定。
边缘节点

边缘节点,指距离最终用户接入具有较少的中间环节的网络节点。

CDN 调度策略

CDN 调度是指通过各种策略将客户端请求调度到合理的目标机房。以达到成本、质量(可用性、平均速度)的最佳控制。

调度形式一般有以下几种:

  • DNS 调度
  • HTTP DNS 调度
  • 302 调度
  • 路由调度(Anycast)
DNS 调度

基于请求端 local DNS 的出口 IP 归属地以及运营商的 DNS 调度。

DNS 调度的问题:

  • DNS 缓存时间在 TTL 过期前是不会刷新的, 这样会导致节点异常的时候自动调度延时很大,会直接影响线上业务访问。
  • 大量的 local DNS 不支持 EDNS 协议,拿不到客户的真实IP,CDN 绝大多数时候只能通过local DNS IP来做决策,经常会出现跨区域调度的情况。
HTTP DNS 调度

客户端请求固定的 HTTP DNS 地址,根据返回获取解析结果。可以提高解析的准确性(不像DNS调度,只能通过local DNS IP来做决策),能很好的避免劫持等问题。

当然这种模式也有一些问题,例如客户端每次加载URL都可能产生一次HTTP DNS查询,这就对性能和网络接入要求很高。

302调度

基于客户端 IP 和 302 调度集群进行实时的流量调度。

我们来看一个例子:

  1. 访问 URL 链接后,此时请求到了调度群集上,我们能拿到的客户端信息有 客户端的出口IP(绝大多情况下是相同的),接下来算法和基于 DNS 的调度可以是一样的,只是判断依据由 local DNS 出口 ip 变成了客户端的出口IP。
  2. 浏览器收到302回应,跟随 Location 中的 URL,继续发起 http 请求,这次请求的目标 IP 是CDN 边缘节点,CDN节点会响应实际的文件内容。

302 调度的优势:

  • 实时调度,因为没有 local DNS 缓存的,适合 CDN 的削峰处理,对于成本控制意义重大;
  • 准确性高,直接获取客户端出口 IP 进行调度。

302 调度的劣势:

  • 每次都要跳转,对于延时敏感的业务不友好。一般只适用于大文件。
AnyCast BGP路由调度

基于 BGP AnyCast 路由策略,只提供极少的对外 IP,路由策略可以很快的调整。

目前 AWS CloudFront、CloudFlare 都使用了这种方式,在路由层面进行调度。

这种方式可以很好地抵御 DDOS 攻击,降低网络拥塞。

当然这种方式的成本和方案设计都比较复杂,所以国内的 CDN 目前还都是用 UniCast 的方式。

除了静态资源,API 是否可以缓存?

动态加速的对象是动态生成的网页,动态加速一般是对针对内容(如数据库信息等)在用户与- 源站之间建立高速通道,通过路由优化、TCP加速等技术手段对动态内容进行加速,降低节点到源站之间的时延,从而大大降低了用户访问动态网页的延迟。

其实这个问题我没有找到比较合适的解答,以下是个人见解: 我们使用 cdn 的原因是,我们经常有一些比较频繁请求且容量比较大的文件,并且更新频率不那么高的文件。这些文件如果我们都放在自己的服务器上,对于客户端,问题在于延长访问时间;对于服务器端是占用服务器端的资源。所以我们采用分布式的方式扔在 cdn 上。 但是 API请求不同,

  • 首先API请求经常更新,就算是简单的get请求,推送更新到所有 cdn 节点同样是需要耗费资源(如带宽,会对源站有压力)的。
  • 如果API请求是和用户信息等相关联的get请求,这种不适合进行cdn缓存,因为总是要进行回源,做缓存没有意义,而且还不安全;
  • 如果是post请求,那压根不用考虑cdn;
  • cdn 判断是否缓存是依靠 url,意味着cdn只能缓存 get 请求,所以cdn的应用范围是有限的。

所以 API 是不适合放在 cdn 上的。但是如果你的内容是相对静态的,不涉及和用户信息关联,更新不频繁,那么勉强可以考虑用cdn加速,如配置信息(但最好不要)。

资源的过期如何判定?cdn 是如何更新数据的?

资源过期时间就是请求/响应头部来判定(详情请自行搜索 强缓存和协商缓存 等关键词)。

那么 cdn 是如何更新数据的?

  • 分两种,主动(PUSH)和被动(PULL);
  • 被动,即利用回源就可以被动在途经的 cdn 节点缓存数据。;
  • 主动指的是,我们从服务器(或nginx)主动往 cdn 推送数据,主动刷新所有节点;
不同运营商宽带如何实现互相访问的?

通过BGP Peering(对等)等方式实现流量交换(相互访问),如两家运营商约定在特定地点(互联网交换点)集中进行流量交换。

所以如果你的运营商是电信,可以直接通过电信服务器访问你的目标IP,不需要经过交换转换,那肯定能大幅提高访问速度,当然还要看其他限制原因,如本市的电信,还是跨省的电信。

参考链接:

  • DNS缺点&升级方案(HttpDns,解决Local DNS劫持)
  • 计算机网络基础之CDN
  • 阮一峰的DNS 原理入门
  • 不同运营商宽带如何实现互相访问的?
  • 淘宝的cdn缓存方案,包括三级缓存结构、多副本清除CDN缓存方案等
  • CDN节点缓存策略、CDN工作原理、什么资源可以被加速
  • CDN加速原理
  • 什么是CNAME
  • 关于 cdn、回源等问题一网打尽
  • CDN 调度策略

0 人点赞