#rate-limiting #rate #limiting #limit #throttling #throttle

nenya

Rust 适应性速率限制和 PID 控制器crate

2 个版本

0.0.2 2024 年 5 月 30 日
0.0.1 2024 年 5 月 25 日

#2 in #throttling

Download history 271/week @ 2024-05-24 44/week @ 2024-05-31 7/week @ 2024-06-07 3/week @ 2024-06-14 1/week @ 2024-06-28 4/week @ 2024-07-05

每月 64 次下载

MIT 许可证

38KB
642

尼娜

尼娜 是一个使用比例-积分-微分(PID)控制器的适应性速率限制器。该项目包含两个主要组件

  • 尼娜:一个用于适应性速率限制的 Rust crate。
  • 尼娜哨兵:一个独立的速率限制 gRPC 服务,旨在作为现有服务的边车运行。

概述

尼娜

尼娜是一个 Rust crate,它使用 PID 控制器提供适应性速率限制功能。该 crate 旨在提供一种动态高效的方式来管理请求数率,使其适用于高吞吐量服务。

功能

  • PID 控制器:使用高度可配置的比例-积分-微分(PID)控制器,根据当前流量模式动态调整速率限制
  • 可配置的滑动窗口:使用可配置的滑动窗口确定每秒事务数(TPS),确保准确的速率限制决策
  • 配置:允许微调 PID 参数(kpkikd)、错误限制、输出限制和更新间隔

尼娜哨兵(进行中)

尼娜哨兵是一个独立的速率限制服务,将支持 gRPC,以便作为微服务架构中的边车轻松集成。

入门

要开始使用尼娜,将其添加到您的 Cargo.toml 中

[dependencies]
nenya = "0.0.2"

示例

具有静态设置点的基本速率限制器

use nenya::RateLimiterBuilder;
use nenya::pid_controller::PIDControllerBuilder;
use std::time::Duration;

fn main() {
    // Create a rate limiter
    let mut rate_limiter = RateLimiterBuilder::new(10.0)
        .update_interval(Duration::from_secs(1))
        .build();

    // Simulate request processing and check if throttling is necessary
    for _ in 0..20 {
        if rate_limiter.should_throttle() {
            println!("Request throttled");
        } else {
            println!("Request accepted");
        }
    }
}

使用 PID 控制器的动态速率限制器

use nenya::RateLimiterBuilder;
use nenya::pid_controller::PIDControllerBuilder;
use std::time::Duration;

fn main() {
    // Create a PID controller with specific parameters
    let pid_controller = PIDControllerBuilder::new(10.0)
        .kp(1.0)
        .ki(0.1)
        .kd(0.01)
        .build();

    // Create a rate limiter using the PID Controller
    let mut rate_limiter = RateLimiterBuilder::new(10.0)
        .min_rate(5.0)
        .max_rate(15.0)
        .pid_controller(pid_controller)
        .update_interval(Duration::from_secs(1))
        .build();

    // Simulate request processing and check if throttling is necessary
    for _ in 0..20 {
        if rate_limiter.should_throttle() {
            println!("Request throttled");
        } else {
            println!("Request accepted");
        }
    }
}

请求模拟器

尼娜包括一个请求模拟示例,用于测试和调整。您可以使用以下命令运行模拟

cargo run --example request_simulator_plot -- \
    --target_tps 80.0 \
    --min_tps 75.0 \
    --max_tps 100.0 \
    --trailing_window 1 \
    --duration 120 \
    --base_tps 80.0 \
    --amplitudes 20.0,7.0,10.0 \
    --frequencies 0.05,2.8,4.0 \
    --kp 0.8 \
    --ki 0.05 \
    --kd 0.04 \
    --error_limit 10.0 \
    --output_limit 3.0 \
    --update_interval 500 \
    --error_bias 0.0

大多数这些参数都有合理的默认值,可以省略。有关更多详细信息,请参阅

cargo run --example request_simulator_plot -- --help

适应性速率限制

速率限制器通过使用比例-积分-微分(PID)控制器实现适应性速率限制,该控制器根据请求速率确定目标速率限制。此实现包括误差偏差、累积误差夹断、反饱和反馈和输出夹断。

概述

  1. 错误计算:误差是通过从设置点减去请求速率来计算的。
  2. 比例项:比例项是比例增益和误差的乘积。
  3. 误差偏差:误差通过偏差因子进行调整,如果 $B > 0$ 则对正误差反应更强烈,如果 $B < 0$ 则对负误差反应更强烈。
  4. 积分项:积分项是随时间累积的错误,通过钳位来防止积分饱和。
  5. 微分项:微分项是误差变化的速率。
  6. 原始校正:原始校正是指P、I和D项的总和。
  7. 输出钳位:输出被钳位到一个指定的限制,以防止过度的校正。
  8. 抗饱和反馈:如果发生钳位,累积错误会被调整以防止积分饱和。
  9. 最终输出:钳位校正是PID控制器的最终输出。
  10. 请求限制调整:钳位校正被添加到当前请求限制中,以推导出新的请求限制。

1. 错误计算

误差 $e(t)$ 是通过设定点 $S$ 和请求率 $r(t)$ 的差值来计算的

e(t) = S - r(t)

2. 比例项 (P)

比例项 $P(t)$ 是使用比例增益 $K_p$ 计算的

P(t) = K_p \cdot e(t)

3. 错误偏置

通过偏置 $B$ 调整错误,以更积极地响应正负误差

\text{biased\_error}(t) =
\begin{cases}
e(t) \cdot (1 + B) & \text{if } e(t) > 0 \\
e(t) \cdot (1 - B) & \text{if } e(t) \leq 0
\end{cases}

4. 积分项 (I)

累积误差 $E(t)$ 被钳位以防止积分饱和

E(t) = \text{clamp}\left( E(t-1) + \text{biased\_error}(t), -L, L \right)

其中 $L$ 是误差限制。

积分项 $I(t)$ 然后是

I(t) = K_i \cdot E(t)

5. 微分项 (D)

微分项 $D(t)$ 是使用微分增益 $K_d$ 和误差变化率来计算的

D(t) = K_d \cdot \frac{d e(t)}{dt}

对于离散的时间步长,这可以近似为

D(t) = K_d \cdot \left( e(t) - e(t-1) \right)

6. 原始校正

原始校正 $u(t)$ 是比例、积分和微分项的总和

u(t) = P(t) + I(t) + D(t)

7. 输出钳位

输出校正被钳位以防止过度的输出

u_{\text{clamped}}(t) = \text{clamp}(u(t), -M, M)

其中 $M$ 是输出限制。

8. 抗饱和反馈

如果校正被钳位,累积误差 $E(t)$ 被调整以防止积分饱和

\text{if } u(t) \neq u_{\text{clamped}}(t) \text{ then } E(t) = E(t) - \frac{u(t) - u_{\text{clamped}}(t)}{K_i}

9. 最终输出

PID控制器的最终输出是

u_{\text{clamped}}(t)

10. 请求限制调整

输出被添加到当前请求限制 $R(t-1)$ 中,以推导出新的请求限制 $R(t)$

R(t) = R(t-1) + u_{\text{clamped}}(t)

许可证

本项目受MIT许可证许可。有关详细信息,请参阅LICENSE 文件。

依赖关系

~240KB