7 月 13 日犹他州停机更新
从 7 月 13 日(星期三)协调世界时大约 18:00 开始,Deno 公司提供的几项服务在犹他州(us-west3)经历了长达 24 小时的区域性服务中断。在此期间,犹他州地区的用户在访问托管在 Deno Deploy 上的项目时遇到了故障,其中包括许多 Deno 网页属性。
我们已经确定此次停机是由我们的负载均衡服务造成的。这篇文章详细介绍了具体发生了什么以及我们正在采取哪些措施来防止将来发生这种情况。
在尝试将 us-west3 区域恢复在线后,7 月 15 日协调世界时 15:30 到 16:00 之间也发生了更短的停机。新创建的负载均衡器运行良好几个小时,但最终遇到了同样的问题。在此期间,托管在 Deno Deploy 上的项目,包括许多 Deno 网页属性,在此区域不可用。
所有服务现已恢复正常运行。没有数据丢失。我们认真对待此类停机事件,并对由此造成的中断表示诚挚的歉意。
影响
大约 24 小时的时间里,us-west3 区域的一些用户无法访问 dash.deno.com 和 Deno Deploy 项目,包括 deno.com 和 deno.land。该区域位于犹他州,服务于周边地区,包括一些邻近州。在二次事故期间,影响相同,但持续时间短得多;不到 30 分钟。
只有 us-west3 区域受到影响。在整个事件期间,所有其他区域均正常运行。此外,子托管不受影响。
事件时间线
7 月 13 日,协调世界时大约 18:45,我们开始收到少量用户关于停机的报告。我们调查了我们服务的状况,但无法确认任何报告。我们所有的状态监控和测试报告都显示一切正常。
在停机期间,我们继续监控我们的服务状态,并与一些受影响的用户合作以缩小问题的范围。
7 月 14 日,协调世界时 19:14,我们能够确定问题在于我们的 us-west3 区域,随后我们将其下线,并将流量重定向到其他附近的区域。
7 月 15 日,协调世界时 11:30,我们尝试使用新的负载均衡器实例将该区域恢复在线。
7 月 15 日,协调世界时 16:00,负载均衡器进入与之前相同的故障状态,我们再次禁用了该区域。该区域将保持禁用状态,直到我们的监控改进并且问题得到更永久的解决。
根本原因
进入 Deno Deploy 网络的最终用户请求会经过各种负载均衡器,最终到达可以执行 JavaScript 代码以响应请求的服务。
不同层的负载均衡器和后端服务使用 etcd 来执行服务发现。服务在可用性状态发生变化时向 etcd 集群宣布自身。其他服务(例如这些负载均衡器)从 etcd 中检索健康后端服务的列表。他们还会 监视 公告的服务列表,以便在给定服务变得可用或脱机时收到通知。负载均衡器然后使用此列表来决定将流量路由到哪些后端服务。
在此停机期间,一个区域负载均衡器设法断开了与 etcd 的连接,而应用程序没有注意到。我们预计这种连接会由于网络故障、超时等原因而经常断开。因此,该应用程序被编程为自动重新连接,如果它失败,则关闭自身。
没有这种连接,负载均衡器就无法接收来自 etcd 的更新。这导致它与系统其他部分“不同步”,并且不知道要将流量路由到哪些健康的后端。
负载均衡器没有健康的后端服务的情况并不罕见,因此负载均衡器知道如何处理这种情况。如果没有健康的后端,它将从网络中取消广告自己,以防止请求最终到达这个“死胡同”。
由于负载均衡器中的设计疏忽,它在这种特定情况下没有从系统中取消广告自己。这导致负载均衡器继续从上游负载均衡器接收流量,而没有地方可以将流量路由到。这会导致流量完全被丢弃。
下一步是什么?
这次事件清楚地表明,我们的监控系统中存在一些盲点。我们正在研究减少这些盲点的方法,并改进各个区域的监控能力。
此外,我们很难缩小导致停机的区域,因为失败的负载均衡器位于网络堆栈的早期位置(一个 TCP 负载均衡器)。它不会记录有关断开连接的任何诊断信息,也没有返回通道将诊断信息返回给用户(与 HTTP 负载均衡器不同,HTTP 负载均衡器可以返回响应头)。我们正在努力改进这里的监控情况。
我们目前还在对负载均衡系统进行一些架构更改,以完全防止此类故障。