-
Notifications
You must be signed in to change notification settings - Fork 487
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 ratelimiter for node api #577
Conversation
This commit adds ratelimiting logic for calls to the node api. It uses client IP as the ratelimiting key, and will drop log lines if/when a client is affected by the limiting. Signed-off-by: Evan Gilman <evan@scytale.io>
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.
Neato! A few comments...
pkg/server/endpoints/node/limiter.go
Outdated
l.notify(callerID, msgType) | ||
} | ||
if !res.OK() { | ||
res.Cancel() |
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: do you need to cancel if the burst limit has been exceeded?
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.
Not sure :) I put it there "just in case"... I've removed it.
pkg/server/endpoints/node/limiter.go
Outdated
} | ||
|
||
func (l *limiter) limiterFor(msgType int, callerID string) (*rate.Limiter, error) { | ||
limiters := l.limitersFor(msgType) |
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.
since limitersFor
is only ever called by limiterFor
, and holds the lock for the entire function, you may consider calling it while under the lock (and removing the Lock()/Unlock() inside limitersFor
.
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 did this out of concern for code safety... instead, opted to leave a code comment on limitersFor
, and moved to only taking a lock in limiterFor
// be processed. It introspects the context in order to identify the caller. An error will be | ||
// returned if the context is cancelled, an invalid msgType is specified, or if the number | ||
// of messages exceeds the burst limit. | ||
func (l *limiter) Limit(ctx context.Context, msgType, count int) error { |
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.
so if i understand correctly, the limits are imposed per caller, per msg type? 500 ops a second per caller seems a tad high....
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.
That's correct, though the "limit" is the max burst size - no request with more than 500 CSRs will be allowed to pass. The actual rate is defined when the struct is created, currently capped at 100 per second... In this example, if a request was submitted with 500 CSRs, it would (under the worst conditions) have to wait 5 seconds for it to be permitted.
Since exceeding this limit would be a permanent error condition, I have taught the agent to truncate requests that would exceed it, allowing the remainder to be submitted on the next manager cycle
@@ -0,0 +1,141 @@ | |||
package node |
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: use github.com/stretchr/testify helpers to cut down on assertion boilterplate
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
* Clean up tests through use of testify * Teach agent to not exceed burst limit * Use coarse outer lock w/ code comment instead of granular independent locks * Dont cancel reservations for limits that are not "OK" Signed-off-by: Evan Gilman <evan@scytale.io>
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!
This commit adds ratelimiting logic for calls to the node api. It uses
client IP as the ratelimiting key, and will drop log lines if/when a
client is affected by the limiting.
Signed-off-by: Evan Gilman evan@scytale.io