温馨提示:
本文所述内容具有依赖性,可能因软硬条件不同而与预期有所差异,故请以实际为准,仅供参考。
一、背景
Google Cloud CDN(内容交付网络)使用 Google 的 全球分布式边缘点 来缓存与用户接近的 HTTP(S)负载平衡内容。在 Google 网络边缘缓存内容可以更快地向用户提供内容传输,同时降低服务成本。
这篇文章将介绍如何利用 GCE(Google Compute Engine) 建立一个 Anycast 网络,想要实现这个功能,就需要使用 Cross-Region Load Balancing(跨地区的负载均衡),此功能就相当于一个 HTTP(S) 的反向代理,所以只能针对 HTTP/HTTPS 请求进行负载均衡。
二、概述
GCE 上所实现的这个功能是基于第七层的网络代理,所以其拓扑图是这样的:
用户 —> 边缘服务器 —> 实例
- 用户到边缘服务器之间的连接:使用 HTTP 或 HTTPS;如果是 HTTPS 连接,那么 TLS 加密过程是在边缘服务器上实现。
- 边缘服务器到实例的连接:使用 HTTP 或 HTTPS 连接,之前的网络是走的 Google 的专线。
不论配置了几个位置的实例,边缘服务器都是使用 Google 全部的边缘服务器。
启用这个功能后,就会得到另一个 Anycast 的 IP 地址,这是个独享的 IP 地址。
需要注意的是,Google CDN 仅适用于 Google 负载平衡器和云存储,这意味着如果不在GCP(Google Cloud Platform)上托管应用程序,那么将无法使用他们的 CDN,换句话说,就是不支持外部来源。 简单。
所以本文的实例是在 GCP 上运行,并使用负载平衡器(LB)来使用 Google CDN,你猜对了,Google CDN 也不能将 VM 作为原点,它只能在负载均衡器上启用。
三、配置
大致步骤:
建立实例 —> 建立实例组 —> 建立健康检查 —> 建立负载平衡器 —> 启用 CDN。
现已支持单个实例开启 CDN,
不需要
创建多个实例、多个实例组。创建实例组时选择非托管式实例组
即可。
如需更详细的实例配置详情,请参考《配置启用 Google Cloud CDN 实例详解》
1、建立实例
首先,需要前往到 GCE 后台,建立至少两个不同地区的实例,我专门为测试 Anycast 功能建立了三个新的实例:
每个地区也可以建立多个实例以提高可用性,而我只给每个地区建立了一个实例,分别为 gce-jp、gce-us 和 gce-sg。
2、建立实例组
实例组用于负载平衡设置,为 LB 的后端服务。需要给 每个地区 的实例建立一个实例组,三个地区 VM 就需要创建三个实例组,分别为 us-group、jp-group 和 sg-group:
需要注意的是,实例组配置页面中位置里的 “多地区(Multi-zone)” 是指同一个地区(Region)的不同可用区域(Zone),而不是多个不同的地区。
我只给每个地区建立了一个实例,所以我只需要选择 “单地区(Single-zone)”,因为
VM 虚拟机已经建好了,所以组类型选择非托管实例组。
3、建立健康检查
行状况检查对于负载均衡器确定 VM 是否健康至关重要,很多人无法成功开启 Google CDN 都是在这一步失败的。
当虚拟机无法响应查询时,负载均衡器会标记不健康并停止发送流量也就是说,负载均衡通过健康状态检查来判断流量走向,因此需要先创建健康检查:
检查支持 HTTP、HTTPS、TCP、SSL、HTTP/2,如果没有指定
主机 HTTP 标头
(即 Host,点请求路径下面的展开即可看到),那么将会检查默认站点,举个例子:假设服务器 IP 是 1.1.1.1,网站域名是 vircloud.net。
如果没有指定 主机 HTTP 标头
,那么检查的地址将是:http://1.1.1.1
,网站则是服务器配置中的第一个网站或者标记 default
的网站;如果指定 主机 HTTP 标头
为 vircloud.net
,那么检查的地址将是:http://vircloud.net
。
显然后者才是我们需要的检查目标,虽然可能不指定也可能可以检测成功,但不确定性较大,谁知道会不会哪天新建了一个 default 网站呢?所以建议标头设置为网站域名
。
4、建立负载均衡
接下来就需要建立负载均衡的规则了,需要选择 “HTTP(S) 负载平衡” 来实现 Anycast 的功能:
后端配置中,创建后端服务,把这三个实例组都添加到 “后端” 中,然后指定运行状态检查为上一步创建的检查(相当于监控功能,此例中名为 test ),当主机达到某个设定好的条件后能实现切换,会话粘性设为无:
主机和路径规则 保持默认即可:
前端配置中,可以单配或者一起配置 HTTP 及 HTTPS,也可以选择静态或者动态 IP,根据需要了,如果需要 HTTPS,那么还需要指定一个证书:
检查一下:
点击创建(名称不要忘记输了,本例中设为 all),成功后回到负载平衡就可以看到刚创建的平衡器了,点击可以看到如下界面,其中的 IP 地址就是 Anycast IP 了:
5、开启 CDN
在 CDN 下新建,来源选择刚创建的 负载平衡 即可:
至此,Google CDN 基本上就成功启用了。
6、Nginx 的配置
如果你只是单纯的使用 CDN,可以在另外的 VM 开启反代,以下的配置只是为了方便调试,实际使用并不需要。
在这两个主机上都安装 Nginx,然后稍微改动默认的配置文件:增加两个 Header,然后 Reload:
add_header X-Tlo-Hostname $hostname always;
add_header Cache-Control "max-age=36000, public";
7、检测是否可用
在测试 Anycast 之前,先测试这两个主机是否存在问题。为了方便阅读,我将 curl 的 IP 地址换为主机名,并省略两个主机都相同的 Header 字段
$ curl -I gce-us
HTTP/1.1 200 OK
...
ETag: "5a682aae-11"
X-Tlo-Hostname: gce-us
...
$ curl -I gce-jp
HTTP/1.1 200 OK
...
ETag: "5a682abd-12"
X-Tlo-Hostname: gce-jp
...
$ curl -I gce-sg
HTTP/1.1 200 OK
...
ETag: "5a682934-15"
X-Tlo-Hostname: gce-sg
...
可以看到这三个主机都没有什么问题,我们再测试 Anycast IP,新加坡主机访问:
$ curl -I anycast-ip
HTTP/1.1 200 OK
…
ETag: "5a682934-15"
X-Tlo-Hostname: gce-sg
Cache-Control: max-age=36000, public
Accept-Ranges: bytes
Via: 1.1 google
可以看到,这是 gce-sg 主机响应的,然后我们使用另一个在美国的主机继续测试这个 Anycast IP:
$ curl -I anycast-ip
HTTP/1.1 200 OK
…
ETag: "5a682aae-11"
X-Tlo-Hostname: gce-us
Cache-Control: max-age=36000, public
Accept-Ranges: bytes
Via: 1.1 google
此时就是 gce-us 主机响应的,是因为客户端离这个服务器更近,日本主机也是一样的:
$ curl -I anycast-ip
HTTP/1.1 200 OK
…
ETag: "5a682abd-12"
X-Tlo-Hostname: gce-jp
Cache-Control: max-age=36000, public
Accept-Ranges: bytes
Via: 1.1 google
当通过 Anycast IP 访问时,就可以看到 HTTP Header 中的 Via: 1.1 google 字段。
8、排错
如果发现访问 Google CDN Anycast IP 回应 502 Bad Gateway(no-referrer),如下:
$ curl -I anycast-ip
HTTP/1.1 502 Bad Gateway
Content-Type: text/html; charset=UTF-8
Referrer-Policy: no-referrer
Content-Length: 332
Date: Wed, 24 Jan 2018 12:22:40 GMT
那么首先应该考虑是不是运行状况设的有问题(VM 已经在上面测试过是正常的了),查看负载平衡器监控,发现几个 VM 都被判定不良:
Nginx 访问日志也报错:
那么很明显就是运行状况检查有问题了,回到运行状况检查一下,需要注意的地方在代理协议这边:
无特殊需求正确的应该设置为 无,设置好后 Nginx 日志就正常了:
检查也正常了:
再访问 Anycast IP 是不是正常了?
当然了,造成此问题的原因还有可能是防火墙、端口等,但相信你已经先排查一遍了。
额外提一句,运行状况检查生效可能会有延迟,且只有源站 VM 回应检查状态码为 200 时,运行状况检查才会认为源站是健康的,在开启 https 时要特别注意。
运行状况检查来源 IP 为:35.191.0.0/24,CDN 来源 IP 为:130.211.0.0/16,检查 User-Agent 为: GoogleHC/1.0,如果有开启相关防火墙记得放行。
9、速度测试
① Ping 测试
Ping 测试发现速度很快,看来反代的操作是放在 Google 的边缘服务器上了,速度真的很 Google 啊:
中国的速度那更是一流的快,Google 有香港的边缘节点,所以基本上是直接走的香港节点(只有部分 IP 段是完全直连的),比原本的连接台湾可用区快不少:
② HTTP GET 测试
在开启 CDN 功能之前,负载均衡器是不会对任何内容缓存的,所以会发现 Connect 的速度很快,但是 TTFB 延迟还是有不少:
可以预测,如果启用了 HTTPS 功能,其 TLS 所需要的等待时间也会很短,TTFB 时间不变,总时长不会延长太多。
③ 开启 CDN 后进行 HTTP GET 测试
当将 CDN 开启后,负载均衡器就会自动地对静态资源做缓存了,当缓存命中后会显示 Age 字段,这个字段是表示自缓存命中了,后面的数字代表这是多少秒之前缓存的内容。
curl anycast-ip -I
HTTP/1.1 200 OK
…
Via: 1.1 google
Age: 10
经过多次执行这个指令,会发现有一定几率 Age 字段消失,这可能是流量指到了同一个地区的不同可用区上。但总之,是缓存命中率不高,即使之前曾访问过了:
多次运行测试确保有缓存之后,发现速度似乎并没有太多明显的提升。能够明显的看出改善的是:巴黎和阿姆斯特丹的 TTFB 延迟从 200ms 减少到了 100ms,然而还是不尽人意。可能的原因是:Google 并没有将内容缓存到离访客最近的边缘节点上,而是别的节点上。
四、统计与日志
开启了 Load Balancing 后,就会自动在 Google Cloud Platform 下记录一些信息了。
1、实时流量查看
在网页后台的 Network,Load balancing,advanced menu 的 Backend service 下,可以查看实时的流量情况:
2、延迟日志
在网页后台的 Stackdriver,Trace 下,可以看到延迟日志:
这里的延迟包含了网络延迟和服务器响应延迟。
五、总结
GCE 所能实现的 Anycast 功能,只能通过 HTTP 代理(第七层)的方式实现,所以只能代理 HTTP 请求,其他功能(如 DNS)无法实现。所以很多功能受限于负载均衡器的功能(比如证书和 HTTP2 都需要在负载均衡器上配置),然而由于 TLS 加解密过程是在边缘服务器上实现,而且其本身也带有 CDN 功能,所以会比单纯的 Anycast(比如基于 IP 层,或是 TCP/UDP 层)的更快一些。
1、价格
前五个 Rules $18/月,流量费用相比 GCE 不变,已经被缓存的内容的流量有一点优惠。
2、节点
- 亚洲:香港、台湾、孟买、东京、新加坡、悉尼等 19 个
- 美洲、纽约、旧金山、西雅图、迈阿密、波哥大等 31 个;
- 欧洲:柏林、都柏林、米兰、伦敦、巴黎、华沙等 30 个
- 非洲:约翰内斯堡 1 个
3、对比
① Cloudflare
通过使用 Cloudflare 所提供的服务也能实现 Anycast,也是基于第七层的,即将也能实现 Cross-Region Load Balancing 的功能。虽然它还不能根据主机的 CPU 占用率去调整权重(毕竟它拿不到这些数据),却有强大的 Page Rules 功能以及 WAF 功能。
CloudFlare 并不提供独立 IP 地址,不过这不是什么大问题。
由于它属于第三方服务,不受服务提供商的限制,于是就可以给多种不同的服务提供商去做 Anycast 功能;而且无论服务商是否支持,都能够使用。
连接速度上,GCE 的在中国连接速度有明显的优势,目前部分地区已完全连不上 Cloudflare 了。
4、释疑
① 什么是 Anycast ?
Anycast 能够让多个主机使用一个 IP 地址,当用户连接这个 IP 地址的时候,连接到的只是这多个主机中的其中之一,通常会选择最快的线路,能有效的降低延迟,所以很多 DNS/CDN 提供商都使用了 Anycast。
② 区域的概念
刚接触云服务的人可能不理解可用区域的概念,可以参考 AWS 的这篇文章 来理解。简单点说,地区这个概念就是指离得很远的地区(比如城市之间,如北京和上海),所有在北京的服务器都算北京地区,所有在上海的服务器都算上海地区。但是为了能达到更高的可用性,通常还会在同一个地区设立多个数据中心,也就是可用区域。这些可用区域虽在一个地区中,其之间的距离可能相隔几十甚至几百公里,但这些可用区域之间的距离和不同地区之间的距离相比起来要小得多,所以这些可用区域之间的网络延迟也很低。
设立多个可用区域的意义是:可以能加更高的可用性(主要是为了避免外界因素:比如说火灾等),虽然是异地分布,但是可用区域之间的距离并不远,所以网络延迟可以忽略。
③ 什么是 TTFB ?
TTFB (Time To First Byte),是最初的网络请求被发起到从服务器接收到第一个字节这段时间,它包含了 TCP连接时间,发送HTTP请求时间和获得响应消息第一个字节的时间。
参考文章:
1、利用 GCE 建立一个 Anycast 网络,超快的香港节点,Google Cloud CDN
2、Cloud CDN Location
3、Cloud CDN Pricing
4、How to Implement Google Cloud CDN?
5、配置启用 Google Cloud CDN 实例详解
iPhone 11_2_2微信 6.6.1来自 加利福尼亚 的大神
我觉得你的文章写的很好,很有帮助。但是我不知道如何给我实际使用的一个Wordpress的网站进行这样的配置。你能帮我一下吗?
Mac OS X 10_13_2Chrome 63.0.3239.132来自 加利福尼亚 的大神
你的文章很有帮助。但是我不知道怎么给我的Wordpress配备谷歌的CDN。 我用的是GCP里Bitnami的Wordpress虚拟机。你能帮我一下吗?
谢谢。
配置方法跟文章中 三、配置 步骤是一样的,参照着设置就行了。
iPhone 11_2_2Safari 604.1来自 加利福尼亚 的大神
谢谢回复。
我按照您的方法领创了两个VM,一个亚洲一个欧洲。我还有个美国的,里面装的是wordpress。另两个里面什么都没有。然后设置了load balance
我用360测速后,发现只有一个ip节点,是美国的。我检查backend日志时发现,两个新VM都不健康。亚洲的网络流到了美国的那个实例群。
这是怎么回事?请email我如果您需要我截图。
再次感谢
VM 需要一模一样的配置,也就是说美国的装 wordpress,亚洲欧洲也要装 wordpress,不然就会被运行健康状态检查认为这两个是故障的,进而自动导向美国,除此之外,这两个也都要可以正常访问,你再试试。
iPhone 11_2_2Safari 604.1来自 加利福尼亚 的大神
那我两个wordpress跟我主要的那个不就不一样了吗。我是不是还要手动把另两个的Wordpress内容给同步一下?
内容可以不一样,可以这样做,开一个最低配的 GCE,然后反代缓存,再添加这层 CDN。
其实我感觉难点在于负载均衡器的配置。
更新了健康度问题,你再看看。
Windows 7Chrome 69.0.3497.100来自 香港 的大神
我现在也遇到了一样的问题,就是我的网站的服务器在美国,我想在欧洲国家建立实例,我需要让这两个服务器数据完全一样吗?如果要完全一样那么我是不是一定要做服务器同步?你说的“内容可以不一样,可以这样做,开一个最低配的 GCE,然后反代缓存,再添加这层 CDN。”怎么反代缓存?
不要求服务器数据完全一样,但至少网站内容是一致的,不然也就没有 CDN 的意义。
反代缓存,具体可以搜索一下 Nginx 反向代理
Windows 7Chrome 76.0.3809.132来自 河北 的大神
写的非常好。
还有点想不明白的是,创建多个实例后,比如美国一个,香港一个,欧洲一个,代码和数据库是放在那里个实例了啊?数据库是自动在3个实例之间同步了吗?
其实完全没必要那么复杂,现在 GCP 已经支持一个 VM 就开启 CDN,参见我后来写的文章《配置启用 Google Cloud CDN 实例详解》 https://vircloud.net/exp/enable-gcp-cdn.html
Windows 10Chrome 63.0.3239.132来自 澳大利亚 的大神
写的太好了,我gogole了三天终于发现你这篇文章了,
但是还是看的不太懂,我的wordpress装在地域在欧洲的VM上,我想在澳洲开启CDN.那么按照你的文章我应该在洲洲再建立一个VM.那么我更新网站的的时候是不是还要进去二个网站的后台更新?(比如说我写一篇文章,我是不是在这个VM上更新完了,然后再去另外一个VM再次手动更新?)
能不能出个视频?
现在不需要一个区域建一个 VM,可以参考我的另一篇文章《配置启用 Google Cloud CDN 实例详解》
Windows 10Chrome 63.0.3239.132来自 澳大利亚 的大神
[root@ec2-euro g4223305]# curl -I https://tapehair.com.au
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sun, 01 Mar 2020 22:59:25 GMT
Content-Type: text/html; charset=UTF-8
Location: https://www.tapehair.com.au/
Via: 1.1 google
Transfer-Encoding: chunked
Alt-Svc: clear
我的为什么没有cache?是不是还差点配置文件?
出现这个说明就已经启用成功了。至于缓存的话,看你网站的配置
Windows 10Chrome 63.0.3239.132来自 澳大利亚 的大神
请问怎么在Nginx上加上如下header?修改哪个文件?
add_header X-Tlo-Hostname $hostname always;
add_header Cache-Control "max-age=36000, public";
在你网站配置那一段, server {...} 这中间任意位置都可以
Windows 10Chrome 63.0.3239.132来自 澳大利亚 的大神
经过检验,用google could 宝塔面板 LNMP还需要加以下代码,以下来自google帮助
“如果您使用的是 nginx Web 服务器软件,请修改 nginx.conf 配置文件以启用压缩功能。此文件的位置取决于 nginx 的安装位置。在许多 Linux 发行版中,该文件存储在 /etc/nginx/nginx.conf。要允许 nginx 压缩功能与 HTTP(S) 负载平衡一起运行,请将以下两行添加到 nginx.conf 的 http 部分:
gzip_proxied any;
gzip_vary on;
”
这是二次压缩的,影响不太大
Google Cloud CDN-如何开启配置使用? - 顾小南的技术博客