# 惊魂半小时：一次播放 404 的幕后排查
> 上海时间 6 月 25 日凌晨，部分用户播放 404、部分却正常。一次概率极低的存储层（FUSE/NFS）内核崩溃，从报障到恢复约 40 分钟——这是那半小时的幕后排查与复盘。

> \[!NOTE]
> 上海时间 6 月 25 日凌晨 01:05，部分用户播放报 404，另一部分却完全正常。这是一次概率极低的存储层故障，从报障到彻底恢复约 40 分钟、定位后 15 分钟内处置完毕。本文还原那半小时里，我们如何用排除法一路锁定真凶。

一半人中招、一半人没事——这种「薛定谔式」的故障最让人头皮发麻，因为它几乎排除了所有「一刀切」的简单解释。接下来的半小时，我们靠排除法把范围一步步收窄，最后在最底层找到了真凶。

> \[!TIP]
> **先认识三个角色**
>
> * **推流网关**：你点播放后，负责去后端把视频内容取出来、转发给你的「前台」。
>
> * **存储集群**：真正存放海量影片的地方，规模 2PB 级别，完全自建。
>
> * **线路调度**：按时段自动切换最优分发线路，让不同地区的用户都尽量快。

一个播放请求要穿过一条固定链路：**用户请求 → 推流网关 → 存储集群 → 返回视频流**。崩溃发生时，断点就出在「存储集群」这一环。这也顺带解释了「为什么有人正常、有人 404」——**路径只有一条，差别只在存储这一环**；只有恰好命中受影响内容的请求才会失败，其余照常。

<br />

![播放链路对比图：正常时为「用户请求 → 推流网关 → 存储集群 → 正常播放」，故障时同一路径在存储集群的文件层崩溃并返回 404](/media/aac7789f-a5a3-4d72-a044-b08cca9edb43/image.webp)

## 第一个嫌疑人：播放器

最先被怀疑的总是离用户最近的那一层——是不是某些播放器更新后改了取流方式，不兼容了？

这个假设几分钟就被推翻：团队拿不同的播放器交叉测试，**全都能复现**。问题与客户端无关，根子在服务端。

## 第二个嫌疑人：线路调度

第二直觉指向线路调度。我们有分时自动切换线路的机制，很自然会怀疑：是不是调度环节有缓存没及时刷新，把一个「已经不存在的地址」发给了用户？——这甚至能解释「为什么只有部分人中招」。

但两个事实对不上：

* 当前**根本不在**任何预设的切换时段；

* 那些**压根不走这套调度**的线路，也一样在报错。

> \[!TIP]
> **为什么「缓存没刷新」是个合理怀疑？**
> 分发系统为了快，会把「去哪条线路取内容」的结果缓存一小段时间。如果缓存里存了一个已经失效的地址，用户就会拿到一个指向「不存在」的链接——表现出来正是 404。所以它一度是头号嫌疑；只不过这次，证据不支持。

调度被排除。嫌疑范围进一步收窄，指向了我们最不愿意看到、也最难处理的地方——**存储集群本身**。

## 真凶：存储层的内核级崩溃

定位到存储节点后，真相浮出水面：节点上发生了一次**极其罕见的 FUSE 文件系统内核级崩溃**，并连带把依赖它的 **NFS 共享**一起拖垮了。

> \[!IMPORTANT]
> **FUSE 和 NFS 是什么？**
>
> * **FUSE** 让文件系统能在「用户态」运行，灵活度很高——代价是，一旦它异常退出，挂在它上面的目录会瞬间变成「无法访问」。
>
> * **NFS** 是把一台机器的目录共享给其它机器用的网络文件协议，是集群内部互通的「血管」。
>
> 当底层的 FUSE 崩了，上面的 NFS 共享自然也跟着失效——访问句柄一断，上层取到的部分路径就变成了「无效 / 不存在」，推流网关对外就只能回 404。

到这里，整条因果链闭合了。

## 抢修

判断清晰之后，动作很快：

1. **重新挂载**崩溃的文件系统，恢复底层访问；
2. 刷新共享导出，让其它节点重新建立连接；
3. **重启那些挂载依赖被打断的推流网关**——它们仍「钉」在已经失效的旧挂载上，只修底层还不够，必须让它们重新绑定。

三步走完，服务全面恢复。从 01:05 用户报障，到 01:29 锁定存储层，再到 01:44 彻底处理完毕——**全程约 40 分钟，而真正定位之后，15 分钟内就完成了处置**。

<br />

![故障处置时间轴：01:05 故障浮现，依次排除播放器兼容与线路调度，01:29 定位到存储集群 FUSE 内核级崩溃，01:44 重新挂载并重启推流网关后全面恢复](/media/f8091b9b-9418-42c6-b46e-dcfabd20070e/image.webp)

## 复盘：自建 2PB 存储，意味着什么

这是一次概率极低的故障，但它真实地暴露了一件事：**维护一套 2PB 规模的物理存储集群，运维难度远高于直接套用网盘方案。** 关于这套存储与带宽规模，见[关于本站](/start/about)。

网盘把这些复杂度都藏在了服务商背后；而我们选择自建，就意味着从内核崩溃、文件系统、共享协议到推流链路——**每一层都得自己兜底**。它对团队的技术储备和应急能力提出了更高的要求。这一次，我们扛住了。

## 下一步

恢复服务不是终点。我们已经在做两件事，争取把隐患摁在下一次「惊魂半小时」发生之前：

* **给底层存储硬件做一次体检**，排查阵列控制器等环节是否存在潜在隐患；

* **复查运行环境**，看有没有被忽略的异常因素。

> \[!NOTE]
> 本次日志完结。

