-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Request buffering middleware #2217
Conversation
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.
Hey @harnash, thanks for your contribution!
Instead of setting these options on the whole instance, I was thinking that it would be better to set them by backend. WDYT ? /cc @containous/traefik
@emilevauge I was thinking about something similar. Since it is still blocked I will try to move those settings into backend config. |
ping @harnash Did you try to move the settings into backend config? Do you need some help? |
@nmengin Hey. Sadly no. I had my hands full but I'll try to look at this this weekend |
@nmengin I've just pushed f120a47 which moves configuration to backend config. I might deploy this on our dev cluster soon to test it but I'm not sure I can since to build it I need vulcand/oxy/buffering package which is missing in the containous' fork. Any advice how to deal with this? |
As we need to have the last vulcand/oxy, I think we must wait for #2390 |
The new oxy version is merged on master, can you rebase ? |
@juliens It is rebased but tests will still be failing since fork is missing |
@harnash pb fixed |
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.
Hello @harnash .
Many thanks for this PR 👍
In the description, you said you would adding tests and documentation.
Is it still panned? Because I'm sure it can be helpful 😉
WDYT?
@nmengin I'll look into that |
@harnash any news? |
@ldez sorry I hadn't time to look at this yet but I'll schedule some time tomorrow. |
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.
In addition to what @nmengin said, you also need to remove:
TraefikBackendBufferingEnabled
SuffixBackendBufferingEnabled
pathBackendBufferingEnabled
@@ -90,6 +90,48 @@ func circuitBreaker(exp string) func(*types.Backend) { | |||
} | |||
} | |||
|
|||
func maxRequestBodyBytes(value int64) func(*types.Backend) { |
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.
Could you rewrite this section like that:
func buffering(opts ...func(*types.Buffering)) func(*types.Backend) {
return func(b *types.Backend) {
if b.Buffering == nil {
b.Buffering = &types.Buffering{}
}
for _, opt := range opts {
opt(b.Buffering)
}
}
}
func maxRequestBodyBytes(value int64) func(*types.Buffering) {
return func(b *types.Buffering) {
b.MaxRequestBodyBytes = value
}
}
func memRequestBodyBytes(value int64) func(*types.Buffering) {
return func(b *types.Buffering) {
b.MemRequestBodyBytes = value
}
}
func maxResponseBodyBytes(value int64) func(*types.Buffering) {
return func(b *types.Buffering) {
b.MaxResponseBodyBytes = value
}
}
func memResponseBodyBytes(value int64) func(*types.Buffering) {
return func(b *types.Buffering) {
b.MemResponseBodyBytes = value
}
}
func retrying(exp string) func(*types.Buffering) {
return func(b *types.Buffering) {
b.RetryExpression = exp
}
}
provider/kv/kv_config.go
Outdated
@@ -273,6 +274,23 @@ func (p *Provider) getHealthCheck(rootPath string) *types.HealthCheck { | |||
} | |||
} | |||
|
|||
func (p *Provider) getBuffering(rootPath string) *types.Buffering { | |||
enabled := p.getBool(false, rootPath, pathBackendBufferingEnabled) |
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.
could you rewrite this method like that:
func (p *Provider) getBufferingReal(rootPath string) *types.Buffering {
pathsBuffering := p.list(rootPath, pathBackendBuffering)
var buffering *types.Buffering
if len(pathsBuffering) > 0 {
if buffering == nil {
buffering = &types.Buffering{}
}
buffering.MaxRequestBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMaxRequestBodyBytes)
buffering.MaxResponseBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMaxResponseBodyBytes)
buffering.MemRequestBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMemRequestBodyBytes)
buffering.MemResponseBodyBytes = p.getInt64(0, rootPath, pathBackendBufferingMemResponseBodyBytes)
buffering.RetryExpression = p.get("", rootPath, pathBackendBufferingRetryExpression)
}
return buffering
}
server/server.go
Outdated
@@ -1560,3 +1571,31 @@ func (s *Server) wrapHTTPHandlerWithAccessLog(handler http.Handler, frontendName | |||
} | |||
return handler | |||
} | |||
|
|||
func (s *Server) buildBufferingMiddleware(handler http.Handler, config *types.Buffering) (http.Handler, error) { | |||
var lb *buffer.Buffer |
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.
could you rewrite this method like that:
func (s *Server) buildBufferingMiddleware(handler http.Handler, config *types.Buffering) (http.Handler, error) {
log.Debugf("Setting up buffering: request limits: %d (mem), %d (max), response limits: %d (mem), %d (max) with retry: '%s'",
config.MemRequestBodyBytes, config.MaxRequestBodyBytes, config.MemResponseBodyBytes,
config.MaxResponseBodyBytes, config.RetryExpression)
if len(config.RetryExpression) > 0 {
return buffer.New(
handler,
buffer.MemRequestBodyBytes(config.MemRequestBodyBytes),
buffer.MaxRequestBodyBytes(config.MaxRequestBodyBytes),
buffer.MemResponseBodyBytes(config.MemResponseBodyBytes),
buffer.MaxResponseBodyBytes(config.MaxResponseBodyBytes),
buffer.Retry(config.RetryExpression),
)
}
return buffer.New(
handler,
buffer.MemRequestBodyBytes(config.MemRequestBodyBytes),
buffer.MaxRequestBodyBytes(config.MaxRequestBodyBytes),
buffer.MemResponseBodyBytes(config.MemResponseBodyBytes),
buffer.MaxResponseBodyBytes(config.MaxResponseBodyBytes),
)
}
provider/kv/keynames.go
Outdated
@@ -15,6 +15,12 @@ const ( | |||
pathBackendServers = "/servers/" | |||
pathBackendServerURL = "/url" | |||
pathBackendServerWeight = "/weight" | |||
pathBackendBufferingEnabled = "/buffering/enabled" |
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.
could you modify this section like that:
const (
// ...
pathBackendBuffering = "/buffering/"
pathBackendBufferingMaxResponseBodyBytes = pathBackendBuffering + "maxresponsebodybytes"
pathBackendBufferingMemResponseBodyBytes = pathBackendBuffering + "memresponsebodybytes"
pathBackendBufferingMaxRequestBodyBytes = pathBackendBuffering + "maxrequestbodybytes"
pathBackendBufferingMemRequestBodyBytes = pathBackendBuffering + "memrequestbodybytes"
pathBackendBufferingRetryExpression = pathBackendBuffering + "retryexpression"
// ...
)
server("http://10.14.0.1:8080", weight(1)), | ||
server("http://10.12.0.1:8080", weight(1))), | ||
lbMethod("wrr"), | ||
maxRequestBodyBytes(10485760), |
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.
buffering(
maxRequestBodyBytes(10485760),
memRequestBodyBytes(2097152),
maxResponseBodyBytes(10485760),
memResponseBodyBytes(2097152),
retrying("IsNetworkError() && Attempts() <= 2"),
),
provider/label/names.go
Outdated
@@ -80,6 +87,12 @@ const ( | |||
TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName | |||
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount | |||
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc | |||
TraefikBackendBufferingEnabled = Prefix + SuffixBackendBufferingEnabled |
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.
const (
// ...
TraefikBackendBuffering = Prefix + SuffixBackendBuffering
// ...
)
I'll address those comments soon. |
Due to some conflicts with other PRs and the fact your PR is old (we are sorry for the delay), we will fix your PR. |
Fixed rancher tests.
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 🎉
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
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 🎉 👏 👍
What does this PR do?
This approach allows better control over requests processing incoming into Traefik. It allows to specify buffer limits and maximum request size that will be processed by Traefik. I've decided to use global settings for all requests (which seems enough for us) but it may more convenient to specify those settings per frontend.
For more background about this change please see the linked issue and mentioned PR.
Motivation
Fixes #2043
More
Additional Notes
This is related to PR #2209
This code will not test properly since Traefik uses forked vulcand/oxy dependency which does not havebuffer
package included (merge with upstream needed).