一年前的今天,Cloudflare 给我一项任务:让人们可以在 Cloudflare 的边缘服务器上运行代码。那时,我们还不知道那是什么意思。是基于容器吗?一种新的图灵不完备的领域专属语言?Lua?“函数?”我们有很多想法。
最终,我们做出了现在看来似乎很明显的选择:JavaScript,使用标准的 Service Workers API,运行在一个基于 V8 构建的新环境中。5 个月前,我们扼要介绍了我们正在构建的东西,并开始了 Beta 测试。
如今,Cloudflare 已经部署了数以千计的脚本,并为数以十亿计的请求提供服务,Cloudflare Workers 已经准备好向所有人提供服务了。
“放弃 VCL 并采用 Cloudflare Workers 让我们可以做一些创造性的路由选择,从而让我们可以比现在更快地把 JavaScript 交付给数以百万计的 npm 客户。我们将在 Cloudflare 平台上构建我们下一代的服务,我们将使用 JavaScript 实现!”
— CJ Silverio,npm 公司首席技术官
什么是真正的云?
过去,Web 应用程序代码分成了两部分,服务器一部分,浏览器一部分。两者之间是一个庞大的哑网络负责把数据从一个点传送到另一个点。
我们认为,这有违“云”的初衷。
我们认为,云计算真正的梦想是代码就在网络里。代码不是在“us-west-4”或“南中亚(孟买)”运行,而是随处皆可运行。
具体来说,它应该在最需要它的地方运行。在响应新西兰的用户时,代码应该在新西兰运行。在处理数据库里的数据时,代码应该在存储数据的机器上运行。在和第三方 API 交互时,代码应该在托管 API 的地方运行。当人类探险者到达火星,他们不会愿意花一个半小时的时间等待 App 响应——代码需要在火星上运行。
Cloudflare Workers 是我们向着这个目标迈出的第一步。当你部署一个 Worker 时,它会在 30 秒之内部署到 Cloudflare 的整个边缘网络,全世界 100 多个地点。域中的每个请求都会由离用户近的 Cloudflare 地点的 Worker 来处理,不需要用户考虑自己的地点。我们上线的地点会越来越多,你的代码就越来越能“随处运行”。
好吧……我们不会在火星上运行。目前还没有。你在那里吗,艾伦?
什么是 Worker?
Cloudflare Workers 的名字来源于 Web Workers 以及更特别的 Service Workers,这个 W3C 标准 API 针对的是在浏览器后台运行并拦截 HTTP 请求的脚本。Cloudflare Workers 是使用同样的标准 API 编写的,但是在 Cloudflare 的服务器上运行,而不是在浏览器中。
下面是你需要使用的工具:
- 运行任何 JavaScript 代码,使用最新的标准语言特性;
- 拦截并修改 HTTP 请求,响应 URL、状态、头信息和正文;
- 直接从 Worker 响应请求,或者转发到其他地方;
- 把 HTTP 请求发送给第三方服务器;
- 串行或并行发送多个请求,把这些请求的响应组合成原始请求的最终响应;
- 在响应返回给客户端以后发送异步请求(例如,记录日志或分析);
- 控制其他 Cloudflare 特性,比如缓存行为。
Workers 的使用方法无数,我们很希望看看我们的客户会想出什么。下面是我们在 Beta 测试中看到的一些方案:
- 把不同的请求类型路由到不同的源服务器;
- 扩展边缘服务器上的 HTML 模板,降低源服务器的带宽成本;
- 针对缓存内容应用访问控制;
- 把一小部分用户重定向到过渡服务器;
- 在两个完全不同的后台之间执行 A/B 测试;
- 构建完全依赖于 Web API 的“无服务器”应用程序;
- 创建自定义的安全过滤器,阻止特定于自己 App 的有害流量;
- 重写请求,提高缓存命中率;
- 实现自定义的负载均衡和故障恢复逻辑;
- 快速运用应用程序修复,而不必升级产品服务器;
- 收集分析资料,而不用在用户的浏览器上运行代码;
- 数不胜数。
下面是一个例子。
// A Worker: // 1. 把访问首页(“/”)的访问者重定向到特定国家的页面(例如,“/US/”); // 2. 阻止盗链; // 3. 直接从谷歌云存储提供图片服务。 addEventListener('fetch', event => { event.respondWith(handle(event.request)) }) async function handle(request) { let url = new URL(request.url) if (url.pathname == "/") { // 这是一个首页(“/”)请求。 // 重定向到特定国家的路径。 // 例如,会给美国的用户发送“/US/”。 let country = request.headers.get("CF-IpCountry") url.pathname = "/" + country + "/" return Response.redirect(url, 302) } else if (url.pathname.startsWith("/images/")) { // 这是一个图片(在“/images”目录下)请求。 // 首先,阻止第三方访问者盗链。 let referer = request.headers.get("Referer") if (referer && new URL(referer).hostname != url.hostname) { return new Response( "Hotlinking not allowed.", { status: 403 }) } // 盗链检查通过。直接从谷歌云存储提供图片服务节省服务成本。 // 根据 Cache-Control 头信息,图片会在 Cloudflare 的边缘服务器缓存。 url.hostname = "example-bucket.storage.googleapis.com" return fetch(url, request) } else { // 定期请求。转发给源服务器。 return fetch(request) } }
速度真得很快
有时候,人们问我们,是不是 JavaScript 很“慢”。事实是最好的证明。
Workers 使用谷歌为 Chrome 构建的 V8 JavaScript。V8 不仅是 JavaScript 最快的实现之一,而且是任何动态类型语言的最快实现之一。人们已经针对 V8 做了大量的优化工作,因此,其性能几乎超过了 C/C++、Rust、Go 之外的任何服务器编程语言。(顺便说一下,我们很快就会支持这些语言,通过 WebAssembly。)
小结:普通的 Worker 脚本执行时间不到 1 毫秒。在启用 Workers 时,大多数用户都无法测量出任何延迟差异——当然,除非他们的 Worker 在直接从边缘服务器响应时实际上提高了延迟。
关于速度,还有一个方面需要注意,Workers 的部署也很快。在你保存并启用脚本后,Workers 在 30 秒内就可以部署到全球。
定价
Workers 是 Cloudflare 的收费扩展。我们希望定价策略尽可能的简单,就像下面这样:
每百万次请求 0.50 美元,每月最少 5 美元(包括最初的 1000 万请求)
入门
- 登录 Cloudflare 账户,访问“Workers”部分,配置 Workers;
- 在操练场里试用 Workers ,不需要账户;
- 阅读文档,学习编写 Workers;
- 查阅最初发布公告的博文,了解更多的技术细节;
- 在 Cloudflare 社区里讨论 Workers 。 > “Cloudflare Workers 为我们节省了大量的时间。没有 Workers,管理 bot 流量需要消耗宝贵的开发和服务器资源,有了 Workers,这些开发和资源就可以更好地用在其他地方了。”
— John Thompson,MaxMind 高级系统工程师
Everyone can now run JavaScript on Cloudflare with Workers
感谢徐川对本文的审校。
评论