CloudFlare Worker 将你的网站遁于无形

云原生实验室

共 3076字,需浏览 7分钟

 · 2021-11-15


背景知识

1、网站如何工作

当你在浏览器敲下一个域名,浏览器会先去 DNS 查询域名对应的 IP 地址。然后和这个 IP 地址的 443 端口建立 tcp 连接,连接建立后开始进行 HTTPS 握手(针对 HTTP/1、2)。

HTTPS 握手的时候,客户端(你)会将域名信息以 SNI 的形式发送给服务端, 服务端根据这个 SNI 找到相应的网络服务器,然后返回其证书,完成 HTTPS 的五步握手。

2、CDN 是什么

在没有 CDN 的时候,假设网站的服务器跑在某个 IDC 内,那么域名的 DNS 解析应该直接返回这个 IDC 的出口 IP。

当然,返回的 IP 可能不止一个,毕竟这个网站可能存在于多个 IDC,每个 IDC 可能也不止一个网络出口(可能会接入多运营商)。DNS 服务应该根据查询来源的地理信息和运营商信息,选择一个理论上“最近”的 IP 地址返回给客户端。

这样做有一些缺点,一是所有的动态和静态请求都直接触达服务器,压力比较大,成本也比较高。另一个缺点是机房 IP 直接暴露在外,很容易被恶意攻击,如果被恶意 DDoS 机房 IP,那整个机房可能就瘫痪了。

于是人们在客户端和机房之间多加了一层代理,域名不再解析 IDC 的 IP,而是将 IP 解析到这层代理上。这层代理还提供了存储,做了很多静态资源的缓存。这些代理服务器的逻辑也很简单,获取请求后,判断一下是否是静态资源, 如果是静态资源,就返回缓存(此处省略缓存更新策略一万字),否则就把请求转发回源站。

因为逻辑比较简单,成本也就会比较低,所以可以在世界范围内大规模的部署, 因为部署的数量很多,所以也形成了规模效应,对于全球各地的绝大部分用户,总能找到一个离他比较近的代理站。然后人们就把这些分布很广的静态资源缓存服务器称为内容分发网络(Content Delivery Network, CDN)。

使用 CDN 后不但能相对廉价地对广泛区域内的客户实现加速,而且因为客户端不再能拿到你的源站 IP, 对源站也起了很好的保护作用。

考虑到 HTTPS 会对 CNI 和证书做校验,如果你使用了 CDN,那么也得把证书前置到 CDN 服务器上。也就是将请求拆分为两段,用户和 CDN 进行 SSL 握手,CDN 服务器再和你的源站进行 SSL 握手。

3、FaaS 是什么

传统的 webserver 24 小时在后台运行,监听 TCP 端口的 HTTP 请求,处理后再返回。优点是响应很快,缺点是运行成本比较高,无论有没有请求,都 24 小时跑在那里。

为了提高应对请求压力的灵活性,人们提出了 stateless。就是如果 webserver 做成无状态的, 可以理解为其内部不保存任何中间变量,数据都在外部进行持久化存储,其本身只负责业务逻辑。那么 webserver 就可以随时随地的跟随负载压力进行扩缩容。

这个想法再激进一点,如果有一些请求的频率非常低,比如 CI/CD,或者一些 cronjob, 或者流量的峰值效应很明显,绝大部分请求集中在一天的一部分时间。那么人们就认为根本没必要随时随地运行一个服务器在那等着, 完全可以在有请求来的时候,再去启动一个服务,如果请求量很大,就启动更多的服务, 如果一段时间没有请求量,就把服务器关机释放出来。

这种想法就被称为 FaaS(Function as a Service),因为此时的后端服务表现得就像是一个普通函数(而且不是闭包哦), 接受固定的入参,执行一些逻辑,然后返回,销毁。

4、CF Worker 是什么

了解了上述的背景知识,我们就可以来交接 CF Worker 是什么了。

抛开 LB、SSL 等 infra,纯粹从后端的角度来看 webserver,实际上就是整个逻辑链路就是 socket listener、router、handler。listener 获取到请求后,交给 router 分发给 handler 处理,然后返回。

那我们再来回头看看 CDN,CDN 因为会进行 SSL 卸载,所以可以获取 HTTP 的全部负载明文。我们知道 CDN 可以分析 HTTP URL,发现是静态请求就直接返回缓存,发现是动态请求就转发回源站。

那么如果我们在 CDN 里跑一个 FaaS 的体系,让你可以编写一些相对简单的代码, 直接在 CDN 服务器内处理和响应一些动态的请求,而不是把它们转发给源站,这样整个 RTT 的链路不是更少了吗?这样就可以更快地响应请求,也可以进一步为源站减压。

CF worker 就是这么一个运行在 CF CDN 内的 FaaS。它的核心组成就是:router、FaaS(handler)和 KV(存储)。

你把域名托管在 CF 上并启用 CDN 后。就可以为域名创建 worker,编写一些 handler 函数(可以用 JS、Python 等等)。这些 handler 都是无状态的(因为会被随机启停),持久化的数据可以使用外部的 KV 存储。然后再配置上路由,将匹配的流量分发给 worker, worker 内的代码可以选择将能处理的请求直接就地处理,不能处理的再转发会源站处理。

甚至于,如果你的站点内容如果都可以放进 KV 存储的话,你可以根本不需要源站, 而将整个站点都跑在 worker 里。

CF Worker 使用

前期准备:

  1. 一个域名
  2. 一个 cloudflare 账号

首先,进入 CF 控制台的 worker 页面,按照如下顺序进行操作:

  1. 先创建 KV
  2. 再编辑 worker handler,此时不需要 router,因为 cf 会给你创建一个测试用的 dev 地址,可以在调试的时候请求
  3. 最后编辑域名对应的路由,开始负载正式的流量

创建 KV:

KV 创建后,为了能够在 worker 代码中使用,需要被绑定到一个全局常量中:

KV 绑定好后,我们就可以开始编辑代码了

代码的编辑窗口:

本站使用 cf 缓存了所有 graphql query 的请求,以 ttl=1d 的生命周期放于 KV 中。为了方便调试,还增加了 ?force 参数用来强制穿透和刷新缓存。

因为 CF worker 目前仅支持一个源代码文件,所以可以采用将第三方库代码全部粘贴进来的方式使用第三方库。如果你有使用 webpack 等打包工具的话,也可以以 webpack 工程的形式,最终构建出一个单一的 js 文件即可。

示例代码可见:https://github.com/Laisky/cloudflare-workers

总结

最好把 worker 和路由设计成可随时停用的。比如 worker 拦截了某些路由,而后端服务器依然保留这些路由, 也就是说,即使临时把 worker 关停,对外服务也不会受到影响。

原文链接:https://blog.laisky.com/p/cf-worker/


你可能还喜欢

点击下方图片即可阅读

记一次 Kubernetes 中严重的安全问题

云原生是一种信仰 🤘

关注公众号

后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!



点击 "阅读原文" 获取更好的阅读体验!


发现朋友圈变“安静”了吗?

浏览 21
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报