全站 CDN 的选择和配置经验分享

Website Aug 14, 2021

修订记录

  • 2021.08.30 - 建议腾讯云+分区回源方案
  • 2021.08.24 - 建议分区解析方案
  • 2021.08.14 - 初稿完成

现在是 2021 年了,原则上讲不管到哪里的线路都应该四通八达了,而且速度都应该很快才对。我的个人服务器在北京,之前由于家里用 Singtel 的宽带,到大陆的各个机房特别友好,也就想当然认为小破站不需要 CDN。直到后来换了 StarHub 的宽带,连中国的速度简直是一个惨不忍睹,日常延迟基本上在 400ms,丢包 41.7%。在某天上传 1.8MB 的文件花了 30 分钟失败 N 次都还没成功之后,下定决心整顿下网络速度。

网站优化,对于中国大陆的站长来说无非就两种。1. 域名不备案主机在国外,需要优化国内的速度。2. 主机在国内,需要优化国外的速度。

首先我放结论,如果是不想备案并且服务器在海外的,对于小站长来说基本上不要考虑优化了。CloudFlare 容易抽风,其他的线路总归有几个省市访问速度很慢,基本上只能考虑备案放在境内。财大气粗的站长当我没说了,大家八仙过海各显神通。

针对第二种情况,这的确是一个很小众的需求,毕竟大部分建站在大陆的人,目标受众也都是大陆人,优不优化的无所谓,在联通移动电信基建工作这么优秀的今天,哪怕是一个单节点云主机,全国访问延迟都在 30ms 附近。

方案选择

这个需求一定要上 CDN 才能解决吗?那显然不是的,有条件的话海外也开一台主机,做好数据同步之后,域名 DNS 分区解析就行了。再说回 CDN,市面上可选的 CDN 其实就那么几家,国外的有 CloudFlare,KeyCDN 等等之类的,国内有 BAT 云,又拍云 (upyun),七牛云。

需要强调的一点是,由于各家 CDN 技术水平不一,不可以武断的下 CDN 就是强/会减速这种结论。比如有些 CDN 由于优化不到位,导致回源的节点是随机的,甚至同一次访问中不同的 js/css 回源节点都不是同一个。后果就是很多原本应该复用的东西没有得到复用,比如 DNS 缓存,HTTP/SSL 握手缓存,h2 连接复用。实际使用的体验就是每个页面都很卡(除非重复访问单个页面),缓存像是压根不存在似的。甚至不如直接访问源站,毕竟要刷新的内容很少,大部分都可以复用和缓存。有些 CDN 优化的就很棒,比如腾讯云,同样的静态页面,腾讯云加载只要 20ms,而七牛光卡 TTFB 就 5 秒起步。

另外还有一点值得注意,CDN 会不可避免的带来回源速度慢的问题,而且最少会有一次转发。CDN 工作流程可参考如下:

你的浏览器 > CDN 边缘节点 (L3) > 若干 L2 L1 节点 > 源站服务器

如果你和源站在同一地区,那么一次转发即可,速度尚可。如果你和源站跨地区甚至跨国家,TTFB 会很高,具体多高要看是谁家的 CDN。不过第二次访问的总加载速度就相当快了,100ms 内没什么问题。

境外 CDN 提供商

国外的没什么好说的,CloudFlare 优势就是极其方便,域名托管过去之后一键上 CDN,但是劣势就是没有大陆节点,部分省市能不能访问全凭运气。其他的也不用说,基本上都是没有大陆节点,单这一条就刷下了所有的境外服务商,因为我不能容忍大陆用户因为 CDN 而访问速度变得更慢。CloudFlare 早期好像有一些奇技淫巧可以用大陆节点加速,但是这毕竟不符合用户协议还是算了。

说到这里其实需求就很明确了,有几个硬性要求有几个可选的,首先是硬性要求:

  1. 上 CDN 后,国内用户访问速度不能比现有差(主机在阿里云北京节点)
  2. 可以提供境外的加速节点
  3. 计价灵活

可选的需求有

  1. 可以自己上传 HTTPS 证书
  2. 可自定义不同站点不同后缀文件的缓存策略
  3. 可尝鲜 HTTP2,HTTP3 等等新特性
  4. 支持分区解析回源
  5. 提供丰富的 API 自动化操作

又拍云

又拍云是我从 2014 年就在用的服务,但是这家公司在 18 年左右整个策略变了,专注国内节点。又拍云的优势是自研的技术,CDN 性能似乎真的快一些。劣势首先是对海外支持不好,我记得 15 年刚用的时候,海外节点至少 10-20 个,加上那个时候只需要 CDN 分发博客的图片,upyun 虽然简陋但也够用就一直用着了。直到 2019 年左右,突然发现 CDN 图片宕机了,检查了一下发现节点解析到了德国,用 ping.chinaz.com 的工具测试了一下,果然境外只有两个 IP 了。当时我还发工单去问,请问你们是暂时调整还是永久的了,对方也没说实话。还有就是又拍云的官网控制台日常打不开,后来放弃了 upyun 改用七牛云。

在打算做全站 CDN 之后,我考虑过再用用又拍云,但是在新建 CDN 服务的时候,看到赫然一行大字「若您有海外地区加速需求,可创建 海外加速 服务,详情」,如果开通海外加速的话,有一个月最低消费 399 人民币的限制。这显然不符合硬性要求第三条,计费不够灵活。其实也从侧面反映出来又拍云不太关注海外业务了,这也就是为什么文件分发服务的海外节点只有两个。

七牛云

七牛云,要说他其实也没好到哪里去,租的各个公司的 CDN 服务,文件管理做的一言难尽,文件储存用的是 key/value 类型,不像传统的文件夹管理机制。但是七牛云好在提供海外的节点,速度是差强人意但是也不是不能用。所以 2020 年的时候下定决心迁到七牛云了,无缝迁移很容易也没什么好说的。

最终我还是选择了腾讯云。七牛云计价灵活并且提供海外节点。而且中国大陆的 CDN 服务商肯定有大陆的加速节点,虽然不见得比直接访问源站快多少,但至少不会慢很多对吧。

七牛云整个体验下来就是,这是一个工程师主导的公司。产品文档写的毫无逻辑,产品介绍还不如大一学生大创比赛写的好,外行人看了只会觉得 CDN 深不可测,内行人看完心里只有卧槽这写的什么 jb 玩意儿。甚至他们把和用户的聊天记录复制粘贴出来写成产品文档,一个字都不带改。不光产品文档不行,用户 UI 也处处是坑,就是不能好好说人话,我来随便摘一段:

第一次用的时候完全不知道这到底在说什么。只能凭经验,哦我好像需要一个另外的域名指到源站 IP 地址。跌跌撞撞最后才看懂原来这相当于是覆写 HOST 文件的配置。功能做的很好用,可惜文档写成一坨翔。要不是后来因为自签名证书回源失败顿悟了,我根本没有任何文档可以知道这个功能的正确用法。

关于「动态加速」和「图片小文件」可以多说两句,动态加速几乎每个请求都会回源站,部分 js 文件可以智能识别出来直接 HIT。这是我抓日志下来自己分析出来的,而七牛文档声称是「动态加速每次请求都会回源」。这两种模式还有一个区别就是图片小文件模式可以自定义不同文件类型的缓存时间,当然了服务器节点也会略微不同。

七牛还有个缺点就是修改配置的时候,只能一个一个改,而且改一次要等 10 分钟生效后才能改下一个,而且有很大几率一直卡住卡几个小时甚至一两天都有。针对这点可以提工单人工介入,晚上周末也有人值班。

七牛云也有挺多优势的,包括不限于强大的 API 操作,还算低的计价。但是最终迫于它超高的 TTFB,我转投了 DNS 分区源站解析,再后来转投了腾讯云 CDN。

转投腾讯云之后,我才知道原来 CDN 可以这么快。在用七牛云的时候,最开始源站在北京,我在境外访问每次都要等 5-7 秒时间才开始出首字节。我天真的以为是跨境回源就这么慢,于是把域名迁移到 DNSPod 做分区解析,单独给海外配置 CDN 并且回海外 VPS 的源(因为七牛不支持分地区回不同的源)。结果 TTFB 还是得有 300ms,我直接访问也不过才 3ms。万分无奈之后,试了下腾讯云 CDN,腾讯云居然支持境内境外使用不同的回源策略,完全符合我的需求,尝试一下之后,发现页面加载速度在 20ms 左右,就是他了。

阿里云

阿里云的控制面板感觉很山寨的样子,用的时候摸不着头脑,好像功能也有点简陋。但是基本功能和腾讯云差不多,等后面一起说了。

在速度方面,阿里云虽然我没用过,但是七牛海外是基于阿里云的,表现应该差不多。

腾讯云

腾讯云我在很早就试过了,当时因为他节点数量比阿里云多,ping 延迟也高很多,很多地区是 100-200ms,46 个节点平均延迟比七牛高了 12ms。当时以为这会拖慢 CDN 的性能,毕竟节点多了之后回源也会多,没有倒霉蛋帮忙预热页面大家的访问体验都会很差。所以最开始就没用腾讯云,但是实测之后发现,ping 延迟低并不代表速度快,腾讯云他就是真的快。

关于配置方面,腾讯云的精细度可以说是非常高。源站可以定义不同优先级,甚至境内境外分区解析,防盗链甚至可以设置过滤指定 UA,缓存设置也更精细(其实七牛云也都有类似功能,只不过腾讯云的界面做的友好,加上恰到好处的说明文档,用户用的时候知道自己在做什么)。腾讯云免费每个月送 10GB 的 CDN 境内流量,相信对于绝大多数人都算得上可以白嫖了。

关于分区解析可以吐槽一句,当时为了分区解析,把域名迁移到 DNSPod 的时候,忘记关闭 DNSSEC,结果 dig 命令没办法拿到解析地址。但是很神奇的是国内的 DNS 比如 114.114.114.114,119.29.29.29,225.6.6.6 都可以正常解析,我一度以为 DNSPod 又不支持海外了。结果搜了一圈 SERVFAIL 关键字,最后发现和 DNSSEC 有关。下面的话引用自 Namesilo:

When you manage DS records, the domain will stop resolving correctly if your name servers are not configured correctly with the associated DNSSEC resource records.

意思就是说,一旦你打开 DS 功能,如果你的 DNS 服务商不支持 DNSSEC,那么你的域名将不能正常解析。解决方案就是删除 DS 记录。114 和腾讯阿里 DNS 之所以解析没问题,是因为他们默认不支持 DNSSEC。

当然了我最后又回去了 Cloudflare DNS,并且又打开了 DNSSEC,因为腾讯云 CDN 支持分区解析回源,不再需要 DNS 层面做分区解析。

CDN 其他的配置就没什么好说的了,只要把回源问题解决掉其他都很容易。目前我所有站点的配置就是全站 CDN,图片用对象存储托管,配置单独的 CDN 域名加载图片和公共脚本。

各大 CDN 总结

国内流量 元/GB 国外流量 元/GB 请求计费 元/万次 免费额度 API 更新 SSL 备注
阿里云 0.24 0.46-1.3 分区域 静 0.05 / 动 0.15 不支持
腾讯云 CDN 0.21 0.31-0.9 分区域 不支持 静态加速
腾讯云 ECDN 1 限免(需审核) 0.2 0.25GB/万次 不支持 全站动态加速
又拍云 0.29 0.39-0.89 静 0.02 / 动 0.06 因人而异 不支持 海外动态加速最低消费每月 399 元
七牛云 0.28 0.58 前 5 万次免费之后 0.19 10GB HTTP 支持

又拍云的国外节点可以认为基本不存在,只适合大陆用户。如果你愿意在网站下面挂个 logo 参与推广计划,给博客做个图床还是很不错的。

七牛云属于那种样样做的都不精,但是最后体验还行的那种。加速节点租用的阿里云,国内流量价格平均 3 毛钱 1GB,海外大概 5 毛钱 1GB,定价方面其实算便宜的了,看个人怎么取舍。文档写的像狗屎,但是提供 API 做任何操作,只是修改配置偶尔抽风,总在「处理中」。他有个最大的缺点就是跨境回源的时候 TTFB 过长,再就是缓存方面做的不行,HIT 缓存的情况下还有 300ms TTFB。

阿里云虽然操作面板很山寨,但是他的质量应该是信得过的,如果你是个大客户,阿里云是个至少不坏的选择。

腾讯云的可玩性很高,丰富的可配置选项,操作面板上有恰到好处的说明文字,对新手也很友好。腾讯云支持 CDN 分区解析回源,这是一个痛点,并且腾讯云的缓存表现是真的不错,指哪打哪几乎没有延迟。不过腾讯云的动态加速超过免费额度之后 1 块钱 1GB 是这几个里面最贵的,给论坛/博客/API 动态加速比较贵。另外海外加速需要额外审核,价格暂时限免。

运维技巧

我摸索出来一个比较好的用法是:如果你的网站是用 Nginx+静态文件部署的,比如 react 编译好的静态文件,或者 hugo 等等类似的,甚至任何一个文件夹直接部署成网站,都建议采用「静态加速」模式,缓存策略选择跟随源站,好处就是以后迁移 CDN 的时候不用在新的服务商那里重新配置一遍,因为配置文件全在自己服务器。后面我分享一下我的静态资源缓存配置。

# Expire rules for static content

# Manifest
location ~* \.(?:manifest|plist)$ {
    expires -1;
    # access_log logs/static.log;
}

# Text
location ~* \.(?:css|js|html|htm|shtml|json|xml|pac)$ {
    expires 1d;
    access_log off;
    add_header Cache-Control "public";
}

# Media
location ~* \.(?:jpg|jpeg|gif|png|ico|webp|svg|mp3|aac|wav|flac|mp4|mkv|flv)$ {
    expires 7d;
    access_log off;
    add_header Cache-Control "public";
}

# Document
location ~* \.(?:txt|csv|doc|docx|xls|xlsx|ppt|pptx|pdf)$ {
    expires 7d;
    access_log off;
    add_header Cache-Control "public";
}

# Download
location ~* \.(?:exe|deb|ipa|apk|psd|zip|gz|tar|jar|rar|7z|gzip|dmg)$ {
    expires 7d;
    access_log off;
    add_header Cache-Control "public";
}

把上述文件保存到 expire/static.conf,用的时候直接 include 进来。

server {

    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name static.pupboss.com;

    root /srv/web/com/pupboss/static;
    index index.html;

    include ssl/ecc_meltdownresearch_com.conf;

    location / {
        try_files $uri $uri/ =404;
    }

    include expire/static.conf;
}

针对动态站点,比如 nodejs 网站,或者 php 网站,无特殊需求建议直接采用「动态加速」模式,CDN 自己会做好动静分离缓存。如果很想折腾的话,比如某些 php 网站提供伪静态的配置,也可以采用「静态模式」,然后手动在 CDN 上面配置上述的静态策略,不同服务商的配置格式不一样请参考文档。但是切记在缓存策略里面加一条配置 /admin 目录(你的后台管理目录)的缓存时间为 0 否则你的网站后台会登录不进去。强行给动态网站做缓存后果就是页面更新不及时,所以缓存策略不要太激进,确定不会变的网站无所谓了,博客类可以设置为 1 天,论坛类建议不要缓存。

线路选择

用七牛云的时候,如果你的源站在中国大陆,100% 会遇到回源 TTFB 超过 5 秒的情况,不管是你自己的服务器当源站还是七牛云对象存储当源站。带来的体验就是初次下载某资源 TTFB 要等将近 7 秒,这是完全不能接受的。于是我尝试把储存源站放在其他区域,得到如下发现:

  1. 中国的机房在境内表现优异,各个省市都很快。但是亚洲国家丢包感人,比如日本韩国新加坡印度,总有一个时段丢包丢到不能用,欧洲美国倒是都不错。美洲 200ms,欧洲澳洲 300ms,亚洲 200-400ms 不等
  2. 新加坡机房在全球中规中矩,中国丢包严重,亚洲其他国家 80ms,欧洲 300ms,美洲 200ms,澳洲 250ms
  3. 美西的线路到全球表现优异,基本不丢包,美国境内 10-50ms,欧洲 140ms,亚洲 100-200ms,澳洲 150ms

中国机房的表现是最让我惊愕的,2015 年的时候中国到新加坡就要绕道日本绕道美国 NTT 线路,现在 2021 年了居然还没好,而且中国到亚洲的线路需要绕路美国这恐怕是国际玩笑。

所以关于服务器地区配置的结论就是,如果你愿意搞两台机器分区解析,中国境内一台保证境内用户速度,新加坡/日本/韩国放一台保证全球的速度。如果你想用一个源站或者一个源站配合 CDN,放在美西是个不错的选择,至少 Zenlayer 线路是这样。

Tags

Jie Li

🚘 On-road / 📉 US Stock / 💻 Full Stack Engineer / ®️ ENTJ