Skip to content

[Feature Request] 为 backup request 增加比例限制机制 #3228

@feng-y

Description

@feng-y

Is your feature request related to a problem?

使用 backup request 时,如果下游服务出现短暂延迟抖动,可能在短时间内触发大量 backup 请求,额外增加下游负载,加剧抖动。

目前 BackupRequestPolicy 提供了 DoBackup() 接口供用户自行决策,但框架没有提供开箱即用的比例控制实现。用户需要自行处理滑动窗口统计和线程安全。

Describe the solution you'd like

新增内置的 RateLimitedBackupPolicy,限制滑动窗口内 backup 请求占总请求的比例。

核心设计:

  • 复用 bvar::Adder + bvar::Window 做滑动窗口统计(lock-free 写入,与 auto_cl_* 系列一致的 bvar 技术栈)
  • OnRPCEnd() 累加 total 计数,DoBackup() 返回 true 时累加 backup 计数
  • ratio 缓存到 atomic<double>,每 update_interval 秒重算一次,DoBackup() 热路径只做 1 个 atomic load
  • 超比例时 DoBackup() 返回 false,跳过本次 backup
  • 冷启动(窗口内 total == 0)时允许 backup

为什么选 bvar::Window 而非系统已有的固定窗口/EMA:

  • 固定窗口(如 AutoConcurrencyLimiter 的 SampleWindow):窗口到期清零重置时 total=0,ratio 失效,所有 backup 被放行——这正是我们要防止的毛刺。AutoConcurrencyLimiter 能用固定窗口是因为它只在窗口提交时观测延迟调整并发上限,毛刺只影响观测精度;而 backup 比例控制的毛刺直接导致冗余流量打到下游。
  • EMA(如 CircuitBreaker 的 EmaErrorRecorder):EMA 值不等于真实的"窗口内 backup/total"比例,对用户来说"设了 5% 但实际含义不直观",配置和调试困难。
  • bvar::Window:滑动窗口无重置毛刺;ratio 语义精确(用户设 5% 就是 5%);写入 lock-free;通过缓存 ratio 读取也是 lock-free。

配置方式(沿用 gflags 风格):

DEFINE_double(backup_request_max_ratio, -1,
              "Max ratio of backup requests to total requests. "
              "Valid range: (0, 1]. -1 (default) disables ratio limiting. "
              "e.g. 0.05: at most 5% of requests will trigger backup.");

DEFINE_int32(backup_request_ratio_window_size_s, 10,
             "Sliding window size in seconds for calculating backup request ratio.");

DEFINE_int32(backup_request_ratio_update_interval_s, 5,
             "Interval in seconds for recalculating backup request ratio.");

同时在 ChannelOptions 中增加 backup_request_max_ratio 字段供 per-channel 覆盖。

默认 -1,完全向后兼容。

用法示例:

// 方式 1:gflags
--backup_request_max_ratio=0.05

// 方式 2:per-channel
brpc::ChannelOptions options;
options.backup_request_ms = 100;
options.backup_request_max_ratio = 0.05;
channel.Init("http://...", &options);

Describe alternatives you've considered

  1. 固定窗口 + atomic 计数器(AutoConcurrencyLimiter 风格):窗口重置时 ratio 失效,backup 全放行产生毛刺
  2. EMA(CircuitBreaker 风格):ratio 语义不直观,用户难以理解和调试
  3. 概率性降级:更平滑但无法硬保证比例

Additional context

  • 文件变更范围:backup_request_policy.h/cppchannel.h/cpp、测试
  • 性能:DoBackup() 热路径 1 个 atomic load,bvar::Window 读取每 N 秒一次,高 QPS 下无竞争
  • 详细设计文档见 PR

如果方向没问题,我可以提交 PR 实现。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions