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

Request buffering middleware #2217

Merged
merged 16 commits into from
Jan 31, 2018
Merged

Request buffering middleware #2217

merged 16 commits into from
Jan 31, 2018

Conversation

harnash
Copy link
Contributor

@harnash harnash commented Oct 5, 2017

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

  • Added/updated tests
  • Added/updated documentation
  • Docker Provider updated
  • Rancher Provider updated
  • Marathon Provider updated
  • k8s Provider updated
  • Mesos Provider updated
  • ECS Provider updated
  • Consul Catalog Provider updated
  • KV Provider updated

Additional Notes

This is related to PR #2209

This code will not test properly since Traefik uses forked vulcand/oxy dependency which does not have buffer package included (merge with upstream needed).

Copy link
Member

@emilevauge emilevauge left a 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

@harnash
Copy link
Contributor Author

harnash commented Oct 6, 2017

@emilevauge I was thinking about something similar. Since it is still blocked I will try to move those settings into backend config.

@nmengin
Copy link
Contributor

nmengin commented Oct 26, 2017

ping @harnash

Did you try to move the settings into backend config? Do you need some help?

@ldez ldez added the kind/enhancement a new or improved feature. label Oct 26, 2017
@harnash
Copy link
Contributor Author

harnash commented Oct 27, 2017

@nmengin Hey. Sadly no. I had my hands full but I'll try to look at this this weekend

@harnash
Copy link
Contributor Author

harnash commented Oct 29, 2017

@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?

@juliens
Copy link
Member

juliens commented Nov 10, 2017

As we need to have the last vulcand/oxy, I think we must wait for #2390

@juliens
Copy link
Member

juliens commented Dec 8, 2017

The new oxy version is merged on master, can you rebase ?
Thx

@harnash
Copy link
Contributor Author

harnash commented Dec 9, 2017

@juliens It is rebased but tests will still be failing since fork is missing oxy.buffer package.

@ldez
Copy link
Contributor

ldez commented Dec 9, 2017

@harnash pb fixed

Copy link
Contributor

@nmengin nmengin left a 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?

@harnash
Copy link
Contributor Author

harnash commented Dec 15, 2017

@nmengin I'll look into that

@ldez
Copy link
Contributor

ldez commented Jan 11, 2018

@harnash any news?

@harnash
Copy link
Contributor Author

harnash commented Jan 11, 2018

@ldez sorry I hadn't time to look at this yet but I'll schedule some time tomorrow.

Copy link
Contributor

@ldez ldez left a 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) {
Copy link
Contributor

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
	}
}

@@ -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)
Copy link
Contributor

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
Copy link
Contributor

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),
	)
}

@@ -15,6 +15,12 @@ const (
pathBackendServers = "/servers/"
pathBackendServerURL = "/url"
pathBackendServerWeight = "/weight"
pathBackendBufferingEnabled = "/buffering/enabled"
Copy link
Contributor

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),
Copy link
Contributor

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"),
),

@@ -80,6 +87,12 @@ const (
TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc
TraefikBackendBufferingEnabled = Prefix + SuffixBackendBufferingEnabled
Copy link
Contributor

Choose a reason for hiding this comment

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

const (
// ...
    TraefikBackendBuffering                        = Prefix + SuffixBackendBuffering
// ...
)

@ldez ldez added this to the 1.6 milestone Jan 29, 2018
@harnash
Copy link
Contributor Author

harnash commented Jan 29, 2018

I'll address those comments soon.

@ldez
Copy link
Contributor

ldez commented Jan 31, 2018

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.

Copy link
Contributor

@ldez ldez left a comment

Choose a reason for hiding this comment

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

LGTM 🎉

Copy link
Member

@juliens juliens left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@nmengin nmengin left a comment

Choose a reason for hiding this comment

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

LGTM 🎉 👏 👍

@traefiker traefiker merged commit a81171d into traefik:master Jan 31, 2018
@harnash harnash deleted the buffering_middleware branch March 23, 2018 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants