博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

CDN系统总结笔记

Posted on 2017-02-14 16:20  bw_0927  阅读(3583)  评论(0编辑  收藏  举报

https://blog.goquxiao.com/posts/2016/01/01/cdn-note/

2015年,也花了半年左右的时间用于研究、开发、维护公司的静态CDN系统了,自己也从对CDN系统一无所知、客户带宽只有几MB的规模,到最终全国客户带宽到了几十GB的规模。回顾整个过程,真算是对自己的生理、心理的一种考验,惊险、刺激!同时,也是对自己的一种锻炼。趁着元旦假期,从原理、架构、业务等方面,试着粗浅的总结下CDN系统。

原理

CDN的全称是『Content Delivery Network』,内容分发网络,主要的目的就是提高全国以及全球各地用户访问资源的速度,从而提升各项互联网产品的用户体验。我们可以设想一下,一个互联网产品,肯定会通过各种资源的形式提供服务,这些资源包括:图片、视频、还有普通用户感知不到的js/css脚本,而这些资源又是存储在服务器上,通过网络提供给用户。如果没有CDN的话,用户的每一个请求都会请求至你的服务器(CDN系统中叫做源站),收到服务器的处理能力以及网络情况的影响,等到请求到达一定规模之后,必然会出现请求响应过慢、甚至无法服务的情况。如果需要解决的话,就要自行部署冗余的在各运营商机房部署服务器、购买网络带宽,成本必然升高不少,同时还需要自己处理各个机房的各种问题,人力和精力还会投入不少。但是,有了CDN的话,就可以将服务器的各项资源分发至CDN的各个节点,通过流量调度,用户的请求就会打到链路最优的CDN节点上面,让资源的响应达到最快,增加的费用只是向CDN厂商支付的带宽费用。

从技术角度上,(静态资源)CDN就是基于HTML协议中的缓存机制,将客户的数据存储在离客户『最近』的节点,以达到加速功能的。这篇《 Caching Tutorial 》讲解的比较清楚,当然你也可以看权威的HTML的RFC。CDN节点就是位于用户和源站之间,作为一个中间的缓存代理。用户(的浏览器)发起了资源的请求,并没有之前请求至源站,而是请求到了CDN节点,如果CDN节点认为该资源是没有过期的,就直接将资源数据返回至用户;如果该资源是过期的,CDN节点则会发送请求至源站,拿到源站的数据之后,一方面再返回给用户,另一方面自己将数据存储起来,用于用户的后续相同请求。

架构

架构方面,一个CDN系统由以下几个子系统组成:

  • 缓存系统
  • 流量调度系统
  • 业务系统
  • 数据报表系统

架构图如下:

缓存系统

缓存系统,是CDN系统提供核心功能的模块,也是直接与用户打交道的模块。他的功能比较单纯:

  • 接收用户的HTTP请求,返回缓存资源
  • 维护用户的资源缓存,存储在内存和磁盘
  • 向客户源站或者更高层缓存系统发送请求,获取原始数据

开源的缓存系统也有不少,例如Squid、Apache Traffic Server、Varnish,甚至Nginx、HAProxy,也可以通过开发Module的形式成为一个缓存服务器。《 服务好“最后一公里”,高效CDN架构经验 》这篇文章通过多个纬度对比了这些开源缓存系统,概括的还算不错。根据之前的调研,CDN厂商使用的较多的是Squid和ATS,大部分也会在这些开源缓存系统上面进行二次开发。

在部署方面,一般采用二级缓存方式,这两级缓存节点,一级叫做『边缘节点』,另一级叫做『中心节点』。用户发起了一个资源请求,首先是请求到了边缘节点,如果边缘节点就有未过期的缓存,就直接返回给用户;如果没有的话,边缘节点就会请求中心节点,再以此类推;最后,如果连中心节点也没有缓存,就会请求客户的源站,最终将数据返回给用户。边缘节点的分布应该是尽量做到全面分散分布,需要选择各大小运营商的链路,为了能覆盖到尽可能多的用户;中心节点则是数量相对较少的各运营商访问链路质量好、本身容灾度高的IDC,这样可以做到对于源站的高效回源访问,中心节点一般选择多线BGP网络。

流量调度系统(GSLB)

刚才说了,用户请求上了CDN的资源,首先会指向一个边缘节点,那究竟选择哪一个边缘节点呢?这就需要流量调度系统(Global Server Load Balance,简称GSLB)了。GSLB实现了在互联网上不同地域的服务器间的流量调配,保证使用最佳的服务器服务离自己最近的客户,从而确保访问质量。

GSLB系统分为三大部分:采集/计算、调度、DNS系统。

简单的说,可以理解为下面三个步骤:

  1. 通过监控得到的节点链路质量数据、以及用户访问情况
  2. 将监控数据作为输入,通过调度算法,得出CDN节点 X 用户(地域+运营商)的质量分数矩阵
  3. 将质量分数矩阵转换为域名解析系统的配置,重新加载配置

这三个步骤就会形成了一次迭代过程,GSLB系统就通过不断的迭代不断的优化流量的调度。不过,在不同维度上面进行考量,迭代的周期也是不一样的。如果是考虑服务的可用性,采集/计算是需要实时、不间断进行的,因此迭代的周期也会较短,在秒级别或者分钟级别;如果是在可用性基本一致的情况下,选择链路最好的节点(用户<->边缘、边缘<->上层),则可以使用较长周期的观测数据,例如小时级别或者天级别,用以考量某个链路的网络稳定性(因为有时稳定性要比带宽、性能要重要,而稳定性又需要较长时间才能判断出来),然后再进行流量的调整。

除了通过算法进行自动调度,GSLB同样需要支持手动的配置,这同样是由于业务需求,例如需要中国用户访问位于中国的源站、欧洲用户访问位于美国的源站(虽然可能欧洲用户到中国的链路更好)。

具体三大部分的介绍,可以再看下我之前写的两篇文章: [GSLB调研一] 和 [GSLB调研二]

业务系统

有了缓存系统和流量调度系统,理论上整个用户经由GSLB决定CDN节点、CDN节点再去刷新资源进行缓存并返回给用户的流程就已经跑通了。不过,还是需要有一个业务系统,能够用户或者管理员能否方便的对CDN的配置、缓存等进行操作。

业务系统按照这些功能可以分为两个子系统:

  • 域名管理系统
  • 缓存管理系统

域名管理系统

域名管理,就是当接入CDN客户时,需要将客户的需求,变为缓存系统的配置,比如Squid中的 ACL 、 refresh_pattern 等。一般来说,CDN厂商要求客户提供以下信息:

  • 域名相关
    • 缓存的URL列表
    • 源站IP或者域名
    • 日常带宽数据
  • 源服务器信息
    • 源服务器数量、所处运营商
    • 提供服务的端口
  • 安全相关
    • 是否有防火墙(如果有,需要添加CDN的IP至白名单)
    • 源服务器的最大连接数
    • Referer限制
    • UA限制
  • 缓存策略
    • 缓存资源的类型

    • 过期策略
      • 通过cache-control:max-age
      • 通过Expires
  • 资源相关
    • 单个最大资源大小
    • 平均大小
    • 缓存资源整体大小

另外,有时客户也会有一些特殊的需求。比如我们之前遇到的:

客户有i0.a.com/1.jpg、 i1.a.com/1.jpg 两个需要缓存的URL,但是在CDN系统中只需要当做一份数据来存储。

或者,客户的URL都会有用时间戳当做请求参数,例如 a.com/1.jpg?t=1435432196,需要CDN把不同时间戳的资源都当做一份数据来存储。

其它方面,不同的CDN服务商也会提供更细化的功能,例如又拍云的回源策略,就做得很细致:

缓存操作系统

客户将域名上线至CDN系统之后,虽然本身可以依靠资源上的Cache-control或者Expires进行缓存过期自动获取最新资源,但是出于一些业务需求(时效性较强的活动页面、上线新版式、线上bug处理等),仍然需要人工进行统一对CDN上的资源进行操作。

操作的方式一般来说,分为『刷新』和『预取』。

『刷新』就是指直接将CDN上的指定资源的状态设置为过期,这样当有用户请求该资源的时候,CDN节点就会去源站或者上一层CDN获取最新的资源。刷新操作,又可以分为URL刷新和目录刷新。URL刷新就是用户直接提交需要刷新的URL,缓存操作系统去刷新这个URL;目录刷新要稍微复杂一些,用户提交的是一个URL前缀,缓存操作系统需要将所有包含这个前缀的所有URL都进行刷新。

对于原生的缓存系统来说,缓存的存储形式都是 key-value ,没有一种我们直观感受到的URL路径的树形结构,因此并不直接支持刷新目录的功能,需要对原有系统进行二次开发。

一种比较简单的做法是:通过CDN缓存系统的访问日志,分析出 目录 -> URL列表 的对应关系,保存在专门的刷新系统。当用户请求目录刷新时,刷新系统就可以将对应的URL走原有的URL刷新流程,完成目录刷新,这是我们目前的解决方案。这种方案的特点是:实现比较简单,但是能够刷新的URL都得是用户访问过的才行,另外统计出 目录 -> URL列表 会有一定的延时。

另外一种做法是通过修改CDN缓存系统,在其中增加数据结构来之后次目录刷新。比较详细的介绍目录刷新机制的是阿里CDN的技术分享《 阿里云CDN高性能Cache系统架构之道 》,主要思想是将需要刷新的目录通过Hash表以及字典树(Tire)进行保存,当有用户请求时,就可以判断出该URL是否符合某一个刷新目录,对比两者的时间戳,再决定是否将该资源进行回源。原理图如下:

这种做法的主要特点是技术门槛比较高,平均性能较高,但是每次用户请求都需要判断是否命中了目录刷新,将性能的损失分摊到了每次请求。

『预取』则是在刷新的基础上,当资源已经判断过期的情况下,再去自动获取一次最新资源存储至CDN节点,这样的好处就是用户访问资源的时候,不会出现CDN回源的情况,减少用户这次访问的响应时间。

PS:在接客户的时候,的确会碰到个别2B客户提出一些奇葩需求,例如说要缓存html文件,或者请求参数本来可以当做版本号让CDN自动抓取新资源,客户仍要求缓存不带请求参数的URL,然后自己手动刷新缓存…… 毕竟本身客户的水平就是参差不齐,另外CDN市场的客户也是需要服务提供商来教育的。

数据报表系统

客户已经将业务接入到CDN了,一方面需要让客户能够查看到接入站点的运行情况,另一方面服务商也需要根据数据向客户收费,因此还需要一个数据报表系统。

因为原始数据以及统计的数据量都比较大,另外也需要一定的实时性(最多不能超过5分钟),并且由于CDN业务的特性,节点是分布在各个地域和运营商的,所以整个数据报表系统也是有一定的技术难度的。数据处理的流程包括了:

  • 数据本地采集
  • 数据上报
  • 数据落地(持久化)
  • 数据解析、清洗、格式化
  • 数据预处理
  • 数据实时统计、历史统计
  • 数据展现

数据内容方面,一般则至少包括:

  • 流量
  • 带宽(最细粒度时间区间内的最大流量)
  • HTTP返回码统计
  • 缓存Hit数/Miss数(用于计算不同时间区间的命中率/回源率)
  • 服务器地域信息

有了这些数据,就能够向客户展现比较丰富的图表了。此外,如果数据粒度可以细化到原来数据(访问日志)的话,那还可以提供更高级的功能,例如:日志分析/下载、全国用户来源统计等等。

以下是我们报表系统的部分截图:

流量带宽

访问量/回源率

HTTP返回码统计