全站 CDN 开放测试

几个星期之前本站开始使用了 KeyCDN 作为内容分发和加速,和其它多数 CDN 一样,KeyCDN 也是可以被用于全站 CDN 的。只不过由于 WordPress 自身的一些缺陷,使得全站 CDN 配置起来非常麻烦。

全站 CDN 的好处不言而喻,就是速度快。本站的主机在台湾,亚洲的读者可能没什么大问题,但从欧洲访问过去,最快也至少要 500ms 才能得到内容(第一字节时间,TTFB)。而使用了 CDN 之后,TTFB 会下降到 50ms 以下,必要的 CSS 文件在 500ms 内下载完毕,达到了真正的秒开。

于此同时,之前的一些问题,比如留言之后 CDN 刷新不及时,都已经修复。目前已经没有已知的阻碍正常阅读的使用问题了。想体验一下的同学,可以在左上角目录中选择“使用 CDN”。如果你没有看到这个链接,则说明要么你已经在使用 CDN 了;要么,本站的 CDN 已被墙。

节点分布图可以看出,离大陆最近的节点在香港,除了主机所在地台湾之外,各大主要网络区域都有节点覆盖。也就是说,除了来自台湾的读者可能感受不到 CDN 的优势之外,世界上大多数地区的读者的访问速度都会有提升。

由于 KeyCDN 并不是针对全站 CDN 来设计,它使用起来或多或少还是有些不方便,没有 CloudFlare 那样的完美。但作为一个每月只需要不到一美元的服务,KeyCDN 真是物超所值。继续测试一段时间之后,如果没有太大的问题,站点将全面切换至 CDN 模式,进一步保护主机的安全。

从无到有实现 WordPress 全站 CDN

WordPress 的设计有很多莫名其妙的地方,其中之一就是它的域名设置。WordPress 的每一个站点要设置一个独立的主页(Home)地址,而且只能设置一个。也就是说,即使有两个域名指向同一个博客(比如 a.com 和 b.com),如果博客把主页设置成了 a.com,用户在访问 b.com 的时候,也会被重定向到 a.com。这样造成了 b.com 实际上完全无法访问到。

对于使用 WordPress 的博客主而言,通常一个域名就够了,可能最初 WordPress 的开发人员也是这么想的。但现在的互联网,单一域名已经不足以支撑一个网站了。简单来说,WordPress 配置 CDN 相当麻烦。

CDN,又名内容分发网络,一个把网站内容快速传递给用户的工具。它的工作原理是,预先把内容加载(缓存)到离用户较近的数据中心(通常称为 Edge Server),当用户访问网站时,直接从数据中心读取内容,而不是从源网站(Orginal Server),这样就减少了数据传输的时间。如下图:

一个 CDN 包含多个 Edge Server,如果每个用户都访问离自己较近的 Edge Server,则会比直接访问源网站要快很多。而现在的技术又可以做到当用户访问某一个域名的时候,被自动解析到较近的 Edge Server,用户则完全感受不到差别。

现在做得比较好的 CDN 服务如 CloudFlare。它家提供了一条龙服务,从域名解析到内容分发,一个帐号全搞定。这样做的好处是“傻瓜式”,不需要太多的专业知识就可以配置 CDN;而坏处则是一损俱损,CloudFlare 的服务器经常被墙,一旦被墙了,想脱离 CloudFlare 就重新设置一堆东西,很麻烦。

如果你像我一样不喜欢一键搞定的服务,那我们就来一步一步自己配置全站 CDN 吧。

初始化 CDN 服务

首先,你得有一个 CDN 服务,我用的是 KeyCDN,介绍看这里

初始化(KeyCDN 的术语叫“Zone”)完成之后,一般会得到一个二级域名,比如我的是 leonax-1800.kxcdn.com。然后在自己的域名解析中创建一个 CNAME,指向之前的域名,比如我用的是 www.leonax.net。解析刷新之后,初始化就完成了。

修改链接和资源地址

如上文所说,WordPress 限定了网站的地址,比如本博客设置为“leonax.net”,则所有的资源(JS、CSS 等)和链接都会以“//leonax.net/”开头。即使用户访问了主页“www.leonax.net”,其中的各种资源也会从“leonax.net”加载,这样就达不到 CDN 的效果。于是我们要把页面中所有的“leonax.net”全部替换成“www.leonax.net”。下面有一些方法,可选择用其中的一种或多种组合来达到效果:

修改资源地址

WordPress 提供了 style_loader_src 和 script_loader_src 分别来过滤 JS 和 CSS 的地址,我们要做的是把其中的域名删掉,从而使用相对路径。代码如下:

替换正文中的链接

使用 WordPress 的 the_content 过滤器,可以修改正文内容,具体要改什么,视具体情况而定。注意 WordPress 的短代码(shortcode)解析的优先级为 11,所以下面的代码使用了优先级“8”来避免短代码带来的改动。

Apache 输出全文替换

Apache 提供了 mod_substitute 来对输出内容进行修改。如果你的站点中提供了这项功能,则可以轻松改动网页内容:

mod_pagespeed 域名替换

mod_pagespeed 也提供了类似的域名替换功能,比 mod_substitute 智能的是,mod_pagespeed 可以识别出链接字段,比如 <img src=""> 中的内容,而不像 mod_substitute 那样全局替换:

CDN Pull

有些时候,我们可能需要在 CDN 模式下输出 www.leonax.net,而在访问源站的时候则依然得到 leonax.net。这时就需要对 CDN 发来的请求进行定向输出。一般 CDN 方面会给出一些特殊的信息,比如 KeyCDN 会设置一个特殊的 X-Pull 头,标记这个请求是从 KeyCDN 发来的。于是我们可以对这一类请求做特殊处理(Apache):

CORS

Cross-origin resource sharing,跨来源资源共享,是一个浏览器的特性。简单来说,leonax.net 和 www.leonax.net 是两个域,如果 leonax.net 引用了来自 www.leonax.net 的资源,而 www.leonax.net 没有允许这么做的话,浏览器会主动拒绝加载相应资源的。所以,如果两个域都用了 CDN 的资源,则在 www.leonax.net 中,需要允许 CORS。这一项在 KeyCDN 中默认是开启的,我也就没有多关心。

CDN Purge

CDN 的主要原理是缓存,也就是把网页内容缓存在 Edge Server 中,每次响应用户请求的时候,不必再向源站请求数据。这样就产生了缓存过期的问题。比如博客中有人留言,博客页面更新了之后,CDN 却不知道这件事,依然输出不包含留言的页面,这样就不对了。为了解决这个问题,CDN 通常都会提供一种清除缓存的方式,称为 CDN Purge。 KeyCDN 的做法是发出一个如下的 HTTPS 请求,用于清除一个特定页面的缓存:

CDN 方面搞定了,WordPress 依然成问题,因为我们也不知道页面什么时候更新。研究了一下发现,我可以利用 WP Super Cache,在 Super Cache 的缓存页面被删除的同时,也发送一个请求给 KeyCDN,同时删除那边的缓存,一举两得:

上述的代码会在博文更新、或是有新留言的时候触发,会稍微减慢响应速度,更好的办法应该利用 WordPress 的 wp_schedule_single_event 方法,不过暂时还没有研究。

总结

把上述所有内容串起来,就有了现在的全站 CDN

本站开启 CDN 加速

本站的流量以每个月 10GB 的速度上升,而 Google Cloud 对中国地区的流量收费又比较贵($0.23/GB)。这样下去大有流量费用高过主机的势头,没办法,只能上 CDN 了。

之前一直不用 CDN 的主要原因有两个:

  • 一是没有一个 CDN 可以兼顾国际和国内的流量,一般国内的 CDN 都要求域名备案,国外的 CDN 都没有大陆节点;
  • 二是多数 CDN 服务对自定义 SSL 的收费都比较高,比如 CloudFlare 要收取每个月 $200 的费用。

不过最近发现一个 CDN 服务:KeyCDN

KeyCDN 的模式是按用量收费,$0.04/GB,也就是一美元可以有 25GB 的流量,比 Google Cloud 要便宜多了。没有月租,充多少用多少。新用户还有一个月的试用期,送 25GB 流量,非常吸引人。虽然 KeyCDN 也没有大陆的节点,不过在香港和东京都有,勉强可以接受。另外关键的一点是,它家对自定义 SSL 是免费的,直接上传证书即可,5 分钟内自动配置完成,很方便。

为了解决 CDN 服务可能被墙的困扰,本站默认还是从主站加载。然后会自动侦测 CDN 是否可用,如果可用,则会自动切换成从 CDN 加载的模式。对于本站的读者,您将感受不到任何差别,默默地帮我省了流量而已。

个人博客在国内的访问加速

最近开始研究国内访问的解决方案。

可行的方法无非有两种,一是使用第三方的 DNS 服务器,比如 DNSPod,一个国内的免费 DNS 服务器,提供免费的 DNS 解析、流量监测等服务,通过简单的 6 步设置,就可以把域名的 DNS 解析放到 DNSPod 上,解析速度一般低于 100ms(免费版)。

不过即使有了国内的 DNS 解析,博客的内容依然是在国外的服务器上,访问速度依然慢。于是就有了第二种解决方案,CDN。它的全称是 Content delivery network,工作原理大致是把网站的内容缓存到一些网络节点上,终端用户只需访问离他最近的节点即可,大大地减少了数据包传输的物理距离,从而提升网站的实际访问速度。

听上去 CDN 很美好,但是实际上多数 CDN 服务都是要收费的,而且动辄就是成千上万的年费,个人博客实在负担不起。不过最近貌似有免费的 CDN 服务出来了,比如 Webluker,是一家国内的 CDN 服务商,提供免费的 CDN、DNS 解析等服务。兴冲冲地去试了一把,于是就放弃了。据说还有一家 CoCDN 的,现在连主页都打不开了,情何以堪-_- 国外也有免费的 CDN,它家最近的节点在日本,而 GoDaddy 的服务器在新加坡,从网速上差不了多少,还是不用了吧。

于是目前可行的方案就是在 DNSPod 上注册了一个解析服务,其它什么事情也干不了@@