分享CDN内容分发网络实战技巧

分享CDN内容分发网络实战技巧

给大家分享下关于 CDN 的东西,总共分为 2个大部分:原理、详解。

分享CDN内容分发网络实战技巧

首先说一下 CDN 的基本原理部分,主要分 4 块来描述:CDN 的由来、调度是怎么做的、缓存是什么、关于安全。

什么是CDN?

这是一个做过 CDN 之后的拓扑图,里面有几个概念需要明确一下:

Origin Server: 源站,也就是做 CDN 之前的客户真正的服务器;

User: 访问者,也就是要访问网站的网民;

Edge Server: CDN 的服务器,不单只“边缘服务器”,这个之后细说;s/(单)只/指/;

Last Mile: 最后一公里,也就是网民到他所访问到的 CDN 服务器之间的路径。

我们平时所使用的DNS服务器,一般称之为LDNS,在解析一个域名的时候,一般有两个情况,一种是域名在DNS上有记录,另一种情况是没有记录,两种情况的处理流程不一样。

当你访问163这个域名时,如果LDNS上有缓存记录,那它会直接将IP地址直接给你。如果没有缓存记录,它将会一步步向后面的服务器做请求,然后将所有数据进行汇总交给最终的客户。

当你访问163这个地址时,实际上如果本身没有内容的话,它要去后面拿数据,这个过程术语叫递归,它首先会向全球13个根域服务器请求,问com域名在哪,然后根域服务器作出回答,一步步往下,这个过程较复杂,如果大家感兴趣可去查相关资料,在这就不一一赘述。

DNS调度

分享CDN内容分发网络实战技巧

肯定很多人好奇是如何进行调度和进行定位的?

其实也是通过LDNS的具体地址来进行的,比如,看图,假设你是一个广东电信客户,那你所使用的DNS服务器去做递归的时会访问到某一个CDN厂商的GRB,全球的一个调度系统,他就能看到来自于哪个LDNS。假设如果用户和LDNS使用同一个区域的服务器,他就会间接认为用户也是广东电信的。

再举个例子,比如说北京联通的用户,它使用DNS地址,一般自动给它分配的是北京联通的服务器,这个服务器去做递归的时候,调度服务器就会看到这个请求是来自北京联通的LDNS服务器,就会给它分配一个北京联通的服务器地址,然后让来自北京联通的用户直接访问北京联通的服务器地址,这样来实现精准的区域性调度。

从这个调度理论上看,我们可以发现一个问题,就是假设用户所使用的LDNS地址和你是同一个区域,那么这个时候我们的调度才有可能是正确的。但是举个例子来说,如果你是北京联通的用户,可是使用的是广东电信的LDNS的话,就会让GRB系统误以为你是广东电信的客户,这样就会错误的调度过去。

之前有一次我在小区里上网,由于我的路由器有问题,我设了202.106.0.20的北京联通的DNS服务器地址,后来出差去深圳,访问比较大的网站发现比较慢,经过分析,才发现原来我设的DNS地址是北京联通的,而我在广东和深圳使用的网络都是电信接入的,但是分配给我的是北京联通的地址,那我用电信的线路访问北京联通的地址,势必就会很慢。

因为刚才讲到的DNS调度机制存在一定问题,所以在某些场合下我们会使用第二种调度机制,叫HTTP的调度。

了解http协议的人知道,在http协议中有一个叫302跳转的功能,它的实现并不是说你访问一个URL,然后马上吐给你想要的数据,而是吐给你一个302返回信令,这个信令头部会告诉你,有一个location目标,这个location就是告诉你下一步将要怎么做,而具体调度是通过location来实现的。

即便我所使用的DNS和我不在一个区域,但当我访问http server的时,这个server是由CDN公司提供的。客户访问server的时,虽说通过DNS方式无法拿到客户的真正IP地址,但是如果你访问的是http server,他一定能直接看到客户的真实IP,利用这种方法可以进行调度的纠偏,可以直接返回给你一个302,然后location里面携带一个真正离你最近的CDN server。

这种调度方式,优势是准确,但是也存在弊端,它需要有一次TCP的三次握手建连,他不像DNS那样直接请求一个数据包过去给一个反馈就OK了,他需要一次TCP的三次握手建连。

第二个是你如何访问到http的服务器?如果你之前是通过DNS调度过去的,实际上前边的那个DNS也是省不了,在国内是没有办法做anycast的,也就是没有办法来直接访问一个众所周知的大的IP来进行,所以,一般情况下都是通过DNS来进行第一次调度,然后用http来进行第二次纠偏。这种情况下大家可以想象,如果你下载一个大文件,比如说电影,但你访问的是一个页面小元素,比如说这个图片只有几k,那么,实际上你调度的时间就已占用了很大的成分。实际上,这种302调度是一种磨刀不误砍柴工的方案,如果你后面有很多工作要做,比如要下载一个电影时间会很长,那你调度准确,即使花一点时间调度也是值得的。但是如果你后续访问一下就完了,那么你这样调度就没有太大意义。

除了DNS调度和http的302调度以外,其实还有一种调度方式,叫http DNS调度,它的原理是通过一个正常的http请求,发一个get的请求,然后再请求里面以参数的形式携带一个我要解析的域名,然后服务器那边去通过数据库查询,查询之后又通过http的正常响应,把这个你要请求的IP通过http协议给你,这种协议有一个特点就是必须双端都支持,因为这种模式是非标准的。没有任何一个RFC文档说,你的客户端或者你的操作系统天生就支持这种机制。这有点类似是一种API的这种方式,那如果要实现的话就必须双端都支持。

一般,第三种调度的应用场景是在手机的APP端,在APP软件里面,你要访问某些东西很有可能被运营商劫持等问题,这个劫持问题后面还有很大的篇幅去讲。那为了避免这种劫持,可能会用到这种http DNS的调度方式。既然APP的程序都是你自己写的,所以说实现这么简单一个API的借口是很容易的。

CDN的接入

分享CDN内容分发网络实战技巧

可能会有人问,你讲了这么多DNS和具体CDN的调度有什么关系呢?

因为在讲你获得一个具体的DNS域名地址的时,他给你的就是一个IP地址。那在没有CDN之前,他给你的IP地址就是在原来没做CDN时的原始服务器地址。但如果你做过CDN的话,你会发现最终拿到的这个IP地址是CDN的节点,而并不是真正的原始服务器。

我们通常说的拿到一个IP地址,这实际上是DNS的A记录。DNS里面有很多不同的记录,比如像A记录负责给你一个IP地址;比如像CNAME记录给你的是一个域名的别名。当然还有很多其他记录,比如TXT的记录、MX记录等等。这个跟CDN无关,这里就不细说了,有兴趣去查一下DNS相关的文档。

上图就是一个很明显的CDN介入后的效果图。linux里有一个命令叫dig,它可直接把要访问域名的具体的解析情况列出来。那么,通过这个图可看出,当你要访问www.163.com时,他最终虽给出的是一个IP地址,但实际上,它经过了两次CNAME记录。第一次CNAEM记录就是我们之前说得CDN的GRB,他拿到了这个数据,就可以间接知道你的这个LOCODNS是从哪里来的,然后间接给你进行一个定位。以这个图为例,他实际上第一跳是跳到网速地址,第二跳是分配了网速的一个平台,这个平台又分开其他的IP给最终的客户。

Cache系统——缓存系统

分享CDN内容分发网络实战技巧

除DNS调度以外,在CDN里还有一个非常大的重头戏就是Cache系统,也就是缓存系统。它用于把那些可以缓存住的东西,缓存到CDN的边缘节点,这样当第二个人去访问同一节点,同一具体电影或MP3时就不用再经过CDN链路回到真正的源站去拿数据,而是由边缘节点直接给数据。

在Cache系统里囊括了很多的技术,比如,用空间换时间的这种高效的数据结构和算法,多级缓存以热度来区分,前端是SSD后面是机械硬盘等等。很多的细节就不说了,如感兴趣的可之后交流。

对于Cache系统来说,有两种不同的工作状态。第一种工作状态就是所谓的命中(hit),第二种就是没有命中(miss)。如果命中了,直接通过检索找到磁盘或内存上的数据,把这个数据直接吐给客户,而不是从后面去拿数据。这样的话就起到一个很完美的加速效果。

第二种是在miss时,其实,miss的时候跟hit唯一的区别就是,当我发现我的本机上没有这个资源,我会去我的upstream(上游)去拿数据。拿完这个数据,除了第一时间给客户,同时还会在硬盘上缓存一份。如果这个硬盘空间满了,会通过一系列置换方法,把最老的数据、最冷的数据替换出去。

提到了upstream,不是原始服务器,原因是因为当客户访问到CDN节点的时,他发现上面没有数据,并不是直接从原始服务器上去拿,而是经过他的另一个CDN节点,然后通过middlemell的方式去进行一些数据传输。然后upstream这一层,从原始服务器拿数据,通过一系列的加速手段,快速的把数据投递给我们的边缘节点,再把这个数据给最终客户。在过程当中upstream和downstream这两层都会把数据缓存一份。通过这种树形结构,比如说多个边缘节点,然后汇总到一个或者几个副层结点,这样的话可以逐渐的实现流量的收敛。

提到Cache的具体技术,我相信这里的很多朋友都是同行业的,有人会说其实这没有什么难的,你只要有网络、有运维人员就可以了。其实我并不这样认为,因为你如果想把它做好的话其实很难,比如,我列出的很多技术你有没有在考虑?

举几个例子来说,你有没有做网卡的的多队列和CPU的亲和性绑定?你有没有做磁盘的调度算法改进?另外,你存储的时候还是用还是?等等都是有讲究的。包括内核的调优包括架构和CPU的绑定,CPU的多级缓存的使用,然后你的处理你使用,还是用标准的的这种机制。再比如说编译的程序时使用的去编译还是用英特尔的,然后你再做很多的调用。比如说一个很简单的字符串拷贝,那你是用,你还是用汇编去写,你还是用什么方式等等很多细节。

关于高性能这一块,还有很多的研究,如大家感兴趣的话,可以之后跟我进行进一步的沟通。我想表达的一个观点就是说,看上去做CDN很简单,入门确实也简单,但是要真正想做好很难。

安全问题

在没有做CDN之前你的网站很有可能会遭受到各种各样的攻击。那么攻击一般分成两种,第一种叫蛮力型攻击,量大的让你的带宽无法抗住最后导致拒绝服务,另外一种是技巧性攻击。

作为CDN来讲,就已经将你的原始服务器的IP进行了隐藏。这样当一个攻击者去访问你的域名的时,实际上访问的并不是你真正的服务器。当他访问的是CDN的节点,就没有办法把CDN的节点打倒,换句话说,即使有能力把CDN的比如10g的节点或者是40g的大节点全部打倒,但由于CDN天然的分布式的部署方式,他也很难在同一时间之内迅速的把全国所有CDN的边缘节点全都打瘫。

另外,还有一种攻击是针对你的DNS地址的。如果你的GRB瘫了的话,会导致整个调度系统失灵。如果调动系统失灵,即使你的CDN的Cache server还是能够正常接受请求,但由于流量调度不了。因此,你需要在DNS层做很多防护机制,比如说用高性能的DNS或用分布式的部署方式等等。

技巧型攻击不需要很大的流量,就可以把你的原针打倒或是让你的网页出现错误的情况。比如说,像注入、挂马甚至说更严重的会直接拖走你的数据库等等。那么作为CDN来说,有很多厂商实际上已经开始具备这样的技巧性的防护能力了,比如说WAF(Web Application Fierwall),就是应用层防火墙,他可以直接去解析你的请求内容,分析内容是否有恶意性,如有恶意性的话去进行过滤,报警等一系列措施来保证你的原始服务器的安全。

第二部分主要是针对网络层的优化、架构的优化、Cache的选型还有性能分析等等几个方面,对整个CDN的基础原理作很深入地剖析。

原始的CDN其实是Content Delivery Network这三个词的缩写,也就是内容分发网络。但我认为应该是can do something on Network。CDN的理念是加速,所以,我们就尽一切可能去做各种优化,从一层到七层的优化来实现最终的优化效果。

为什么说一层是优化,实际上也是硬件,你的服务器选型就是一种优化。你是用ssd,还是用saker硬盘,你是该用pce卡,还是应该用ssd。你的CPU应该用至强还是应该用阿童木的等等,都是需要去斟酌。

至于二层,链路层的优化指的就是资源方面。比如机房如何去选择。

三层路由层是指你在middlemell这块真正选路的具体的细节,后面会有一个图来具体讲一下。

四层是指传输层的优化,我们一般的业务全都是TCP,所以说这里面就可以明确的说这里是指TCP的优化。还有一个就是七层也是可以优化的。比如说你强行对内容进行压缩,甚至你改变压缩级别去压缩。

作为CDN来说,基本上我罗列了一下可能会用到的一些技术,大概10个。比如说就近分布、策略性的缓存、传输的优化、链路层的优化、包括内容的预取、合并回源。然后持久连接池、主动压缩,还有当你原始服务器挂了的话你怎么样能够保证让客户看到数据等很多的细节。

路径的优化,实际上,我们可以把它抽象成是一个求最短路径最优解的思路去解决真实的问题。当你从a点到b点需要传输数据的时,往往会经过一个c点,比直接从a到b更快。在互联网里有个三角原理,和地理位置的原理有一定区别的。虽说有一定的相关性,但还是有区别的,有可能从a经过c到b会比a直接到b更快。