首先说一下 CDN 的基本原理部分, 主要分 4 块来描述: CDN 的由来, 调度是怎么做的, 缓存是什么, 关于安全.
给大家分享下关于 CDN 的东西, 总共分为 2 个大部分: 原理, 详解.
首先说一下 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 调度
肯定很多人好奇是如何进行调度和进行定位的?
其实也是通过 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 的接入
可能会有人问, 你讲了这么多 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 系统 -- 缓存系统
除 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 更快.
在数据传输的时, 需要去考虑很多综合因素, 目前为止, 包括阿克麦也很难做到完全系统自动化去做链路选择和切换. 在调度的时, 很多公司都有专门的团队管流量调度的. 很多的系统可能只起到支撑和参考的作用, 而真正需要决策的还是人. 因为你需要考虑的元素太多了, 比如说要考虑你的带宽成本, 带宽节点冗余量, 服务器承载能力, 要考虑你的客户敏感度哪些该切哪些不该切等很多细节.
传输层的优化刚才讲到了是 TCP 优化, 在现今的互联网里, TCP 优化是可以带来最直接客户体验感的一种实现方式.
来源: http://network.51cto.com/art/201810/585928.htm