-
Notifications
You must be signed in to change notification settings - Fork 0
Add Sidecar MaxConn support without other functionality changes #8
Conversation
configuration.go
Outdated
@@ -334,6 +334,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration { | |||
defaultSidecar.Endpoint = "http://127.0.0.1:7777" | |||
defaultSidecar.Frontend = "sidecar.toml" | |||
defaultSidecar.RefreshConn = flaeg.Duration(60 * time.Second) | |||
defaultSidecar.MaxConns = 300 |
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.
This is a super low default. HAproxy defaults to 2000 for example:
Also, when is set to large values, it is possible that the servers
are not sized to accept such loads, and for this reason it is generally wise
to assign them some reasonable connection limits.
By default, this value is set to 2000.
provider/sidecar.go
Outdated
} | ||
return nil | ||
|
||
return provider.loadSidecarConfig(states.ByService()) |
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.
As mentioned in #7, I'd just pass states
here and loop over them with states.EachService()
later. Saves allocation for a biggish map and lots less CPU time.
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.
This might not work out easily, because the Sidecar watch
endpoint returns state.ByService()
, which is a map[string][]*service.Service
.
Given this, you mentioned submitting a PR to Sidecar to add a parameter to this endpoint that allows the consumer to specify whether they want to get the state "ByService" or not. I'll proceed to make the required changes in Sidecar for this to work.
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.
@relistan Changes pushed to address this... Hopefully, it will fit nicely with the Sidecar watcher additions :)
provider/sidecar.go
Outdated
safe.Go(func() { catalog.DecodeStream(resp.Body, provider.callbackLoader) }) | ||
|
||
//wait on refresh connection timer. If this expires we haven't seen an update in a | ||
//while and should cancel the request, reset the time, and reconnect just in case | ||
<-provider.connTimer.C | ||
provider.connTimer.Reset(time.Duration(provider.RefreshConn)) | ||
tr.CancelRequest(req) | ||
|
||
//TODO: Deprecated method. Refactor this to use a context. |
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.
👍
provider/sidecar_test.go
Outdated
} | ||
|
||
func TestSidecarFetchState(t *testing.T) { | ||
setup() |
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.
This is working against the grain for goconvey. Have a read here: https://github.com/smartystreets/goconvey/wiki/Execution-order
provider/sidecar_test.go
Outdated
configMsg, _ := <-configurationChan | ||
|
||
// We have no way to shut down the provider when it's running in watch mode, | ||
// so just let the unit test close it at the end |
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 a smell. There are solutions. This is one: https://github.com/relistan/go-director
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.
@relistan I have pushed 4635181 to address this comment. Please let me know if that change fully addresses this code smell.
provider/sidecar.go
Outdated
method = "wrr" | ||
weight = 0 | ||
sticky = false | ||
maxConnExtractorFunc = "request.host" |
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'm struggling to see where this is used other than in New
and 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.
That's just there until we finally agree to have this setting configurable via TOML along with the actual limit. In our case "request.host" makes sense, but other people might want to change it. It's used here and it can be set to "client.ip" or "request.host" or "request.header.<header_name>". I think it's best if we allow users to change it via the config file.
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.
If you guys really think we need this level of control with the max connections per backend (as opposed to one global setting), then I agree with Mihai's implementation. Simplest would be to expose it in the toml config file.
Some comments inline above. But generally 👍 |
|
||
sidecarHTTPClient = &http.Client{ | ||
Timeout: 5 * time.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.
👍 this is much cleaner
Just one comment from me re: the max connections setting, but I'll defer to you guys on that point. Thanks for doing this @mihaitodor 👍 |
2b7a4cc
to
138c9ff
Compare
@relistan @bparli I have managed to add the MaxConn field as optional on the frontends defined in the TOML via commit c06c529. Please note that it will default to Amount: 2000 / ExtractorFunc: "request.host" if no MaxConn field is defined for a specific frontend in the TOML file. This approach was discussed here and I assumed silent approval :) |
- restructure tests and remove useless repetition - use custom http.Client instances which we can reset to http.DefaultClient in the unit tests, because httpmock can't hook into (multiple) non-default HTTP clients and we need to have two of them (one for the watcher endpoint and one for fetching state.json) - adjust TestSidecarWatcher to actually test that loadSidecarConfig is being invoked when adding new service entries to the mock Sidecar watcher response
- Allow the user to configure MaxConns via the TOML settings file - Extend TestSidecarMakeBackends to test this new functionality
I decided to not add a dependency on go-director, since Traefik already has similar functionality builtin (safe/routine.go). Discussion: #7 (comment) #8 (comment)
Remove the "Frontend" field from the Sidecar provider and use the default "Filename" field from the embedded BaseProvider struct. Note: this will require updating the configuration files in erector. Discussion: https://github.com/Nitro/traefik/pull/7/files#r113908566
decodeStream should terminate when the input stream is closed. Discussion: #8 (comment)
- This commit enables adding a MaxConn field on the frontends defined for Sidecar via the TOML specified in the Filename field. - Design discussed here: #7 (comment) and here: #8 (comment)
c06c529
to
726472c
Compare
[frontends.web.routes.test_1] | ||
rule = "Host: some-aws-host" | ||
rule = "Host: some-aws-host" | ||
[frontends.web.maxconn] |
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.
Should there be another test without the frontends.web.maxconn to verify the default Maxconn setting?
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.
It's tested for the other backend defined in this file. See here.
I was considering to create a separate TOML for that specific case, but I think it wouldn't add much value.
Fix resource leak (missing
resp.Body.Close()
inSidecar.fetchState()
)Add maxconn functionality
Restructure tests and remove useless repetition (couldn't help myself, sorry)
http.DefaultClient in the unit tests, because httpmock can't hook
into (multiple) non-default HTTP clients and we need to have two
of them (one for the watcher endpoint and one for fetching
state.json)
loadSidecarConfig is being invoked when adding new service entries
to the mock Sidecar watcher response
Fix linter suggestions
Update 09.05.2017:
TODO in separate PRs:
tr.CancelRequest(req)
as agreed here (see Refactor deprecated Transport.CancelRequest method #12)(cc @bparli, @relistan)