-
Notifications
You must be signed in to change notification settings - Fork 6.3k
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 rate-limiting support to batched MultiGet() #10159
Conversation
d249c8c
to
48a1611
Compare
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.
LGTM, thanks!
file/random_access_file_reader.cc
Outdated
assert(rate_limiter != nullptr); | ||
size_t remaining_bytes = total_bytes_to_request; | ||
size_t request_bytes = 0; | ||
while (remaining_bytes > 0) { | ||
request_bytes = std::min( | ||
static_cast<size_t>(rate_limiter->GetSingleBurstBytes()), | ||
remaining_bytes); | ||
rate_limiter->Request(request_bytes, pri, stats, op_type); | ||
remaining_bytes -= request_bytes; | ||
} |
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.
This doesn't need to be executed via a function object, does it?
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.
Hmmm - I think it's still thru function object under the hood. Actually I wanted to reach out for help on this and the PR here is just a WIP.
My goal is to encapsulate the helper function LoopRateLimitRequestHelper
within this particular function ::MultiRead()
to minimize its usage as much as possible (as you can see from our plan of deprecating BackupEngineImpl::LoopRateLimitRequestHelper
).
So I am trying something like local (so that it can't be called outside of this function) static (so that we only have one copy) anonymous function. According the website title, "Lambda expressions - Constructs a closure: an unnamed function object capable of capturing variables in scope.", I think a function object is still constructed.
I am not sure if this is the best practice to achieve my goal though so let me know if you see alternatives!
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.
I'd delete line 369-372 and line 383-386, and then fixup the undefined variables.
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.
Okay - so basically just remove the function abstraction - I can do that too.
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.
Fixed
file/random_access_file_reader.cc
Outdated
// TODO: ideally we should request bandwith for each | ||
// `FSReadRequest::len` seperately instead of requesting | ||
// the sum and calling `LoopRateLimitRequestHelper()` afterwards |
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.
I am not sure the TODO describes a goal that is better than what's here already. One possible goal would be looping: RequestToken()
followed by MultiRead()
with as many requests as possible to consume the bytes granted by the rate limiter.
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.
RequestToken() followed by MultiRead() with as many requests as possible to consume the bytes granted by the rate limiter.
Will reach out offline for more clarification.
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.
Fixed.
ef8d321
to
c686056
Compare
Hi @anand1976, @ajkr - I know crash test wrapper does not use rate-limiting yet but I want to at least cover "new MultiGet + rate-limiting" in For that, I want to invoke |
Try this command. I built it incrementally but maybe the key piece is just the cache_size (apparently the default for db_stress is 2GB!)
|
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
Thanks - indeed a smaller cache is what I needed for db_stress! However, this still doesn't work for triggering multiget under
|
@hx235 has updated the pull request. You must reimport the pull request before landing. |
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
HISTORY.md
Outdated
@@ -32,6 +32,7 @@ | |||
* Add a new column family option `blob_file_starting_level` to enable writing blob files during flushes and compactions starting from the specified LSM tree level. | |||
* Add support for timestamped snapshots (#9879) | |||
* Provide support for AbortIO in posix to cancel submitted asynchronous requests using io_uring. | |||
* Add support for rate-limiting new void-returning `MultiGet()` APIs |
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.
I suggest calling them batched MultiGet() APIs rather than new.
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.
Will update all such reference.
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.
Fixed
3dbba60
to
2ca9659
Compare
@hx235 has updated the pull request. You must reimport the pull request before landing. |
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
Will merge this after signals are clear |
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
1 similar comment
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
@hx235 has updated the pull request. You must reimport the pull request before landing. |
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
ca744ee
to
6f06366
Compare
@hx235 has updated the pull request. You must reimport the pull request before landing. |
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
6f06366
to
d75dd3b
Compare
@hx235 has updated the pull request. You must reimport the pull request before landing. |
@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
Context/Summary:
#9424 added rate-limiting support for user reads, which does not include batched
MultiGet()
s that callRandomAccessFileReader::MultiRead()
. The reason is that it's harder (compared with RandomAccessFileReader::Read()) to implement the ideal rate-limiting where we first callRateLimiter::RequestToken()
for allowed bytes to multi-read and then consume those bytes by satisfying as many requests inMultiRead()
as possible. For example, it can be tricky to decide whether we want partially fulfilled requests within oneMultiRead()
or not.However, due to a recent urgent user request, we decide to pursue an elementary (but a conditionally ineffective) solution where we accumulate enough rate limiter requests toward the total bytes needed by one
MultiRead()
before doing thatMultiRead()
. This is not ideal when the total bytes are huge as we will actually consume a huge bandwidth from rate-limiter causing a burst on disk. This is not what we ultimately want with rate limiter. Therefore a follow-up work is noted through TODO comments.Test:
DBRateLimiterOnReadTest/DBRateLimiterOnReadTest.NewMultiGet
io_uring_enter
and verified they are 10 seconds apart from each other correctly under the setting ofstrace -ftt -e trace=io_uring_enter ./db_bench -benchmarks=multireadrandom -db=/dev/shm/testdb2 -readonly -num=50 -threads=1 -multiread_batched=1 -batch_size=100 -duration=10 -rate_limiter_bytes_per_sec=200 -rate_limiter_refill_period_us=1000000 -rate_limit_bg_reads=1 -disable_auto_compactions=1 -rate_limit_user_ops=1
where eachMultiRead()
read about 2000 bytes (inspected by debugger) and the rate limiter grants 200 bytes per seconds../db_stress (-test_cf_consistency=1/test_batches_snapshots=1) -use_multiget=1 -cache_size=1048576 -rate_limiter_bytes_per_sec=10241024 -rate_limit_bg_reads=1 -rate_limit_user_ops=1
work