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

Dynamic rate limiter #4390

Merged
merged 77 commits into from
Jun 2, 2023
Merged

Conversation

pdoerner
Copy link
Contributor

What changed?
Adding a new rate limiter that dynamically adjusts its rate based on signals from the persistence layer.

Why?
For system protection

How did you test it?
A new integration test confirms that the rate limiter adjusts itself
More manual testing will be required

Potential risks
Over aggressive rate limiting
The rate limit seesaws back and forth

Is hotfix candidate?

Comment on lines 64 to 69
EnableDynamicRateLimiting dynamicconfig.BoolPropertyFn
DynamicRateLimitingRefreshInterval dynamicconfig.DurationPropertyFn
DynamicRateLimitingLatencyThreshold dynamicconfig.FloatPropertyFn
DynamicRateLimitingErrorThreshold dynamicconfig.FloatPropertyFn
DynamicRateLimitingRateBackoffStepSize dynamicconfig.FloatPropertyFn
DynamicRateLimitingRateIncreaseStepSize dynamicconfig.FloatPropertyFn
Copy link
Member

Choose a reason for hiding this comment

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

If you have a common set of dynamic config properties that are all used together, consider: define a struct for them, use a dynamic config "map" (which gives you a map[string]any) and then write a function to unpack the map into the struct (slightly annoying but you can cheat and do json.Marshal+json.Unmarshal to get it for free)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dnr I updated the dynamic config properties, let me know what you think.

I'm a little concerned about two things:

  1. Will json.Marshal and json.Unmarshal add significant overhead when updating the dynamic values?
  2. The field names to use in that map are somewhat harder to find. I included them on the comment on the constant for dynamicconfig.HistoryPersistenceDynamicRateLimitingParams, do you think that will be clear enough or will users have trouble understanding what config options are available?

@pdoerner pdoerner marked this pull request as ready for review June 1, 2023 20:39
@pdoerner pdoerner requested a review from a team as a code owner June 1, 2023 20:39
@pdoerner pdoerner requested a review from yycptt June 2, 2023 03:52
Copy link
Member

@yycptt yycptt left a comment

Choose a reason for hiding this comment

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

Haven't reviewed the rate limiter impl yet.

@pdoerner pdoerner merged commit de7f679 into temporalio:master Jun 2, 2023
@pdoerner pdoerner deleted the dynamic-rate-limiter branch June 2, 2023 22:30

func (rl *HealthRequestRateLimiterImpl) refreshDynamicParams() {
var options dynamicRateLimitingOptions
b, err := json.Marshal(rl.params())
Copy link
Member

Choose a reason for hiding this comment

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

Hmm.. I thought the point of defining the keys explicitly was to avoid the json stuff? So, those constants are only used in the default value and nowhere else?

I would think if you're going to define string constants for the map keys, you should use them to read the map

Comment on lines +74 to +79
dynamicRateLimitEnabledKey: dynamicRateLimitEnabledDefault,
dynamicRateLimitRefreshIntervalKey: dynamicRateLimitRefreshIntervalDefault,
dynamicRateLimitLatencyThresholdKey: dynamicRateLimitLatencyThresholdDefault,
dynamicRateLimitErrorThresholdKey: dynamicRateLimitErrorThresholdDefault,
dynamicRateLimitBackoffStepSizeKey: dynamicRateLimitBackoffStepSizeDefault,
dynamicRateLimitIncreaseStepSizeKey: dynamicRateLimitIncreaseStepSizeDefault,
Copy link
Member

Choose a reason for hiding this comment

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

Personally I find this kind of hard to read and I'd just put the defaults inline in this map. It is effectively a constant itself

Comment on lines +153 to +154
rl.rateLimiter.SetRate(rl.curRateMultiplier * rl.rateFn())
rl.rateLimiter.SetBurst(int(rl.rateToBurstRatio * rl.rateFn()))
Copy link
Member

Choose a reason for hiding this comment

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

should you maybe update rl.rateLimiter always here, in case rateFn returns something different?

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.

4 participants