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

Don't open and close HTTP connections too often #110

Merged
merged 3 commits into from
Apr 12, 2019

Conversation

bbrowning
Copy link
Contributor

This adds a test to verify we aren't opening and closing HTTP
connections too often when sending events to a single host. The test
will fail in CI (it fails locally) until I push a subsequent change to
actually fix this issue.

The test tracks the count of opened HTTP connections and fails if it's
an amount more than double the expected concurrency. In practice, when
this is fixed properly, the number of opened connections should be
close to if not exactly the expected concurrency. In the case of this
test, that would be 200 new connections. As the code stands today,
when I run this on my laptop, we actually opening over 3000 new
connections in just the 1 second this test runs.

Related to #98

This adds a test to verify we aren't opening and closing HTTP
connections too often when sending events to a single host. The test
will fail in CI (it fails locally) until I push a subsequent change to
actually fix this issue.

The test tracks the count of opened HTTP connections and fails if it's
an amount more than double the expected concurrency. In practice, when
this is fixed properly, the number of opened connections should be
close to if not exactly the expected concurrency. In the case of this
test, that would be 200 new connections. As the code stands today,
when I run this on my laptop, we actually opening over 3000 new
connections in just the 1 second this test runs.

Signed-off-by: Ben Browning <bbrownin@redhat.com>
@bbrowning
Copy link
Contributor Author

This blew up as expected in CI, confirming we have an issue with the current behavior:

--- FAIL: TestStableConnectionsToSingleHost (1.04s)
    transport_test.go:126: too many new connections opened: expected 200, got 3619

Signed-off-by: Ben Browning <bbrownin@redhat.com>
@bbrowning bbrowning changed the title [WIP] Don't open and close HTTP connections too often Don't open and close HTTP connections too often Apr 12, 2019
@bbrowning
Copy link
Contributor Author

By not forcing every HTTP connection to close every time we send an event AND by tuning the net/http client properly (see the makeStableClient func) we can get good connection reuse when sending concurrently to a single host.

cc @n3wscott @matzew

If a user explicitly needs to close the connection after sending every
event, they can do so similar to how they can override the request
method and headers - by setting the req.Close value in a http.Request
passed and setting that as `transport.Req`.

Signed-off-by: Ben Browning <bbrownin@redhat.com>
@n3wscott
Copy link
Member

Thanks a bunch. Now @matzew can still set that setting using the request injection and it is off by default.

@n3wscott n3wscott merged commit c418b88 into cloudevents:master Apr 12, 2019
@bbrowning bbrowning deleted the stable-http-connections branch April 12, 2019 18:58
return nil, err
}
netHTTPTransport := &http.Transport{
MaxIdleConnsPerHost: 1000,
Copy link

Choose a reason for hiding this comment

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

@bbrowning, how does MaxIdleConnsPerHost with a value of 1000 interact with MaxIdleConns with its default value of 100?

My understanding is that MaxIdleConns is the number of connections to keep-alive across all hosts and MaxIdleConnsPerHost is the number of connections to keep alive per host. I'm guessing that if MaxIdleConnsPerHost has a higher value than MaxIdleConns, only MaxIdleConns will be used??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dubee I had to dig into the source to figure this out, but both values get applied. It first checks MaxIdleConnsPerHost and then enforces MaxIdleConns by evicting the oldest connections from the cache. There are slightly different semantics in the errors returned between the two limits as well as the actual behavior - hitting the global limit still puts the new connection in the cache and just evicts the oldest. Hitting the per-host limit doesn't put the new connection in the cache at all.

For the purposes of this test, that doesn't seem to actually matter, but it's good to know when tweaking these values on the Knative side of things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants