Railway 这次故障有一个很反常的点:不是所有负载都真的停了,但用户还是访问不到。
根据 Railway 事故报告,5月19日22:20 UTC 至5月20日06:14 UTC,平台因 Google Cloud 将其生产账号错误置为暂停状态,出现约8小时服务中断;07:58 UTC,事故被标记为解决。
直接影响很清楚:Dashboard、API、数据库、GCP compute 下线。用户看到的是 503、404、无法登录、部署阻塞。
更要命的是,故障越过了 GCP 边界。Railway Metal 和 AWS 上的部分用户负载本身仍在线,但边缘代理依赖托管在 GCP 的网络控制面 API 来更新路由表。路由缓存过期后,这些负载就从外部“消失”了。
这篇事故真正值得看的,不是谁背锅,而是一个更工程化的问题:多云资源在线,不等于平台可达。
账号恢复很快,服务恢复很慢
Railway 的时间线里,GCP 账号访问在 22:29 UTC 恢复。距离确认根因只过了十来分钟。
但这不是服务恢复。账号能进,不代表磁盘、计算、网络、边缘路由都能同时回来。云平台故障常见的麻烦就在这里:控制权恢复只是第一步,依赖它的系统还要一层层重新站起来。
这次的关键时间点大致如下:
| 时间点 | 进展 | 用户看到什么 |
|---|---|---|
| 5月19日22:11 | Dashboard 返回 503 | 无法登录,API 不可用 |
| 22:19 | 确认 GCP 生产账号被暂停 | 平台级故障定位到上游账号状态 |
| 22:29 | GCP 账号访问恢复 | 账号恢复,但服务未恢复 |
| 22:35 | 路由缓存开始过期 | Metal、AWS 负载开始出现 404 |
| 5月20日01:38 | 边缘流量恢复服务 | 网络层逐步恢复 |
| 02:47 | GitHub OAuth/webhook 因重试流量触发限流 | 登录、构建再次受阻 |
| 04:00 | API、Dashboard、OAuth 确认可用 | 剩余负载继续恢复 |
| 06:14 | 主要中断窗口结束 | 约8小时故障结束 |
| 07:58 | 标记解决 | 事故状态关闭 |
这里要避免一个误写法:不能说所有用户工作负载都实际宕机。
更准确的说法是,峰值时全区域工作负载不可达。部分非 GCP 负载仍在运行,只是平台边缘无法解析到它们。
对开发团队来说,这种故障更烦。应用进程可能没死,数据库也未必丢数据,但外部用户已经打不开服务。排障时,你会看到一个很别扭的状态:服务像是活着,又像是不存在。
问题不在“多云”,在热路径卡在单云
Railway 称其网络是 Metal、GCP、AWS 之间的 mesh ring,也有高可用互联。数据库也跨多个可用区运行。
这说明 Railway 不是完全没有冗余。问题更具体:工作负载可发现性依赖运行在 GCP 机器上的网络控制面 API。
缓存能拖一会儿,但缓存不是故障切换。等缓存过期,边缘代理拿不到新的路由表,Metal 和 AWS 上的负载即使在线,也会变成不可达。
这就是热路径的危险。
很多团队谈多云,容易只看资源层:机器在哪些云上,网络是不是互通,数据库有没有多可用区。可真正决定事故边界的,往往是控制面、服务发现、鉴权、构建、登录这些链路。
可以简单对照一下:
| 看起来的多云能力 | 真正要追问的问题 | 这次事故暴露的风险 |
|---|---|---|
| 计算资源分布在 GCP、AWS、Metal | 路由发现是否也跨云可用 | 非 GCP 负载在线但不可达 |
| 网络有高可用互联 | 控制面 API 是否依赖单一云 | 缓存过期后边缘无法更新路由 |
| 数据库跨可用区 | quorum 是否跨云、跨设施运行 | 单云实例消失时仲裁能力受考验 |
| 使用 GitHub OAuth/webhook | 重试风暴是否有保护 | 恢复期触发限流,登录和构建受阻 |
这也不是说 PaaS 都不可信。PaaS 的价值本来就是替开发者屏蔽复杂基础设施。
现实限制在于,用户很难直接验证供应商控制面的真实依赖。状态页、SLA、架构说明、事故复盘,往往是少数可用线索。PaaS 用户买到的是抽象后的可靠性,但抽象层本身也要被审计。
目前还不能推断 Google Cloud 内部到底发生了什么。Railway 原文也在等待 Google 内部复盘确认。事故报告没有提到数据丢失、入侵或计费异常,这几个点不该硬加戏。
我更在意的是 Railway 自己承认的部分:供应商选择和架构依赖由自己负责。这个表态比单纯把问题推给上游更有信息量。
工程团队现在该问什么
Railway 的后续计划,方向很明确:把 GCP 从数据面热路径中移出,更多保留为 secondary/failover;把高可用数据库分片扩展到 AWS 和 Metal;重构数据面和控制面,让单一云的全部实例瞬间消失时,数据库仲裁仍能保持运行,并能快速迁移不可用工作负载。
这不是“换一家云”能解决的问题。换云只是在换单点。如果控制面仍在单一供应商上,事故边界还是会被那条热路径决定。
对云平台和基础设施工程师,最该做的是把依赖图画到控制面,而不是停在资源清单。
具体说,要补三类检查:
- 路由发现.边缘代理的路由表从哪里来,缓存多久过期,失联后是降级还是失明。
- 数据库仲裁.quorum 是否跨 AWS、Metal、GCP 生效,单云全灭时会不会卡住写入或恢复。
- 恢复保护.OAuth、webhook、构建队列在重试洪峰下有没有限流、退避和隔离。
对依赖 Railway 或类似多云 PaaS 的开发团队,动作要更现实一点。
如果是生产系统,不必因为一次事故立刻迁移,但可以先延后把更关键的新服务压上去,等 Railway 公布更细的整改结果。已有业务要检查自己的外部兜底:DNS、状态页、降级页、备份部署方案,以及能否在 PaaS 控制面不可用时保留最小服务能力。
如果正在采购或续约,多问四个问题,比问“你们是不是多云”更有用:
| 决策场景 | 该问的问题 | 可能的动作 |
|---|---|---|
| 准备上生产 | 控制面和服务发现是否跨云可用 | 延后关键业务上线,等待整改细节 |
| 已经依赖 Railway | PaaS 控制面不可用时,业务是否还有兜底入口 | 补 DNS、降级页、备份部署预案 |
| 评估多云 PaaS | 登录、构建、webhook 是否依赖单点 | 把这些链路纳入供应商审查 |
| 做内部基础设施 | 缓存过期后系统是降级还是不可达 | 为路由发现设计失联模式 |
接下来最该观察的不是道歉措辞,而是三件工程结果。
Railway 会不会公开新的路由发现架构;数据库 quorum 是否真的跨 AWS、Metal、GCP;GitHub OAuth 和 webhook 的重试风暴是否能被限流保护吸收。
如果这三件事没有交代清楚,多云听起来再完整,也只能说明资源分散了,不能说明故障边界被切开了。
回到开头那个反常点:负载还在,用户却访问不到。它提醒的是一个老问题,牵一发而动全身。多云架构最怕的不是少一朵云,而是所有云都要经过同一扇门。
