Skip to content
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

Rate Limit ScanStatistics #2779

Merged
merged 1 commit into from
Aug 7, 2023
Merged

Conversation

raggar
Copy link
Contributor

@raggar raggar commented Jul 31, 2023

This pull request uses a TokenBucket to limit the number of keys that
read from ScanStatistics within a certain period of time.

Changes rely on #2713

Fixes: #2778

@cockroach-teamcity
Copy link
Member

This change is Reviewable

@raggar raggar changed the title Rahul rate limit Rate Limit Scan Statistics Jul 31, 2023
@raggar raggar changed the title Rate Limit Scan Statistics Rate Limit ScanStatistics Jul 31, 2023
db.go Outdated
@@ -2604,9 +2605,21 @@ type LSMKeyStatistics struct {
func (d *DB) ScanStatistics(ctx context.Context, lower, upper []byte) (LSMKeyStatistics, error) {
stats := LSMKeyStatistics{}
var prevKey InternalKey
tb := tokenbucket.TokenBucket{}
tb.Init(50, 50)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what values to put here (I just put placeholders for now)

Copy link
Member

@RaduBerinde RaduBerinde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 3 unresolved discussions (waiting on @jbowens and @RahulAggarwal1016)


db.go line 2605 at r3 (raw file):

// ScanStatistics returns the count of different key kinds within the lsm for a
// key span [lower, upper) as well as the number of snapshot keys.
func (d *DB) ScanStatistics(ctx context.Context, lower, upper []byte) (LSMKeyStatistics, error) {

Perhaps in a separate change, it would be nice if we could make this stop if the context is cancelled
Not sure if we want ScanInternal to do that in general (CC @itsbilal), if not we can just try to poll ctx.Done() in each callback.

That would make it possible to interrupt the query and stop the scan, which would be useful if we accidentally passed in a very big key range.


db.go line 2609 at r3 (raw file):

Previously, RahulAggarwal1016 (Rahul Aggarwal) wrote…

Not sure what values to put here (I just put placeholders for now)

@jbowens maybe has an idea of how many keys per second would not be a problem for most deployments. If I had to guess, on the order of 100K to 1M keys per second?


db.go line 2612 at r3 (raw file):

	rateLimit := func() {
		fulfilled, tryAgainAfter := tb.TryToFulfill(1)

This needs to be done in a loop

Copy link
Collaborator

@jbowens jbowens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 3 unresolved discussions (waiting on @jbowens, @RaduBerinde, and @RahulAggarwal1016)


db.go line 2609 at r3 (raw file):

Previously, RaduBerinde wrote…

@jbowens maybe has an idea of how many keys per second would not be a problem for most deployments. If I had to guess, on the order of 100K to 1M keys per second?

I think we should rate limit on InternalKey.Size()+lazyValue.Len() so that we limit the read bandwidth. Also, I think the rate should be passed in by the user (and maybe even through the SQL builtin).

Copy link
Contributor Author

@raggar raggar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 3 unresolved discussions (waiting on @jbowens and @RaduBerinde)


db.go line 2609 at r3 (raw file):

Previously, jbowens (Jackson Owens) wrote…

I think we should rate limit on InternalKey.Size()+lazyValue.Len() so that we limit the read bandwidth. Also, I think the rate should be passed in by the user (and maybe even through the SQL builtin).

for limiting based on size, what should a reasonable value for the rate and burst be (to also use in tests)?

@raggar raggar force-pushed the rahul_rate_limit branch 2 times, most recently from 48f54ca to 2b8c8b5 Compare August 1, 2023 14:18
Copy link
Member

@RaduBerinde RaduBerinde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 6 unresolved discussions (waiting on @jbowens and @RahulAggarwal1016)


db.go line 2678 at r5 (raw file):

type ScanStatisticsOptions struct {
	rateLimitEnabled bool
	rate             float64

I'd change to LimitBytesPerSecond int64. 0 could mean no limit.


db.go line 2690 at r5 (raw file):

	var prevKey InternalKey
	tb := tokenbucket.TokenBucket{}
	tb.Init(tokenbucket.TokensPerSecond(opts.rate), tokenbucket.Tokens(opts.burst))

I don't think "burst" needs to be configurable, we can just hardcode it to something like 1024 bytes.


db.go line 2690 at r5 (raw file):

	var prevKey InternalKey
	tb := tokenbucket.TokenBucket{}
	tb.Init(tokenbucket.TokensPerSecond(opts.rate), tokenbucket.Tokens(opts.burst))

Add a comment explaining that each "token" (roughly) corresponds to a byte that was read.

@raggar raggar force-pushed the rahul_rate_limit branch 2 times, most recently from 23e78ec to e6c0bb3 Compare August 2, 2023 14:33
Copy link
Contributor Author

@raggar raggar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 6 unresolved discussions (waiting on @jbowens and @RaduBerinde)


db.go line 2612 at r3 (raw file):

Previously, RaduBerinde wrote…

This needs to be done in a loop

fixed!


db.go line 2678 at r5 (raw file):

Previously, RaduBerinde wrote…

I'd change to LimitBytesPerSecond int64. 0 could mean no limit.

fixed!


db.go line 2690 at r5 (raw file):

Previously, RaduBerinde wrote…

I don't think "burst" needs to be configurable, we can just hardcode it to something like 1024 bytes.

fixed!


db.go line 2690 at r5 (raw file):

Previously, RaduBerinde wrote…

Add a comment explaining that each "token" (roughly) corresponds to a byte that was read.

fixed!

Copy link
Contributor Author

@raggar raggar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 6 unresolved discussions (waiting on @itsbilal, @jbowens, and @RaduBerinde)


db.go line 2605 at r3 (raw file):

Previously, RaduBerinde wrote…

Perhaps in a separate change, it would be nice if we could make this stop if the context is cancelled
Not sure if we want ScanInternal to do that in general (CC @itsbilal), if not we can just try to poll ctx.Done() in each callback.

That would make it possible to interrupt the query and stop the scan, which would be useful if we accidentally passed in a very big key range.

yeah this could be interesting, would it be like we cancel the context after we have read a certain number of bytes? Also, should I make a follow up issue for this if it is something that we want?

@raggar raggar force-pushed the rahul_rate_limit branch 3 times, most recently from 286381b to 5238d18 Compare August 2, 2023 14:43
@raggar raggar marked this pull request as ready for review August 2, 2023 14:44
@raggar raggar requested a review from RaduBerinde August 2, 2023 14:44
Copy link
Member

@RaduBerinde RaduBerinde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 7 unresolved discussions (waiting on @itsbilal, @jbowens, and @RahulAggarwal1016)


db.go line 2605 at r3 (raw file):

Previously, RahulAggarwal1016 (Rahul Aggarwal) wrote…

yeah this could be interesting, would it be like we cancel the context after we have read a certain number of bytes? Also, should I make a follow up issue for this if it is something that we want?

If you run a SQL statement in the sql shell I believe you can interrupt it and that should cancel the relevant contexts. That's the use case I have in mind.

Sure, you can file an issue. Once https://github.com/cockroachdb/tokenbucket/pull/1/files merges, we can replace the loop with WaitCtx


db.go line 2679 at r9 (raw file):

type ScanStatisticsOptions struct {
	// LimitBytesPerSecond indicates the number of bytes that are able to be read
	// per second using ScanInternal.

[nit] Mention that 0 means no limit.

Copy link
Contributor Author

@raggar raggar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 7 files reviewed, 7 unresolved discussions (waiting on @itsbilal, @jbowens, and @RaduBerinde)


db.go line 2679 at r9 (raw file):

Previously, RaduBerinde wrote…

[nit] Mention that 0 means no limit.

fixed!

@raggar raggar requested a review from RaduBerinde August 3, 2023 19:07
@@ -2672,11 +2675,38 @@ type LSMKeyStatistics struct {
BytesRead uint64
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm right now I am not using this BytesRead field, did you have an idea for if we should use it for rate limiting @jbowens

@raggar raggar requested a review from a team August 7, 2023 17:22
Copy link
Collaborator

@jbowens jbowens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 2 of 6 files at r8, 2 of 4 files at r10, 1 of 1 files at r11, all commit messages.
Reviewable status: 5 of 7 files reviewed, 8 unresolved discussions (waiting on @itsbilal, @RaduBerinde, and @RahulAggarwal1016)


db.go line 2675 at r10 (raw file):

Previously, RahulAggarwal1016 (Rahul Aggarwal) wrote…

hm right now I am not using this BytesRead field, did you have an idea for if we should use it for rate limiting @jbowens

Let's still surface it in the output, even if we don't need it for rate limiting because it's useful information in its own right. We should add a comment describing what it is (logical, pre-compression size of keys and values read).

This pull request uses a `TokenBucket` to limit the number of keys that
read from `ScanStatistics` within a certain period of time.

Fixes: cockroachdb#2778
@raggar raggar merged commit ff5c929 into cockroachdb:master Aug 7, 2023
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rate Limit Scan Statistics Function
4 participants