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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions