-
Notifications
You must be signed in to change notification settings - Fork 13
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 #411
Add rate limiting #411
Conversation
PR Summary
|
e09e425
to
98b71d2
Compare
http_proxy.go
Outdated
@@ -86,6 +87,8 @@ type HTTPProxyConfig struct { | |||
CloseAfterReply bool | |||
DenyDomains []*regexp.Regexp | |||
DenyDomainsExclude []*regexp.Regexp | |||
ReadLimit uint |
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 think it would be beneficial to use a special type that supports kb mb etc, see in rclone for inspiration.
bind/flag.go
Outdated
@@ -127,6 +127,12 @@ func HTTPProxyConfig(fs *pflag.FlagSet, cfg *forwarder.HTTPProxyConfig, lcfg *lo | |||
"Use this flag multiple times to specify multiple deny domain excludes. "+ | |||
"This flag takes precedence over deny-domain. "+ | |||
"Can be specified only if --deny-domain is also specified. ") | |||
|
|||
fs.UintVar(&cfg.ReadLimit, "read-limit", cfg.ReadLimit, "<bandwidth>"+ | |||
"Global read rate limit in bytes per second.") |
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.
Same here more sophisticated input would be nice.
Looks good, some commits could be squashed. |
d1478a6
to
9b88eb0
Compare
88ace92
to
2f340ee
Compare
resource/sizesuffix.go
Outdated
@@ -0,0 +1,247 @@ | |||
package resource |
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.
How about putting it directly in forwarder. This is needed for config and CLI.
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.
ok
ratelimit/ratelimit.go
Outdated
const defaultMaxBurstSize = 4 * 1024 * 1024 // Must be bigger than the biggest request. | ||
|
||
func newRateLimiter(bandwidth resource.SizeSuffix) *rate.Limiter { | ||
// The rate limiter is configured to allow a burst of 1/64th of the bandwidth or defaultMaxBurstSize. |
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.
Let's leave the original discussion and a pointer to rclone issue.
The point is that it does not allow high bandwidth if defaultMaxBurstSize is used.
2f340ee
to
db3998a
Compare
@mmatczuk comments addressed |
@@ -94,3 +97,50 @@ func TestFlagDenyDomain(t *testing.T) { | |||
newClient(t, "https://www.google.com").GET("/").ExpectStatus(http.StatusForbidden) | |||
newClient(t, httpbin).GET("/status/200").ExpectStatus(http.StatusOK) | |||
} | |||
|
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.
Those tests do not make any sense to me.
- There should be one setup with rx and tx
- Test must use more than one connection
- TestFlagWriteLimit is in fact read limit
- TestFlagReadLimit is doing sth very strange
We need an httpbin endpoint that copies request body to io.Discard
b3bf3a1
to
4780cea
Compare
utils/httpbin/httpbin.go
Outdated
@@ -24,6 +24,7 @@ func Handler() http.Handler { | |||
m.HandleFunc("/delay/", delayHandler) | |||
m.HandleFunc("/status/", statusHandler) | |||
m.HandleFunc("/stream-bytes/", streamBytesHandler) | |||
m.HandleFunc("/stream-discard/", streamDiscardHandler) |
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.
stream comes from Dynamic data Generates random and dynamic data
It's more like sink just read all body, it feels like any function should do it.
You could be more creative and have count-bytes that one would return body size as a header etc.
@@ -359,6 +360,45 @@ func SetupFlagDenyDomain(l *setupList) { | |||
) | |||
} | |||
|
|||
func SetupFlagRateLimit(l *setupList) { | |||
l.Add( |
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.
How about a single setup?
e2e/tests/flag_test.go
Outdated
}() | ||
} | ||
wg.Wait() | ||
if elapsed := time.Since(ts); elapsed.Round(time.Second) != expectedTime { |
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.
Rounding is not great, let's say it can be 5% off and compute.
41311a3
to
86fd15d
Compare
e2e/tests/flag_test.go
Outdated
connections = 2 | ||
size = 5 * 1024 * 1024 // 5MiB | ||
expectedTime = 6 * time.Second | ||
acceptableRange = expectedTime * 5 / 100 // 5% |
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.
how about epsilon.
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.
Sounds good.
SizeSuffix code and tests were copied from rclone project https://github.com/rclone/rclone. golangci: skip sizesuffix files chore: go mod tidy
The package exports custom Listener with global rate limiters for every accepted connection. The burst setup is inspired by the one in rclone project [1]. More on that in this thread [2]. [1] https://github.com/rclone/rclone/blob/cda09704a8078fe5cecd1107503de5ab8b401ad4/fs/accounting/token_bucket.go#L59-L77 [2] rclone/rclone#5507 golangci: disable err check in Limiter.WaitN
It reads the request body and sends back the number of bytes read in a header.
@@ -94,3 +98,79 @@ func TestFlagDenyDomain(t *testing.T) { | |||
newClient(t, "https://www.google.com").GET("/").ExpectStatus(http.StatusForbidden) | |||
newClient(t, httpbin).GET("/status/200").ExpectStatus(http.StatusOK) | |||
} | |||
|
|||
func TestFlagReadLimit(t *testing.T) { |
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 was thinking since the test init sequence is almost identical that maybe we should have a helper function?
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.
Extracted it, looks better indeed.
0871cfa
to
5a1b0bd
Compare
5a1b0bd
to
771213c
Compare
This adds global read and write rate limit.