You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
exec${PAGER:-/usr/bin/less}"$0"||exit 1
Executing tests from //trpc/overload_control/flow_control:smooth_limiter_test
-----------------------------------------------------------------------------
Running main() from gmock_main.cc
[==========] Running 3 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 1 test from SmoothLimiter
[ RUN ] SmoothLimiter.Contruct
[ OK ] SmoothLimiter.Contruct (30 ms)
[----------] 1 test from SmoothLimiter (30 ms total)
[----------] 2 tests from SmoothLimiterTest
[ RUN ] SmoothLimiterTest.CheckLimit
[ OK ] SmoothLimiterTest.CheckLimit (1007 ms)
[ RUN ] SmoothLimiterTest.Overload
trpc/overload_control/flow_control/smooth_limiter_test.cc:75: Failure
Expected equality of these values:
smooth_limiter_->GetCurrCounter()
Which is: 3
0
[ FAILED ] SmoothLimiterTest.Overload (1006 ms)
[----------] 2 tests from SmoothLimiterTest (2013 ms total)
[----------] Global test environment tear-down
[==========] 3 tests from 2 test suites ran. (2044 ms total)
[ PASSED ] 2 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] SmoothLimiterTest.Overload
1 FAILED TEST
int64_tHitQueue::ActiveSum() const {
constint begin = window_begin_.load(std::memory_order_acquire);
constint end = (begin + WindowSize()) % frame_hits_.size();
int64_t sum = 0;
for (int i = begin; i != end; i = NextIndex(i)) {
sum += frame_hits_.at(i).load(std::memory_order_acquire);
}
return sum;
}
The text was updated successfully, but these errors were encountered:
问题发现与测试用例补充
在对应 issue #144 (目前已关闭)的时候,我发现了滑动窗口流量控制存在窗口更新不及时的问题。
发现问题的具体代码在这个 branch:
https://github.com/f1akeee/trpc-cpp/tree/sliding_window_limiter_test
(仅据参考,直接看下面的 case即可)
稍加整理,设计出一个 adversary case 😈
相关单元测试用例:
单元测试说明:
单元测试中的 smooth_limiter_ 滑窗对象配置为每秒允许通过3个请求。故而对于1秒内的5个请求,前3个请求是准许通过的,后两个请求应该被拒绝。1秒过后,滑窗应该更新,对于新到的5个请求,应该也是通过3个,拒绝两个。
实际测试结果:
在 1000ms(1s)后,smooth_limiter_ 的当前窗口的活跃连接数依然为 3。
trpc::smooth_limiter 目前的机制
将单位时间 1S 分为 N 个部分,每一个部分称为1帧(frame),默认配置的 fps 为100,即每10ms 为一帧。帧和秒的关系,类比于现实中秒和分钟、分钟和小时的关系,只不过是进制单位不同,帧与秒采用百进制。类比时钟,不难想到用 ringbuffer,实际上,trpc 也是这样实现的。其中 ringbuffer 中每个 slot 对某一帧的计数器,对 ringbuffer 的 slot 计数器求和,即可得到 1s 的有效请求计数。引入外部定时器,用于驱动帧的“滴答”切换。
这是一个符合滑动窗口定义的朴素实现。下面分析一下这个朴素实现存在的问题🤔
机制问题分析
精度问题
使用“分帧分边沿”的滑动窗口的计算精度跟帧的大小有关:
极限状态下,将 fps 设置为1后退化为固定窗口算法(无法处理窗口边沿点的突发流量)
滑动窗口的左右边沿帧可能存在误 reject 的情况(如之前的问题描述),简单的画个图描述如下,其中数字表示帧计数器的值,绿色表示通过,红色表示拒绝:
效率问题
引入外部定时器线程
对于每个请求都要做 HitQueue::ActiveSum(),这是一个 O(n) 的运算。(其实,针对 这个 O(n) 的处理可以用前缀和的方式进行优化,优化后 ActiveSum() 可以降到 O(1),数据类型使用 uint64_t,当 uint64_t 耗尽的时候可以利用减法下溢的特性得到正确的结果)
The text was updated successfully, but these errors were encountered: