requests默认不支持jitter,需继承urllib3.Retry并重写get_backoff_time()方法添加随机扰动,推荐使用JitterRetry子类配合HTTPAdapter配置allowed_methods和status_forcelist。

requests 默认不支持 jitter,必须手动组合 retry 机制
requests 库本身只提供 urllib3.Retry 基础重试能力,它支持指数退避(exponential backoff),但不内置 jitter(随机扰动)。jitter 的作用是避免大量客户端在同一时刻重试导致服务雪崩,必须自己加随机偏移。
常见错误是直接用 urllib3.Retry(backoff_factor=1) 就以为带 jitter 了——其实它只按 min(120, base * 2^retry_count) 算固定等待时间,没任何随机性。
-
backoff_factor是基数,不是 jitter 因子;jitter 需额外计算 - 必须继承或封装
urllib3.Retry,重写get_backoff_time()方法 - 推荐用
random.uniform(0, 1)生成 [0,1) 区间随机数,乘到指数结果上
自定义 Retry 类:覆盖 get_backoff_time() 加 jitter
最稳妥的方式是子类化 urllib3.Retry,在 get_backoff_time() 中插入 jitter 逻辑。注意原方法返回的是秒数(float),你只需在它算出的 base time 上乘一个随机系数。
import random import urllib3class JitterRetry(urllib3.Retry): def init(self, jitter_ratio=0.5, *args, *kwargs): super().init(args, **kwargs) self.jitter_ratio = jitter_ratio # 控制抖动幅度,0.0~1.0
def get_backoff_time(self): base = super().get_backoff_time() if base == 0: return 0 # jitter: base * (1 - ratio + ratio * random) # 例如 ratio=0.5 → 在 [0.5*base, 1.0*base] 区间均匀随机 return base * (1 - self.jitter_ratio + self.jitter_ratio * random.random())这个实现比简单
random.uniform(0, base)更合理:保留最小退避底线,避免过早重试压垮服务。配合 requests.Session 使用时的配置要点
把自定义
JitterRetry实例传给requests.adapters.HTTPAdapter,再挂载到Session。别漏掉allowed_methods和status_forcelist—— 否则 5xx 或连接失败可能不触发重试。
- 务必显式设置
allowed_methods(如["HEAD", "GET", "POST", "PUT", "DELETE"]),否则默认只重试幂等方法 -
status_forcelist=[429, 500, 502, 503, 504]才能让服务端限流/错误也进重试流程 -
total是总重试次数(含首次请求),raise_on_status=False避免自动抛异常打断流程
示例:
import requestssession = requests.Session() retry = JitterRetry( total=3, backoff_factor=1, jitter_ratio=0.3, allowed_methods=["GET", "POST"], status_forcelist=[429, 500, 502, 503, 504], ) adapter = requests.adapters.HTTPAdapter(max_retries=retry) session.mount("http://", adapter) session.mount("https://", adapter)
response = session.get("https://www.php.cn/link/85c19375f0c12c6793bf66b4e2666dc4")
为什么不用第三方库(如 tenacity)?
tenacity 等通用重试库能轻松加 jitter,但它在 requests 场景下会绕过 urllib3 的连接池、超时、重定向等底层控制,容易引发连接泄漏或 timeout 行为不一致。尤其在高并发长连接场景下,直接 patch urllib3 更可控。
如果你已用 tenacity,必须确保每次重试都新建 requests.Request 并交由 session.send() 处理,不能复用 response 对象或 session 状态;否则 jitter 可能掩盖真正的连接问题。
真正难的不是加随机数,而是让 jitter 不破坏退避下限、不干扰连接池复用、不和 timeout 逻辑冲突——这些细节都在 urllib3 的 retry 流程里埋着。










