2025 年 4 月 16 日,Spotify 经历了一次影响全球用户的中断。以下就是发生了什么以及我们将如何解决它。
背景
我们使用 Envoy Proxy 作为我们的网络外围系统。外围是我们的软件接收用户(您!)网络流量的第一部分。然后,它将流量分发到其他服务。我们使用云区域将流量合理地分布在世界各地。
为了增强 Envoy 的功能,我们开发并整合了我们自己的自定义过滤器。一个具体的例子是我们讨论了最近在 EnvoyCon 2025 上详细讨论过的限流过滤器。
发生了什么?
2025 年 4 月 16 日,从 UTC 12:20 到 15:45,我们经历了一次中断,影响了全球大多数用户。在此期间,除了由于时区差异而未受影响的亚太地区外,大部分流量都受到了影响。下面的图表显示了我们外围网络上成功的请求数量,紫色线条代表未受影响的亚太地区。
这次中断的原因是什么?
事发当天,我们更改了 Envoy 过滤器的顺序。这次更改被认为风险较低,因此我们同时将其应用于所有地区。更改顺序触发了其中一个过滤器中的一个错误,进而导致 Envoy 崩溃。与典型的孤立崩溃不同,这次崩溃同时发生在所有 Envoy 实例上。
所有Envoy实例的立即重启,加上客户端应用程序的重试逻辑,给边界带来了前所未有的负载峰值。流量的突然激增随后暴露出一个配置错误。由于Envoy的最大堆大小设置得高于允许的内存限制,Kubernetes不断地重启Envoy实例。一旦有新的Envoy实例启动,它就会接收到大量的流量,这反过来又导致它使用的内存超过了Kubernetes允许的内存限制。然后Kubernetes会自动关闭该实例,如此循环往复。
由于时区和时间的不同,事发时我们亚太地区的流量较低,这意味着该地区的 Envoy 内存使用量从未达到 Kubernetes 限制,这就是为什么该地区未受影响的原因。
故障通过增加总外围服务器容量来缓解,这使得 Envoy 服务器能够降低 Kubernetes 内存限制。终于,Envoy 服务器不再被重复重启。
时间线
- 12:18 UTC - Envoy 过滤器顺序更改,所有 Envoy 实例崩溃
- 12:20 UTC - 触发警报,表明入站流量显著下降
- 12:28 UTC - 形势升级,除亚太地区外,全球无流量
- 14:20 UTC - 欧洲地区流量完全恢复
- 15:10 UTC - 美国地区流量完全恢复
- 15:40 UTC - 所有流量模式恢复正常
今后我们该怎么做?
我们认识到此类中断可能产生的影响,并致力于从中学习。以下是我们正在采取的措施以改进我们的系统并防止将来发生类似问题;
- 我们已经修复了导致 Envoy 崩溃的 bug
- 我们已经修复了 Envoy 堆大小与 Kubernetes 内存限制之间的配置不匹配问题
- 我们将改进我们对边界网关的配置更改的发布方式
- 我们将改进我们的监控能力,以便能够更早地发现这些问题
就像过去一样,我们将在类似情况下继续提供透明度,以便自我问责并支持对我们服务的持续改进。
正文完。下面是巴辉特总结:
- 认为影响不大的小变更,通常是最危险的,因为重视程度不够,如这次故障,连灰度都没有,直接推到全局实例
- 越是对逻辑熟悉的人,越是盲目自信,越是容易犯错,越是对逻辑没那么熟悉的人,越是谨慎小心,越是敬畏线上,越是容易避免犯错
- 变更流程很重要,流程不信赖每个环节,通过整体协同来保障最终效果。流程也是是保护变更人员的,不遵守流程就是触犯红线
- 进程堆内存限制超过了 Kubernetes 限制,应该引以为戒,吃别人的堑,长自己的智,抓紧回去写个巡检任务或者配个告警规则,应该有不少进程都支持设置堆内存大小
- Spotify 这个故障,看起来没有优先回滚,而是选择先扩容,让 Envoy 实例变多,内存使用降低,低于 Kubernetes 限制,才让 Envoy 实例稳定下来。可能他们最开始并未意识到这个变更才是直接原因,复盘的时候才发现的。他们需要 Flashcat 事件墙那样的产品
- 这个时间线写得比较简略,毕竟是对外的,可以理解,对内应该有更详细的时间线,如果对内的复盘也是这样的,那就有点不太合格了
兄弟们,生产无小事,加速故障定位很关键,建设了各类零散的指标、日志、链路系统,但是故障定位仍然很慢?试试 Flashcat 的思路,免费交流申请。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。