1, CDN架构简介
CDN全称为Content Distribution Network, 内容分发网络。CDN可以极大地提升网站的访问速度,提升网站性能,给网站加速。
在无CDN架构中,用户直接使用浏览器请求服务器上的资源。如果访客量大,服务器可能无法响应这么多的请求。同时,如果服务器在国外,那么国内用户访问起来就非常慢。
CDN节点服务器部署在用户和网站服务器之间。用户访问的时候,可以直接从离自己距离最近、速度最快的服务器上请求网站资源。如果CDN服务器上已经缓存了用户请求的内容,就会直接从CDN服务器上把内容传递给访客;如果没有缓存或者缓存过期,才会再由CDN节点服务器从源站取回内容。这样,就能够提升访客的访问速度,且提升服务器响应性能。一个最简单的CDN网络可以用下图来表示。
本文将部署在Ubuntu 20.04 LTS 64bit操作系统中,其他操作系统的部署流程没有太大差异。本教程中,CDN节点服务器的测试环境为单核,1 GB内存的VPS (实测在512 MB内存的VPS上也可以完美运行). 本文假设源站域名为qing.su, 源站IP为88.88.88.88. 在开始部署CDN之前,请按照上一篇教程(https://www.homedt.cn/2406.html)的第二部分内容安装好Traffic Server程序。下面的内容将直接从配置开始。
接下来各部分中,第2, 3节是必须设置的;第4-9节是可选的;第10节CDN服务器上的DNS解析与第11节均衡负载,仅在源站有多个服务器的情况下才需要设置。
现在,开始教程。
2, 设置映射规则
访客使用域名访问了CDN节点之后,如果CDN节点没有储存访客请求的内容,就需要从源站获取内容。因此,需要设置映射规则 (mapping rules),使得CDN能够正确地与源站通讯。这里,我们有两个方案:正向代理与反向代理。尽管两者均可完美实现CDN功能,但是为了安全性考虑,如果您只用一层CDN, 那么可以只用反向代理。如果您使用多层CDN, 那么外层(用户直接访问的节点)应该使用反向代理,内层(所有不和用户发生直接交互的节点)应该使用正向代理。
(1) 使用正向代理 (Forward Proxy)
Apache Traffic Server是一个全功能的代理/缓存/CDN程序,支持正反双向代理与透明代理。因此,我们可以使用正向代理模式来配置CDN与源站交互(你可以把正向代理的CDN服务器理解为一台带缓存的Windows远程桌面,你登录到远程桌面上访问源站)。正向代理与反向代理均可以实现高速缓存,在性能上没有差异。
配置records.config文件,设置下面几条记录的值:
CONFIG proxy.config.reverse_proxy.enabled INT 0 CONFIG proxy.config.url_remap.remap_required INT 0 CONFIG proxy.config.url_remap.pristine_host_hdr INT 1
这样,无需配置mapping rules,服务器即可通过正向代理的方式访问源站。设置为正向代理模式后,服务器目前还不知道我们源站的IP地址。这里有三种方法:1, 我们可以直接更改服务器本地的/etc/hosts文件指明源站IP (最简单且速度最快); 2, 可以按照本文第10节的方法指明源站IP; 3, 可以自己搭建DNS服务器,设置DNS记录。多个源站直接添加多条记录即可。如果您的一个源站有多台服务器,请参考本文第10节与第11节的设置。
出于安全性的考虑,不要将正向代理节点部署在CDN架构的最外层节点。
(2) 使用反向代理 (Reverse Proxy)
CDN服务商的外层节点一般都使用反向代理的方式。
首先,编辑records.config文件,开启反代模式:
CONFIG proxy.config.reverse_proxy.enabled INT 1 CONFIG proxy.config.url_remap.remap_required INT 1 CONFIG proxy.config.url_remap.pristine_host_hdr INT 1
然后我们就可以配置映射规则了。这里我们需要再次强调一下,如果您的源站完全被CDN覆盖,那么不建议您在源站上开启SSL, 因为这完全没有必要,反而会额外增加源站负载。您只需要在CDN服务器上配置SSL即可。
编辑文件remap.config, 如果源站没有开启SSL, 添加下面的内容:
redirect http://qing.su/ https://qing.su/ map https://qing.su/ http://88.88.88.88:80/
如果源站开启了SSL, 则添加下面的内容:
redirect http://qing.su/ https://qing.su/ map https://qing.su/ https://88.88.88.88:443/
请注意,IP地址之后的端口号不可省略。多个源站则添加多条记录即可。
如果您的一个源站有多台后端服务器,请参考本文第10节与第11节的设置。
3, 设置缓存规则
缓存了源站的文件,才能让访客的访问速度得到提升,否则如果只反代而不缓存,那么访客的每次请求都要回源,访问速度反而会下降。
编辑文件records.config, 添加下面的内容:
CONFIG proxy.config.http.cache.http INT 1 CONFIG proxy.config.http.cache.ignore_client_cc_max_age INT 1 CONFIG proxy.config.http.normalize_ae_gzip INT 1 CONFIG proxy.config.http.cache.cache_responses_to_cookies INT 1 CONFIG proxy.config.http.cache.cache_urls_that_look_dynamic INT 1 CONFIG proxy.config.http.cache.when_to_revalidate INT 0 CONFIG proxy.config.http.cache.required_headers INT 2 CONFIG proxy.config.http.cache.ignore_client_no_cache INT 1
这里我们设置了基本的缓存属性,比如忽略客户端no cache请求,开启gzip压缩,等等。接下来,对各文件类型设置缓存期限。编辑文件cache.config,添加下面的行:
url_regex=.* suffix=js ttl-in-cache=5d url_regex=.* suffix=css ttl-in-cache=5d url_regex=.* suffix=html ttl-in-cache=5d url_regex=.* suffix=xml ttl-in-cache=5d url_regex=.* suffix=ts ttl-in-cache=5d url_regex=.* suffix=jpeg ttl-in-cache=5d url_regex=.* suffix=mp4 ttl-in-cache=5d url_regex=.* suffix=zip ttl-in-cache=5d url_regex=.* suffix=gif ttl-in-cache=5d url_regex=.* suffix=jpg ttl-in-cache=5d url_regex=.* suffix=swf ttl-in-cache=5d url_regex=.* suffix=m3u8 ttl-in-cache=5d url_regex=.* scheme=https ttl-in-cache=1h url_regex=.* scheme=http ttl-in-cache=1h
您可以按照自己的需求自行设置。
对于频繁请求的小文件,可以将其储存于系统内存中,加快读取速度。编辑文件records.config, 设置下面的内容:
CONFIG proxy.config.cache.ram_cache.size INT 200M CONFIG proxy.config.cache.ram_cache_cutoff INT 4194304 CONFIG proxy.config.cache.ram_cache.compress INT 1
上面三行中,我们在内存中设置了200MB空间用来存储文件大小在4MB以内的小文件,且启用了内存压缩。
4, 缓存储存空间及缓存分区
在上一节中,我们设置了缓存规则。这一节我们设置缓存大小,并开启缓存分区。
编辑文件storage.config, 设置缓存大小。比如,我这里设置为2 GB:
var/trafficserver 2048M
接下来我们设置缓存分区。Traffic Server支持将储存空间划分为不同大小的分区,然后可以给不同的源站设置不同的缓存大小。同时,不同的缓存分区可以并行储存读取,加快缓存读取速度。
编辑文件volume.config, 我们这里将缓存分为6个分区:
volume=1 scheme=http size=5% volume=2 scheme=http size=5% volume=3 scheme=http size=15% volume=4 scheme=http size=15% volume=5 scheme=http size=25% volume=6 scheme=http size=35%
然后编辑hosting.config文件,为域名指派不同的缓存分区:
domain=qing.su volume=1,2,3,4,5,6 domain=hostloc.com volume=1,2,3,4
5, 安装SSL证书,开启OCSP装订与HTTP/2
访客直接与CDN服务器发生交互,因此我们需要在CDN服务器上安装SSL证书。
首先,我们要开启SSL支持。编辑records.config, 找到含有server_ports的这一行,修改成如下:
CONFIG proxy.config.http.server_ports STRING 80 443:proto=http2;http:ssl
在这个设置中,我们开启了SSL, 并为https开启了HTTP/2传输。可以用浏览器查看是否启用成功,如下图绿框里的h2协议码。
如果您使用了最新版本的Traffic Server (10.0), 您还可以设置QUIC-HTTP/3. 由于本文仍然用的是老版本的Traffic Server, 无法设置QUIC-HTTP/3, 因此就不做过多介绍了,具体的设置方法请参考官方文档。
指明SSL证书存放的文件夹:
CONFIG proxy.config.ssl.server.cert.path STRING /etc/trafficserver/ssl/ CONFIG proxy.config.ssl.server.private_key.path STRING /etc/trafficserver/ssl/
然后我们把证书存放在/etc/trafficserver/ssl/文件夹中。假设私钥文件为qing.su.key, 证书文件为qing.su.crt, CA中间链证书文件为qing.su.ca-certs.crt, 那么我们编辑ssl_multicert.config, 添加下面的行:
dest_ip=88.88.88.88 ssl_cert_name=qing.su.crt ssl_key_name=qing.su.key ssl_ca_name=qing.su.ca-certs.crt
就设置好了SSL证书。
如果您使用Let’s Encrypt证书,那么我建议您开启OCSP装订,原因是该证书CA的OCSP证书被墙了,会导致国内访问速度慢。开启OCSP装订很简单,编辑文件records.config, 设置如下的行:
CONFIG proxy.config.ssl.ocsp.enabled INT 1
这样就开启了OCSP装订。OCSP缓存周期等参数可以保持默认。
6, 自定义HTTP Header
在Apache Traffic Server中,我们可以方便地更改响应的Headers. 这里需要用到header_rewrite插件。
首先,编辑plugin.config文件,加载header_rewrite插件:
header_rewrite.so /etc/trafficserver/header_rewrite.config
这里,我们定义了header_rewrite插件的配置文件名,header_rewrite.config. 编辑该文件,按您的个人需求来修改,比如:
cond %{SEND_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:server} =ATS/8.0.8 set-header server "shc-cdn-server"
这里,我们将header中包含ATS/8.0.8字符串的server字段值修改为”shc-cdn-server”. 可以用浏览器查看修改的headers.
该插件具体的语法可以参考官方文档。
7, 配置VIA Header
Via Header是中间代理添加的信头标识,具体介绍可以看这里。Traffic Server支持via header, 如果我们开启了Via Header功能,则Traffic Server会在所有请求的应答中添加一个字符串,用来提供CDN服务器处理该请求时的状态信息,比如缓存是否命中等。通过解读Via信头,我们可以用来调试CDN服务器。
开启Via信头很简单。编辑records.config, 修改下面的行:
CONFIG proxy.config.http.insert_request_via_str INT 1 CONFIG proxy.config.http.insert_response_via_str INT 2
如果将第二行的值设置为3,则会给出更详细的24位VIA信头;如果设置为2,则会给出6位信头。一般来说,默认的6位Via信头已经能够提供足够多的信息了。开启了Via信头之后,如何分析呢?我们举下面几个例子。请注意图中绿框框起来的部分。
如上图,绿框框起来的部分就是Via header值。图中的值为[cHs f ]. Traffic Server包含了traffic_via命令行工具,可以帮助我们解码。执行:
traffic_via '[cHs f ]'
即可看到解码后的含义:
这里可以看到,该页面的请求命中了缓存,因此无需从源站获取内容。
再来看这张图,
Via header值为[cMsSfW], 解码后得到下图的解释:
可以看到,该请求没有命中缓存,因此我们的CDN服务器从源站获取了请求的内容反馈给访客,并且将该内容写入了缓存。
还有一种常见的情况,如下图:
Via header值为[cSsSfU]. 解码后得到下图的解释:
可以看出,该请求命中了缓存,但是缓存已过期。因此,CDN服务器从源站获取了请求的内容,反馈给访客,并且更新了CDN服务器上的缓存。
如果您开启了24位长Via信头,那么您需要使用这个在线工具来解码:http://trafficserver.apache.org/tools/via. 系统中提供的traffic_via命令行工具在解码24位Via header时会报错。
一般来说,Via header是在调试、配置CDN时使用的工具。当您的CDN服务器完全搭建好后,建议您关闭Via header功能。
8, 日志与状态监测
Traffic Server生成的日志在/usr/local/var/log/trafficserver目录。可以使用tail -f实施监测日志变化:
tail -f /usr/local/var/log/trafficserver/manager.log tail -f /usr/local/var/log/trafficserver/diags.log tail -f /usr/local/var/log/trafficserver/error.log
Traffic Server提供了traffic_logstats工具,让我们更直观地了解CDN服务器的工作状态。比如我们源站的IP为88.88.88.88, 那么我们可以执行:
traffic_logstats -o 88.88.88.88:443
命令执行的结果如下。系统会生成非常详细的日志报告,包含所有的服务器运行状态(命中情况,错误分析,DNS解析命中,等等……您可以自行尝试)。如下图。
上图中,我们的CDN服务器收到的请求中有200多万次命中了,一千多次没有命中,还有900次错误(都是压力测试的时候产生的)。
另外,也可以使用traffic_top命令,使用类似于Linux Top指令一样的界面查看CDN服务器运行状态。执行:
traffic_top
效果如下图所示:
9, 惊群效应与拥塞控制
做CDN一般都需要考虑避免惊群效应 (Thundering Herd Effect) 的出现,尤其是节点数较多的情况,否则很可能在某些时候给源站产生非常大的突发请求,导致源站宕机。
Traffic Server提供的运作机制可以避免惊群的出现。编辑records.config文件,添加下面的行:
CONFIG proxy.config.cache.enable_read_while_writer INT 1 CONFIG proxy.config.http.background_fill_active_timeout INT 0 CONFIG proxy.config.http.background_fill_completed_threshold FLOAT 0.000000 CONFIG proxy.config.cache.max_doc_size INT 0 CONFIG proxy.config.cache.read_while_writer.max_retries INT 10 CONFIG proxy.config.cache.read_while_writer_retry.delay INT 50 CONFIG proxy.config.http.cache.max_open_read_retries INT 5 CONFIG proxy.config.http.cache.open_read_retry_time INT 10
还可以开启服务器的拥塞控制,更好地应对高流量并发:
CONFIG proxy.config.http.congestion_control.enabled INT 1
我们使用loader.io对一台1核1GB内存的轻量VPS搭建的CDN节点进行了压力测试,持续并发2000个访客并不间断地向服务器发送请求(一分钟之内共发送了38万个请求),全部成功。此时CDN节点服务器的负载仅在40%左右。由于达到了VPS服务商的网络带宽与iops限制,因此无法进一步提升并发量来测试了。(测试链接:https://bit.ly/32xD1nI)因此,使用这单个1核1GB VPS一天处理几万个UV还是很轻松的。
10, CDN服务器上的DNS解析
Traffic Server提供了HostDB功能,我们可以将其理解为仅供Traffic Server使用的/etc/hosts文件。区别于/etc/hosts文件的地方是可以使用很多参数来控制HostDB, 实现服务器上的DNS缓存与解析。
HostDB的主要作用是缓存源站域名的DNS请求。实际上,如果您的源站只有一台服务器,那么如果你按照我上面的配置来操作的话并不需要用域名的方式来请求源站,因此无需使用HostDB功能。仅当您的源站有多台服务器的时候,才需要使用HostDB功能。
编辑records.config文件,指明一个hostdb文件的位置:
CONFIG proxy.config.hostdb.host_file.path STRING /etc/trafficserver/hostdb.conf
然后按照hosts文件的格式编辑hostdb.conf文件(IP hostname一行一条记录)。
我们还可以设置轮询:
CONFIG proxy.config.hostdb.strict_round_robin INT 1
其他设置,比如TTL, 缓存更新频率,轮询频率等设置,请参考官方文档,这里不做过多介绍了。
11, 均衡负载
Traffic Server是功能全面的CDN程序,支持设置均衡负载(Load Balancing). 简而言之,如果您的源站本身就有多台服务器,那么可以通过配置CDN, 实现回源时均衡负载,这样不会给单一源站带来过大的压力。
配置均衡负载有三种方法: 1, 是使用Balancer插件; 2, 使用父级代理的方式; 3, 使用上一节介绍的HostDB。我们这里仅介绍使用第二种方法。使用插件的方法较简单,但是由于可以被父级代理的功能完全代替,该插件将在未来版本的Traffic Server中被淘汰,因此我这里就不做介绍了,如果感兴趣可以自行查看。
我们假设qing.su的源站有三个IP, 77.77.77.77, 88.88.88.88, 99.99.99.99. 为了实现均衡负载,在配置映射规则(第2节)时,我们需要用hostname而不是IP地址的方式指明源站地址。因此,在remap.config中,我们可以这样添加规则:
map https://qing.su https://origin.qing.su
这里,origin.qing.su是一个不存在的,我们随便分配的子域名。然后,编辑records.config, 开启父级缓存:
CONFIG proxy.config.http.parent_proxy_routing_enable INT 1
最后,在parents.config文件中指明源站IP以及均衡负载的IP响应规则:
dest_domain=origin.qing.su parent="77.77.77.77:443|2.0, 88.88.88.88:443|3.0, 99.99.99.99:443|5.0" parent_is_proxy=false round_robin=strict
在上面这个例子中,我们使用这三个IP地址开启了轮询均衡负载,并且分配了权重(20%, 30%, 50%)。其他的配置规则可以参考官方文档。
到这里,一台CDN服务器就基本设置完毕了。等您把所有节点全部设置完毕后,您需要设置域名的DNS解析。如果您不需要商用,则直接在DNS服务商处将您的域名按照线路解析到不同的CDN节点上即可,或者设置轮询(Round Robin)。若您需要商用,建议您自行搭建Geo DNS, 以便用户设置解析。以后我们也会介绍Geo DNS的部署。这里,我们直接使用现成的免费DNS服务器(国内推荐阿里云,国外推荐Route53)就可以了。
综上,我们使用Traffic Server搭建好了CDN网络。我们详细说明了映射规则与缓存规则的配置,并介绍了缓存分区、修改信头、配置SSL、状态检测、均衡负载、拥塞控制与处理惊群等具体细节。Traffic Server拥有完整详细的产品手册,如果您想了解更多,请点击参考官方文档。
其他的功能,比如CDN分层,众多插件的使用,Lua编程模块等等,这里就不做太多介绍了。另外,如果您需要商用Traffic Server CDN, 你可以考虑安装开源免费的主控端Traffic Control. Traffic Control用于控制Traffic Server搭建的CDN服务器集群,拥有完整的图形界面,用户管理,DNS, 签发SSL, 均衡负载,等等一切你能想到的CDN服务商需要的功能,您可以自行研究。
原文链接为https://qing.su/article/traffic-server-cdn-cluster.html