跳转至

03 · 推荐配置与调优

本文针对常见场景给出推荐 cooldown 配置,并讲清楚 cooldown 跟 num_retries / fallbacks / latency-based-routing 的叠加效应。


1. 默认 5 秒 cooldown 太短的问题

DEFAULT_COOLDOWN_TIME_SECONDS = 5 这个默认值在多数场景下偏激进。

1.1 后果模拟

假设 deployment X 上游真的挂了 30 分钟,model_group 还有其它 7 个健康 deployment:

T=0      请求 #1 → Router 选 X → 5xx → cooldown X 5s
T=0+ε    请求 #2 → 跳过 X,选其他 → 200 OK
T=1      请求 #3 → 跳过 X → 200 OK
...
T=5      X 的 cooldown 过期
T=5+ε    请求 #N → Router 又可能选 X → 5xx → cooldown X 5s
T=10     请求 #M → Router 又可能选 X → 5xx → cooldown X 5s
... 周而复始 30 分钟

→ 在这 30 分钟里,每 5 秒会撞 X 一次失败。如果 prod QPS 高,这些"无效失败请求"会: - 给上游 X 持续制造负担(让它更难恢复) - 给业务方带去用户可见的失败(即使 LiteLLM 内部用其他 deployment 的 retry 接住了,也消耗了延迟预算) - 持续刷错误日志和 Prometheus 指标

1.2 为什么默认这么短

上游 LiteLLM 的设计哲学:"快速试错快速恢复"。如果 X 是瞬时抽风(比如某个 region 1 秒抖动),5 秒后就好了,长 cooldown 反而错过了它的可用窗口。

这个假设跟现实不符——实际上游的故障多数持续秒级到分钟级,5 秒太短的概率远大于 5 秒太长。

1.3 推荐值

场景 推荐 cooldown_time
默认(不调) 5
小流量服务(QPS < 10) 30
中等流量(QPS 10-100) 60
大流量(QPS > 100) 120-300
知道某 deployment 故障常持续几分钟 per-deployment 配 300-600

2. num_retries 跟 cooldown 的叠加(关键概念)

2.1 触发顺序

业务请求失败时,Router 内部流程:

flowchart LR
    Req[业务请求] --> Try1[Router 选 A → 调 → 失败]
    Try1 -- num_retries > 0 --> Try2[Router 重新选 A* → 调 → 失败]
    Try2 -- num_retries > 0 --> Try3[Router 重新选 → 调 → 失败]
    Try3 -- 还有 retry --> TryN[...]
    TryN -- 重试用完 --> FailFinal[最终抛 exception 给业务方]
    FailFinal --> CB[deployment_callback_on_failure]
    CB --> Cooldown[★ 写 cooldown]

    style Cooldown fill:#fdd

关键事实:

  • 重试期间的失败不写 cooldown(每次重试 Router 内部消化)
  • 重试完最终失败才走 callback → 写 cooldown
  • 每次重试 Router 重新选 deployment(不一定还是 A,可能选 model_group 里其他)

2.2 为什么 retry 期间不写 cooldown

设想:num_retries: 3、A 抽了一下、B/C/D 都好。

如果 retry 期间立刻写 cooldown,第一次 A 失败后立刻把 A 列为 cooldown,retry 时连试都不试。但LiteLLM 设计是 retry 期间继续给 A 一次机会——因为可能就是瞬时抖动。

→ retry 用完后还失败,才"判定" A 真的有问题,写 cooldown。

2.3 实际推荐配置

litellm_settings:
  num_retries: 2          # 业务请求失败自动重试 2 次

router_settings:
  cooldown_time: 30       # retry 都失败的 deployment cooldown 30 秒

逻辑: - 业务方收到的失败 = retry 完仍失败的请求 - cooldown 是给"判定为坏"的 deployment 用,不污染 retry 期间的小抽风


3. fallbacks 跟 cooldown 的叠加

3.1 fallbacks 是什么

litellm_settings:
  fallbacks:
    - { "gpt-4o": ["claude-opus-4-7", "gemini-2-5-pro"] }

意思:调 gpt-4o 失败时,自动 fallback 到 claude-opus-4-7,再失败 fallback 到 gemini-2-5-pro跨 model_group 的 fallback

3.2 fallback 链上每个失败都单独 cooldown

代码 async_function_with_fallbacks(搜这个函数名找到):

  • 第一个 model(gpt-4o 内部某 deployment)失败 → cooldown 该 deployment
  • fallback 到第二个 model(claude-opus)失败 → cooldown claude-opus 的某 deployment
  • fallback 到第三个 model(gemini-2-5-pro)失败 → cooldown gemini-2-5-pro 某 deployment

每段 fallback 各自走 num_retries → callback → cooldown 链,互相独立。

3.3 注意 num_retries 跟 fallbacks 的优先级

代码里通常的顺序:先 retry,再 fallback。也就是:

gpt-4o deployment A → retry 失败 → A 进 cooldown
gpt-4o deployment B → retry 失败 → B 进 cooldown  
... gpt-4o 所有 deployment 都用完
fallback to claude-opus
claude-opus deployment → retry → ...

具体顺序看代码 async_function_with_fallbacks / async_function_with_retries 实现。


4. latency-based-routing 跟 cooldown 的叠加

你们 prod 用的是 latency-based-routing。它跟 cooldown 完全正交,叠加生效:

flowchart TB
    Req[业务请求] --> Step1[async_get_healthy_deployments<br/>拉 model_group 所有 deployment]
    Step1 --> Step2["★ 第一过滤层:cooldown<br/>_filter_cooldown_deployments<br/>(把所有 cooldown 中的踢掉)"]
    Step2 --> Step3["第二过滤层:context length<br/>token 是否超限"]
    Step3 --> Step4["第三过滤层:rate limit<br/>(rpm/tpm 是否已超)"]
    Step4 --> Step5["★ routing_strategy 选最终 deployment<br/>latency-based 选最低延迟的<br/>lowest-tpm 选最低负载的<br/>...等"]
    Step5 --> Done[实际调用]

    style Step2 fill:#fdd
    style Step5 fill:#dfd

所有 strategy 都先过 cooldown 过滤,再做 strategy 自己的选择逻辑。

4.1 latency-based 的"自然避让"特性

latency-based-routing 在每次请求成功后记录该 deployment 的延迟。如果某个 deployment 持续超时(高延迟 / 失败),它的"统计延迟"会变得很高,latency-based 会自动选其他低延迟的 deployment

→ 这跟 cooldown 形成双层保护: - Cooldown: 失败到一定程度后强制跳过一段时间 - latency-based: 即使没 cooldown,也优先选响应快的 deployment

实际效果:上游某 deployment 真挂时,latency-based 几乎不会选它(因为它失败/超时延迟很高),cooldown 是"双保险"。

4.2 推荐组合

router_settings:
  routing_strategy: latency-based-routing
  cooldown_time: 30

不需要 V1 模式(allowed_fails_policy),latency-based 已经用统计学方式自然避让。


5. 推荐配置:按场景

5.1 ⭐ 你们 prod 推荐

litellm_settings:
  num_retries: 2

router_settings:
  routing_strategy: latency-based-routing
  cooldown_time: 30                  # 5 → 30,失败 deployment 30s 内不再被选
  # disable_cooldowns: false          # 默认 false,不要碰
  # allowed_fails / allowed_fails_policy: 不需要,latency-based 已经够用

理由: - 你们 model_group 通常多 deployment(多 region/key 负载均衡),cooldown 30s 足够规避故障 - latency-based 自然避让慢的,cooldown 是兜底 - 不开 V1 累计计数模式,避免 InMemoryCache 的多 Pod 状态不一致问题(详见 04 §4)

5.2 单 deployment 服务(仅 1 个 deployment 的 model_group)

router_settings:
  cooldown_time: 60
  # 这种情况 V2 路径 1.1 / 1.3 都不会触发(is_single_deployment_model_group=True),
  # 只有路径 1.2 (高流量 + 100% 失败) 和路径 1.4 (永久错误) 会触发

代价:单 deployment 抽风时 cooldown 不会立即触发,等真的"完全挂"才冷。这是上游设计——单 deployment 一旦冷就没人服务了。

5.3 高 SLA 业务(不允许任何 deployment 冷掉)

router_settings:
  disable_cooldowns: true            # 完全禁用 cooldown
  routing_strategy: latency-based-routing  # 完全靠 latency 避让

litellm_settings:
  num_retries: 5                     # 增加 retry,业务方"看到"的失败率最低
  request_timeout: 30                # 短超时,失败的 deployment 快速判失败

⚠️ 这种配置下 cooldown 完全失效,靠 latency-based + retry 兜底。代价是失败的 deployment 仍可能被选中(直到 latency 累计够高),prod 监控指标会比有 cooldown 时更差看。不推荐

5.4 调试 / 排障场景

router_settings:
  disable_cooldowns: true

dev 时关掉 cooldown 方便复现"为什么这个 deployment 总是被选不中"——可能就是 cooldown 在工作。


6. 常见误区

6.1 ❌ "我设了 cooldown_time=300,超过 5 分钟自动恢复"

对错各半cooldown_time=300 是单次失败后冷却 300 秒,过期会自动恢复(恢复后下一次请求又可能命中、再失败、再 cooldown 300)。不是"5 分钟内不再尝试"

如果你想"上游恢复了再让该 deployment 进备选",需要的是主动探活机制——LiteLLM 没有原生提供。要么: - 用 health check 配合手动 cooldown 操作(自己加 callback) - 接受周期性"试探失败"

6.2 ❌ "心跳失败会触发 cooldown"

不会。心跳是观测,cooldown 是路由决策,完全独立。详见 04 §5.

6.3 ❌ "成功一次会清零 allowed_fails 计数"

不会。failed_calls 计数器仅靠 TTL 过期清零。每次失败时刷新 TTL(保持 cooldown_time 时长),成功不动它

如果你期望"刚成功一次说明可能恢复了,应该重置失败计数"——LiteLLM 没这个语义。cooldown_time 时长内不再有失败 → 计数器自然消失。

6.4 ❌ "把 cooldown_time 设很大就更安全"

也不一定。设很大的代价: - 偶发抽风(某次请求恰好命中 retry 都没救活的 deployment)会让该 deployment 冷却很久,期间真实流量被挤到其他 deployment - 如果 model_group 内健康 deployment 不多,可能造成热点 deployment 过载

合理范围:30-300。不要无脑设大

6.5 ❌ "Single deployment model group 的 cooldown 跟 multi 一样"

完全不一样。代码 _should_cooldown_deployment:193-194:

is_single_deployment_model_group = (
    model_group is not None and len(model_group) == 1
)

后续多个分支判断 not is_single_deployment_model_group,意味着: - 路径 1.1(429 立即冷)—— single 不触发 - 路径 1.3(失败率 50%)—— single 不触发 - 路径 1.2(100% 失败 + 流量 1000)—— single 唯一会触发的"统计"路径 - 路径 1.4(永久错误码)—— single 也触发

单 deployment 的 cooldown 触发条件比多 deployment 严格得多。这是设计——单 deployment 一旦冷就没人服务,更保守。详见 04 §2.


7. cooldown 调优 checklist

调任何 cooldown 配置前,先问自己:

  • [ ] 我的 model_group 有几个 deployment?1 个跟多个的 cooldown 行为完全不同
  • [ ] 我有多少个 Pod?V1 allowed_fails 模式下多 Pod 计数不共享
  • [ ] 我的 QPS 多少?太低会让路径 1.3(失败率)触发不到
  • [ ] 我用什么 routing_strategy?latency-based 自带避让,cooldown 设激进点 OK
  • [ ] 我希望"激进避让"还是"宽容容错"?前者短 cooldown,后者长 + allowed_fails
  • [ ] 我有 fallbacks 配置吗?fallback 链上每段独立 cooldown
  • [ ] 我希望失败的 deployment 自动恢复吗?没有原生主动探活,靠 TTL + 真实请求探测

下一步