3 月 2 日事件更新
在星期二 UTC 时间 02:01 AM,Deno 组织提供的几项服务发生了 98 分钟的服务中断。这影响了 deno.land 网站上的图片和视频、deno.land/x 和 deno.land/std 上 TypeScript 文件的服务、doc.deno.land 上文档报告的生成以及 cdn.deno.land 上注册表元数据的下载。我们已经得出结论,这次中断是由上游服务提供商 Cloudflare 的一个恶意滥用预防过滤器造成的。这篇文章详细介绍了究竟发生了什么、我们如何恢复系统以及我们正在采取哪些措施来防止将来再次发生这种情况。
所有服务现在都已恢复正常运行。api.deno.land 上的注册表 API 未受此事件影响。没有数据丢失。我们认真对待此类中断,并对由此造成的不便表示诚挚的歉意。
为了理解实际发生了什么,重要的是要知道我们在事件发生前 1.5 小时发布了 Deno 1.8 并在博客文章中发布了发行说明。这篇博客文章在事件发生前约 30 分钟出现在 Hacker News 上。事件发生时,我们网站的流量约为正常流量的 9 倍。
事件时间线
UTC 时间 02:00 AM,我们收到了来自 Cloudflare 自动化系统的电子邮件,通知我们 deno.land 上的所有媒体由于涉嫌违反其 TOS 的 2.8 条款而被阻止。TOS 的这一部分详细说明 Cloudflare 不得用于主要提供媒体文件。收到这封电子邮件后,我们决定从 1.8 博客文章中删除屏幕截图和图像作为临时缓解措施。这在 UTC 时间 02:09 AM 完成。但这并没有解决问题。UTC 时间 02:22 AM,我们向 Cloudflare 开了一个支持工单。
UTC 时间 03:00 AM,我们决定将我们的基础设施迁移到另一个基础设施提供商 (https://fly.io) 以缓解中断。非常感谢 Fly.io 的 Kurt Mackey 帮助我们进行这项工作并立即为我们提供基础设施。我们在 UTC 时间 03:24 AM 切换了受影响服务的 DNS 记录。这在 UTC 时间 03:41 AM 为全球大多数用户解决了中断问题。
Cloudflare 在事件开始 16.5 小时后,以及在我们联系他们 16 小时后,于 PM UTC 18:40 解除了对我们网站的阻止。这是我们在开工单后从他们那里得到的第一个非标准化回应。
根本原因
我们对事件的初步分析得出结论,Cloudflare 阻止了 deno.land 区域的所有媒体文件 - 可能是由于 Hacker News 导致的流量急剧增加。单单这一点不应该导致 deno.land/x 或 deno.land/std 瘫痪,因为它们不提供媒体,而是源代码。这是因为 Cloudflare 似乎将所有 .ts 文件(无论内容或 content-type 标头如何)都解释为 MPEG 传输流(属于媒体阻止范围)。在我们的例子中,这是不正确的,因为 .ts 文件既可以是 MPEG 传输流,也可以是 TypeScript 文件(就像我们的情况一样)。我们所有的 typescript 文件都使用 application/typescript
提供。
影响
您可能知道,Deno 使用 URL 导入远程代码。这意味着如果您要导入的模块的主机遇到中断,您将无法再从该主机下载此模块。所有包管理器都存在同样的问题 - 例如,当 npmjs.org 遇到中断时,您将无法再 npm install
。
这是否意味着当模块主机宕机时您无法运行您的项目?不是的。Deno 将所有远程导入缓存到您系统上的全局缓存目录中。这意味着当您第一次导入一段代码时,它将被下载并缓存,然后在后续运行时,您将能够离线使用该代码,而无需网络访问 - 就像 node_modules 一样。
我们预计这次中断对大多数在活跃项目中使用 Deno 的开发人员的影响相对较小,因为他们可能已经缓存了他们的依赖项。这次中断主要影响了新的 Deno 用户和 CI 管道。
同样重要的是要注意,Deno CLI 不依赖于 deno.land 域在线才能运行。它是完全注册表无关的。如果您的项目仅由来自其他注册表(如 esm.sh、skypack.dev、jspm.dev 或 nest.land)的模块组成,您将不会受到此次中断的影响。
下一步是什么?
Cloudflare 在周二晚上联系我们讨论了发生的事情。经过初步调查,他们得出结论,这是他们的滥用监控系统中的错误。Cloudflare 向我们保证这个问题不会再次发生,并且他们将在他们的系统中实施更改,以确保这种情况不会发生在任何其他 Cloudflare 客户身上。
Cloudflare 还向我们保证,从误报检测到修复之间 16 小时的间隔是不可接受的,这将是他们立即关注的领域。
这次经历巩固了我们的信念,即在标准化的开放 Web API(如 fetch
)上构建 Deno 运行时是正确的举措。由于 Cloudflare Workers 也基于这些标准的 Web API 构建,我们能够在 20 分钟内将我们的主要 Cloudflare Worker 迁移到在 Fly.io 上运行的 Deno 脚本。我们只需要 polyfill “fetch” 事件即可让我们的 workers 运行起来。
如果您有兴趣,这是我们用于 polyfill “fetch” 事件的代码:https://gist.github.com/lucacasonato/1a30a4fa6ef6c053a93f271675ef93fc。尝试在本地运行此示例,然后访问 http://0.0.0.0:8080。
$ deno run --allow-net https://gist.githubusercontent.com/lucacasonato/1a30a4fa6ef6c053a93f271675ef93fc/raw/efcdc8e798604e194831830fcb962b50261384b3/example-worker.js
Listening on http://0.0.0.0:8080
由于此事件,我们建立了一个公共状态页面。此页面显示 deno.land/x、deno.land/std、cdn.deno.land 和 api.deno.land 的当前状态。您可以在 https://status.deno.land/ 上查看它。