上游来源
Nexus 目标
将 QuantumNous#1730 拆成可被上游接受的、与现有渠道选择器兼容的渠道级准入控制,并在上游提交完整 PR。目标不是直接引入现有候选 PR,而是重新实现可靠的 RPM 与并发预留。
每个渠道新增两个可选限制:
max_concurrency:渠道同时在途的上游请求数;0 或缺省表示不限。
rpm_limit:渠道每分钟允许开始的上游请求数;0 或缺省表示不限。
限制按渠道聚合,多 Key 渠道的初版语义为所有 Key 共享渠道总额度。现有优先级、权重、分组、auto group 和渠道亲和仍然有效。
必须满足的路由语义
- 在发送上游请求前完成原子准入和容量预留。
- 候选渠道达到任一上限时,从当前优先级的剩余候选中重新选择;满载跳过不消耗上游重试次数,也不记录为上游错误。
- 当前优先级全部满载后,才进入下一优先级或下一自动分组。
- 所有候选都无法准入时,直接返回稳定的本地容量错误和
Retry-After,不得先发请求再等待上游 429。
- 绑定/亲和到固定渠道的请求不能悄悄改道;固定渠道满载时返回本地限流错误。
- 并发租约必须覆盖整个上游响应生命周期,包括流式响应、取消、错误、超时和重试切换;所有退出路径都必须释放。
- RPM 额度在请求被接纳后不回退;并发槽位在请求结束后释放。
- 配置热更新必须对新请求生效,不能把旧的容量永久保留在进程内。
- 在 Redis 可用的多实例部署中提供全局渠道语义;无 Redis 时明确降级为单实例语义并可观测。
- 本期不引入排队,排队应作为独立需求处理,避免队头阻塞和请求取消语义混入准入控制。
建议实现边界
- 抽取独立的 channel admission/lease 接口,由渠道选择器在候选选择阶段调用。
- Redis 路径使用原子脚本或等价原子操作,同时完成 RPM 检查和并发租约预留,避免“先探测、后占位”的竞态。
- 并发租约带唯一 attempt ID 和过期保护;长流需要续租,进程崩溃后租约自动失效。
- 内存实现仅作为无 Redis 的单实例 fallback,不宣称跨节点全局限制。
- 未配置限制的渠道保持现有性能路径,不能因为新增能力为每次请求增加无意义的数据库查询。
- 渠道配置优先复用
ChannelSettings,默认值保持向后兼容,不新增生产数据迁移要求。
- 准入拒绝、当前占用、RPM 消耗和释放异常应提供后续可观测性所需的计数接口,但不把本 issue 扩展成完整监控页面。
相关实现与不直接引入的原因
这些实现可作为参考和 review 背景,但不直接 cherry-pick 当前 head。
验收条件
跟踪计划
上游来源
功能请求:渠道速率限制与并发控制功能upstream/main@cfaba1dd6754d4238e1360247c198a64a313e96cNexus 目标
将 QuantumNous#1730 拆成可被上游接受的、与现有渠道选择器兼容的渠道级准入控制,并在上游提交完整 PR。目标不是直接引入现有候选 PR,而是重新实现可靠的 RPM 与并发预留。
每个渠道新增两个可选限制:
max_concurrency:渠道同时在途的上游请求数;0或缺省表示不限。rpm_limit:渠道每分钟允许开始的上游请求数;0或缺省表示不限。限制按渠道聚合,多 Key 渠道的初版语义为所有 Key 共享渠道总额度。现有优先级、权重、分组、auto group 和渠道亲和仍然有效。
必须满足的路由语义
Retry-After,不得先发请求再等待上游 429。建议实现边界
ChannelSettings,默认值保持向后兼容,不新增生产数据迁移要求。相关实现与不直接引入的原因
这些实现可作为参考和 review 背景,但不直接 cherry-pick 当前 head。
验收条件
nexus补丁栈中移除等价本地补丁;在此之前 Nexus 使用独立、可回放的本地补丁。跟踪计划
main重新实现并发/RPM 准入nexus以独立线性补丁回放最终实现