📘 第四章 返回结果的HTTP状态码
📄 一句话概括

503 是「服务暂时不可用」:维护、过载、依赖挂了。配 Retry-After 告诉客户端等多久再来。

📝 本节和前面几节的关系

上一节的 500 是「我出 bug 了」,这一节的 503 是「我暂时不行」。 差别在「重试有没有用」——这直接决定客户端策略。

一、三个使用场景

维护:主动下线时回 503 加 Retry-After,比直接断连友好得多。 客户端知道「等会儿再来」,而不是「这站挂了」。 过载:请求量超过处理能力时,主动拒绝一部分(过载保护)。 这比让所有请求都超时好——快速失败比慢慢失败更省资源。 依赖故障:数据库连不上、上游服务挂了。严格说这更适合 502/504,但很多系统统一用 503。

二、Retry-After 怎么用

两种写法:秒数(Retry-After: 120)或 HTTP 日期(Retry-After: Wed, 21 Oct 2026 07:28:00 GMT)。 秒数更常用,因为不用算时区。 客户端拿到它就应该等到那个时间再来,而不是立刻重试。 忽略 Retry-After 的客户端会把故障放大——服务端刚从过载里缓过来,又被一波重试打死。 Demo 里服务端前两次回 503 加 Retry-After: 2,第三次回 200。 这个「前两次失败、第三次成功」的形态,就是自动重试要处理的标准局面。

三、重试必须配退避与抖动

2 → 4 → 8 → 16 → 32 秒是指数退避,五次重试累计等 62 秒。 这个数字很重要:重试不是免费的,业务上要能接受「最多等一分钟」。 光有退避还不够,还要加随机抖动(jitter):每个客户端在基准时间上随机偏移一点。 因为如果一万个客户端同时收到 503、同时等 2 秒、同时又回来, 服务端在那一刻要面对同一万个请求——惊群。加了抖动,请求就被摊平到一个时间窗里。 这三件事合起来(重试次数上限、指数退避、随机抖动)叫「退避重试」,是所有分布式客户端的标配, 缺一个都会出问题。

四、动手 Demo:两次 503 之后成功,顺带算一遍退避

服务端计数器前两次回 503 加 Retry-After: 2,第三次回 200。最后再算一遍指数退避的累计等待。

state[u'n'] += 1
if state[u'n'] <= 2:
    return (u'HTTP/1.1 503 Service Unavailable',
            [(u'Retry-After', u'2')], b'busy')
return (u'HTTP/1.1 200 OK', [(u'Content-Type', u'text/plain')], b'ok')

实跑输出:

--------------------------------------------------------------------
503 Service Unavailable:现在不行,等会儿再来
--------------------------------------------------------------------
  第 1 次                    HTTP/1.1 503 Service Unavailable(Retry-After: 2)
  第 2 次                    HTTP/1.1 503 Service Unavailable(Retry-After: 2)
  第 3 次                    HTTP/1.1 200 OK

  503 的含义                 服务暂时不可用:维护、过载、依赖挂了
  Retry-After                告诉客户端等几秒再来(秒数或 HTTP 日期)
  和 500 的区别              500 是「我出 bug 了」,503 是「我暂时腾不出手」
  和 429 的区别              429 是「你请求太频繁」,503 是「我不行」

  指数退避(秒)             2 → 4 → 8 → 16 → 32
  累计等待                   62 秒(5 次重试)
  客户端遇到 503 的正确做法是**退避重试**,而且要加随机抖动,
  否则所有客户端会在同一秒一起回来,把刚恢复的服务再打死一次。
  这就是「惊群」——微服务里几乎所有重试都要配 jitter。

第 1 次 / 第 2 次 503(Retry-After: 2)、 第 3 次 200 OK——三次请求的状态变化就是自动重试要处理的完整剧本。 指数退避(秒)2 → 4 → 8 → 16 → 32、累计等待 62 秒(5 次重试)。 62 秒这个数是和的,不是单次——很多人算退避时只看最后一次。 和 500 的区别 500 是「我出 bug 了」,503 是「我暂时腾不出手」——所以 500 重试通常没用, 503 重试通常有用。这一条直接决定客户端策略。

30 秒实验

  1. 把 Retry-After 改成一个 HTTP 日期字符串,看客户端能不能解析。
  2. 把服务端改成永久 503,看客户端重试五次之后该做什么(放弃并报错)。
  3. 算一算:如果加 20% 抖动,一万个客户端在第一个重试点上会分散到多宽的时间窗。

常见误区

  1. 「503 就是服务挂了」——是暂时不可用,可能下一秒就好。
  2. 「收到 503 应该立刻重试」——那会把过载放大,必须按 Retry-After 等。
  3. 「退避就够了,不用抖动」——所有客户端会在同一刻一起回来,形成惊群。
自测三问(点开对答案) 1. 503 与 500 的关键区别? —— 500 是服务端缺陷,重试通常无用;503 是暂时不可用,重试可能有用。 2. `Retry-After` 有哪两种写法? —— 秒数,或 HTTP 日期(RFC 1123 格式,末尾 GMT)。 3. 为什么退避要加随机抖动? —— 避免所有客户端在同一时刻一起重试,形成惊群把服务再打死一次。

第四章到此结束。第五章看站在客户端和服务器中间的那些程序。

相关笔记