摘要:2026年10月15日上午,DeepSeek 网页、App、API 全量中断近5小时。官方致歉、全额返还一周 API 消费,并将原因指向工程链路中的「单点依赖」。本文从故障时间线出发,拆解单点依赖的致命机理、近5小时 MTTR 的构成与重试风暴的流量放大效应,并给出可直接落地的多供应商切换、指数退避、熔断器、幂等续跑代码,以及一份高可用自查清单。

图1 故障早高峰的服务监控示意(AI 生成概念图,非真实截图)
1 事件回顾:全天最值钱的三个小时,全没了
2026年10月15日,周四。8点11分,DeepSeek 网页端与 App 开始出现服务异常,官方状态页陆续标红:对话服务部分中断、DeepSeek V4.1 Flash API 部分中断、网页/API 性能下降。用户看到的提示是「服务器暂时不可用」「服务器繁忙,请稍后重试」,部分用户反馈对话内容丢失。
故障持续到13点04分,共计4小时52分,网页、App、API 同时不可用,国内与海外用户均受影响,「DeepSeek崩了」一度冲上微博热搜第一。当天傍晚,DeepSeek 发布致歉与补偿方案:按账号10月8日至14日7天内的消耗金额,以赠金形式全额返还,自动到账,后续 API 计费优先从赠金账户扣除。
故障完整覆盖了9点到12点的高峰计价时段------对调用方来说,这是全天最值钱的三个小时。
| 时间 | 关键节点 | 影响 |
|---|---|---|
| 08:11 | 网页/App 开始异常,状态页标红 | 对话服务、V4.1 Flash API 部分中断 |
| 上午 | 网页/API 性能下降,请求大面积失败 | 无法发起新对话,部分对话内容丢失;API 调用失败 |
| 期间 | 「DeepSeek崩了」冲上微博热搜 | 开发者与企业业务被动中断 |
| 13:04 | 服务全面恢复 | 故障持续约4小时52分 |
| 傍晚 | 官方致歉并公布补偿 | 全额返还7日消耗;承诺剥离单点依赖 |
表1 10·15 故障时间线(依据官方状态页与公开报道整理)
这并不是孤立事件。据公开报道,10月12日 DeepSeek 对话服务也曾短暂异常。官方状态页显示,2026年7月至10月,DeepSeek V4 Pro API 可用率为99.74%,V4.1 Flash API 为99.46%。数字贴着「四个九」,但剩余的零点几个百分点一旦集中在工作日早高峰砸下,就是实打实的近5小时。对开发者而言,这不是一次「App 崩了」,而是一次大模型在线服务的系统性中断。
2 官方口径:根因是工程链路里的「单点依赖」
DeepSeek 在致歉公告中给出的整改方向是:「全面梳理并剥离单点依赖,坚决杜绝同类问题再次发生」。SPOF(Single Point of Failure,单点故障)并不是新鲜概念,但在大模型在线服务里,它的杀伤力被链路长度放大了。
需要先做两个事实澄清:其一,网传「算力被借给量化交易」等说法没有任何官方依据,官方与多位业内人士均指向工程链路问题而非算力挪用;其二,截至本文成稿,官方并未披露具体是哪个组件,下文以「单点依赖」这一官方层级表述为限,不做过度揣测。
2.1 串联系统的可用性,取决于最脆弱的一环
一个在线推理请求通常要穿过多个环节:流量入口 → 网关/鉴权 → 调度 → 缓存/计量计费 → GPU 推理集群。这些环节在可用性上是串联关系,整体可用性近似等于各环节可用性的乘积:
|--------------------------------------------------------------------------------------------|
| A_system ≈ A_1 × A_2 × ... × A_n # 10 个环节各自 99.9%,整体只有 99.0% 左右 # 任意一个环节可用性趋近于 0,整条链路趋近于 0 |
这意味着:即使你买了再多 GPU、推理集群再健康,只要链路上有一个共享组件是单点(比如唯一的调度器、没有热备的缓存/计量服务),它一挂,下游所有健康算力都会被「饿死」。

图2 单点依赖架构与高可用多活架构对比
2.2 大模型服务里常见的单点清单
| 环节 | 典型单点 | 故障后果 |
|---|---|---|
| 注册/配置中心 | 单实例、无热备 | 服务无法互相发现,新实例无法上线 |
| 统一网关/调度层 | 无热备的调度器 | 全部请求无法路由,下游集群被饿死 |
| 共享缓存 | 单副本、无持久化 | 缓存击穿,请求全部打到推理后端 |
| 鉴权/计量计费 | 单实例服务 | 推理集群正常也无法放行请求 |
| 任务编排/消息队列 | 单节点 | 智能体任务链整体卡死、无法续跑 |
| 单一模型供应商 | 调用方无备选 | 供应商故障即等同于自身业务停摆 |
表2 大模型服务链路中的常见单点(SPOF)
3 为什么修了近5小时:MTTR 是五段时间之和
很多人第一反应是「重启不就好了」。但大模型在线服务不是手机 App。据澎湃新闻报道,受访专家指出:诊断并不慢,瓶颈在修复阶段。平均修复时间(MTTR)在这起事件里至少由五段构成:
|--------------------------------------------|
| MTTR ≈ 检测告警 + 定位隔离 + 权重加载/预热 + 缓存重建 + 灰度放量 |
3.1 大模型重启,等于一次小型发布
- 权重加载:几千亿参数的模型权重要从存储读入显存,耗时以十分钟甚至小时计;
- 实例预热(Warm-up):新实例不能立刻接满流量,要先用请求逐步「喂热」,否则首 token 延迟和错误率都会飙升;
- 缓存重建:缓存层若受波及,恢复后命中率会率先下降,大量请求直接打到推理后端,形成二次冲击;
- 灰度放量:流量只能逐步放开,不能一次性全开,每一档都要观察指标,相当于重新走一遍发布流程。
3.2 重试风暴:用户每点一次「重试」,都在给修复添堵
故障恰好撞上早高峰。卡顿时用户反复点击「重试」,客户端在自动重试,上游业务的定时任务还会把失败批次整批重跑。如果三层各自最多重试 3 次,故障瞬间最坏情况下的请求量是正常值的 3³≈27 倍:
|----------------------------------------------------------------------------------|
| 最坏放大倍数 ≈ 每层重试次数 ^ 重试层数 示例:3 层链路 × 每层最多 3 次重试 ≈ 27 倍流量 结果:修复通道被重试流量挤占,恢复时间被进一步拉长 |
这正是「重试风暴(Retry Storm)」的经典机理。它也解释了为什么生产级系统必须使用指数退避 + 随机抖动、设置重试预算(Retry Budget),并在下游持续失败时由熔断器快速失败------故障期间,「不发请求」比「疯狂重试」更有价值。

图3 大模型服务恢复链路与可用容量的台阶式恢复曲线
恢复时间最终取决于两件事:修复通道是否与故障域隔离,以及修复期间的流量洪峰有多大。这两件事,恰恰都是工程能力,而不是算力规模。
4 算力余量与运维工程:限流熔断为什么没拦住
公开信息显示,DeepSeek 的算力余量并不宽裕:V4.1 Flash 内测期间,每个账户最多只能同时处理20个请求;其推出峰谷定价时,官方给出的理由正是「更合理地配置资源、提升服务稳定性」。需要用价格来削峰,本身就说明余量不厚。而今年 DeepSeek 发布节奏密集:4月 V4 预览版、8月 V4 Pro 正式版、9月10日 V4.1 Flash 正式发布。若新模型灰度与线上服务共用同一批算力,发布前后往往正是余量最薄的时刻。
但算力紧张不等于必然全量中断。受访的 AI 云计算服务商高管指出,限流、熔断、降级、测试与预发布环境、灰度升级、流量管理、回退机制等一整套运维工程,才是把「容量不足」兜成「局部降级」而不是「整体停摆」的关键。用业内一句概括:研究型公司的迭代速度,一度跑在了运维余量前面。
对调用方来说,结论很朴素:永远不要假设任何一家模型服务「永远可用」。SLA 是商务承诺,架构上的冗余才是工程承诺。
5 调用方高可用实战:四段可直接抄的代码
服务端的整改我们控制不了,但调用链路上的高可用完全可以自己掌握。下面给出四段最小可用实现。
5.1 多供应商故障切换(Failover)
主用厂商、备用厂商、本地开源模型三级兜底,按优先级依次尝试。注意:只有连接失败、超时、429、5xx 这类「换一家可能就好」的错误才切换;鉴权失败、参数错误等 4xx 直接抛出,避免无意义重试。
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| from openai import OpenAI # 按优先级:主用厂商 → 备用厂商 → 本地开源模型(vLLM 等兼容端点) PROVIDERS = {"base_url": "https://api.deepseek.com", "api_key": "sk-xxx", "model": "deepseek-v4-flash"}, {"base_url": "https://your-backup-vendor.example.com/v1", "api_key": "sk-yyy", "model": "your-backup-model"}, {"base_url": "http://127.0.0.1:8000/v1", "api_key": "not-needed", "model": "local-model"}, FAILOVER_STATUS = {408, 429, 500, 502, 503, 504} def chat(messages, timeout=30): last_err = None for p in PROVIDERS: client = OpenAI(base_url=p"base_url", api_key=p"api_key", timeout=timeout) try: resp = client.chat.completions.create( model=p"model", messages=messages) return resp.choices0.message.content except Exception as e: status = getattr(getattr(e, "response", None), "status_code", None) if status is not None and status not in FAILOVER_STATUS: raise # 4xx 业务错误,切换供应商也无意义 last_err = e raise RuntimeError(f"all providers unavailable: {last_err}") |
5.2 指数退避 + 全抖动(Exponential Backoff with Full Jitter)
固定间隔重试会让海量客户端在同一时刻重新发起请求(惊群),全抖动把重试时刻打散,是 AWS 架构白皮书推荐的标准做法。
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| import random import time class ServerError(Exception): pass def call_with_retry(fn, max_retries=5, base=0.5, cap=30.0): for attempt in range(max_retries + 1): try: return fn() except (TimeoutError, ConnectionError, ServerError): if attempt == max_retries: raise # sleep = random(0, min(cap, base * 2 ** attempt)) sleep = random.uniform(0, min(cap, base * 2 ** attempt)) time.sleep(sleep) |
补充两点:遇到 HTTP 429 时优先读取响应头 Retry-After,而不是自行计算;写请求只有携带幂等键时才可以安全重试。
5.3 熔断器:下游持续失败时快速失败
熔断器让下游在故障窗口内快速失败(fail fast),把请求切给备用通道或降级逻辑,而不是让线程全部阻塞在超时等待上。
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| import time class CallNotPermitted(Exception): pass class CircuitBreaker: CLOSED, OPEN, HALF_OPEN = "CLOSED", "OPEN", "HALF_OPEN" def init(self, fail_threshold=5, cool_down=30.0): self.fail_threshold = fail_threshold self.cool_down = cool_down self.state = self.CLOSED self.fails = 0 self.opened_at = 0.0 def call(self, fn): if self.state == self.OPEN: if time.time() - self.opened_at >= self.cool_down: self.state = self.HALF_OPEN # 只放行少量探测请求 else: raise CallNotPermitted("circuit open, failover now") try: result = fn() self.state, self.fails = self.CLOSED, 0 return result except Exception: self.fails += 1 if self.state == self.HALF_OPEN or \ self.fails >= self.fail_threshold: self.state = self.OPEN self.opened_at = time.time() raise |
5.4 幂等键与断点续跑:让任务「从头再来」变成「接着跑」
智能体任务的中断损失按任务长度放大,解药是幂等与检查点(Checkpoint):写请求携带幂等键让服务端去重;长任务拆分步骤、每步持久化状态,故障后从最后一个检查点恢复。
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| # 写操作携带幂等键,服务端按同一键去重,重试不产生副作用 headers = {"Idempotency-Key": "task-20261015-0001"} # 断点续跑:每完成一步持久化 checkpoint state = load_checkpoint(task_id) # 从存储恢复已完成步骤 for step in remaining_steps(state): result = run_step(step) save_checkpoint(task_id, step, result) # 故障重放时从上一步继续 |
5.5 本地模型兜底
DeepSeek 权重开源,vLLM、Ollama 等推理框架提供 OpenAI 兼容接口。对不允许「断供」的关键流程,可以部署一套本地开源模型作为最后兜底------它性能未必最强,但在所有外部服务都不可用时,它是唯一不受外网影响的链路。这也是 5.1 示例中把本地端点放在最后一级的原因。
6 高可用自查清单
| 层级 | 检查项 | 建议手段 |
|---|---|---|
| 接入层 | 是否绑定了单一模型供应商? | 多供应商/多中转站接入,自动故障切换 |
| 流量层 | 故障时是否会无限重试? | 指数退避+全抖动、重试预算、超时与请求取消 |
| 熔断层 | 下游持续失败能否快速失败? | 三态熔断器、降级回复、排队限流 |
| 任务层 | 中断后能否接着跑? | 幂等键、Checkpoint、上下文与中间结果持久化 |
| 容量层 | 发布/灰度是否挤占线上容量? | 灰度与生产算力隔离、压测、水位告警 |
| 容灾层 | 外网全断怎么办? | 本地/开源模型、私有部署、关键流程人工预案 |
| 商务层 | SLA 是否覆盖真实损失? | 可用性条款、状态页订阅、故障后索取 RCA |
表3 大模型调用方高可用自查清单
7 结语
DeepSeek 这次的处理算得上教科书式的故障公关:快速道歉、明确整改方向、全额返还一周账单。但账单能赔,赔不回高峰时段里没写完的代码、没跑完的任务和没交付的工作。
从架构视角看,这起故障的价值在于它足够典型:一个单点组件、一条串联链路、一次撞上早高峰的恢复,再叠加层层重试形成的流量放大,最终把局部问题演变成全网近5小时的停摆。服务端的冗余由厂商负责,调用链路上的冗余只能由我们自己建设。
真正的可靠不是从不出故障,而是故障发生时,你的系统能在用户无感知的几秒内切到另一条路。