-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add BurstingRateLimiter for simulating super-bursty traffic. #14
Conversation
Introduces a new `--burst-size` option. Implemented via `BurstingRateLimiter`, which accumulates acquisitions by the underlying configured `RateLimiter`, and starts releasing when the burst-size threshold is met. For example, `--burst-size 100 --rps 1000` will make the client release 100 requests every 100 milliseconds. Signed-off-by: Otto van der Schaaf <[email protected]>
Signed-off-by: Otto van der Schaaf <[email protected]>
463060a
to
4af229d
Compare
Rebased to master and squashed. Has an extra commit to fix the build that broke after the rebase:
Force pushed the squashed version, but I'm leaving a note here to make sure I don't forget about the earlier ASAN failure in CI: May need tweaking the coverage threshold in here, it may err because it didn't consider the test origin when I adjusted it earlier. /assign @htuch |
It looks like the hack to avoid runtime conflicts in the integration test for the client came back to haunt us :( |
Reading the code, there's a comment in the |
I think we should land #15 first, and then rebase this. |
Signed-off-by: Otto van der Schaaf <[email protected]>
Note: just merged master into this, which should clean up the diff now that #15 was merged over there. |
@oschaaf can you merge master again? Thanks |
…iter Signed-off-by: Otto van der Schaaf <[email protected]>
@htuch done, merged master |
Signed-off-by: Otto van der Schaaf <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good modulo a few comments.
/wait
@@ -32,7 +32,7 @@ if [ "$VALIDATE_COVERAGE" == "true" ] | |||
then | |||
COVERAGE_VALUE=$(grep -Po '.*lines[.]*: \K(\d|\.)*' "${COVERAGE_SUMMARY}") | |||
# TODO(oschaaf): The target is 97.5%, so up this whenever possible in follow ups. | |||
COVERAGE_THRESHOLD=96.6 | |||
COVERAGE_THRESHOLD=96.8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huzzah!
// the system is lagging behind. | ||
while (rate_limiter_->tryAcquireOne()) { | ||
accumulated_++; | ||
if ((accumulated_ % burst_size_) == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of %
here together with both ++ on release and acquire is clever; it took me a minute to grok though, could you add a comment or two?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
source/common/rate_limiter_impl.cc
Outdated
accumulated_++; | ||
ASSERT(accumulated_ <= burst_size_); | ||
} else { | ||
rate_limiter_->releaseOne(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it ever possible to execute this line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, good point, this didn't make sense. I tightened this up.
* 1. First it will be accumulating acquisitions by forwarding calls to the wrapped | ||
* rate limiter, until the accumulated acquisitions equals the specified burst size. | ||
* 2. Release mode. In this mode, BatchingRateLimiter is in control and will be handling | ||
* acquisition calls (returning true and substracting from the accumulated total until |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It cleverly uses increment to subtract! :)
test/rate_limiter_test.cc
Outdated
EXPECT_CALL(unsafe_mock_rate_limiter, tryAcquireOne) | ||
.Times(burst_size) | ||
.WillRepeatedly(Return(true)) | ||
.RetiresOnSaturation(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is RetireOnSaturation
? Is this effectively the same as InSequence
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, InSequence
specifies the intent here more clearly and is more compact, so I switched it over to use that.
Signed-off-by: Otto van der Schaaf <[email protected]>
Signed-off-by: Otto van der Schaaf <[email protected]>
@htuch this is ready for another round |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/wait
void BurstingRateLimiter::releaseOne() { | ||
ASSERT(accumulated_ < burst_size_); | ||
ASSERT(previously_releasing_ != absl::nullopt && previously_releasing_ == true); | ||
// The caller wasn't able to put its earlier successfull acquisition to good use, so we restore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, this is actually different to what I thought you were doing. I thought you were doing:
- During acquisition, keep increasing accumulated until % burst_size == 0.
- During release, keep increasing accumulated until % burst_size ==0.
If you ++ and --, won't you run the risk of getting non-bursty behavior when released tokens get immediately reacquired and a thread spends a long period without requesting a burst?
@@ -41,6 +41,10 @@ SequencerPtr SequencerFactoryImpl::create(Envoy::TimeSource& time_source, | |||
StatisticFactoryImpl statistic_factory(options_); | |||
RateLimiterPtr rate_limiter = | |||
std::make_unique<LinearRateLimiter>(time_source, Frequency(options_.requestsPerSecond())); | |||
const uint64_t burst_size = options_.burstSize(); | |||
if (burst_size) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: prefer burst_size > 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarified points offline, thanks, will merge.
Introduces a new
--burst-size
option. Implemented viaBurstingRateLimiter
, which accumulates acquisitions by the underlying configuredRateLimiter
, and starts releasing when the burst-size threshold is met. For example,--burst-size 100 --rps 1000
will make the client release 100 requests every 100 milliseconds.Signed-off-by: Otto van der Schaaf [email protected]