-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
[native] Share HTTP connection pools between HTTP clients #21367
Conversation
acb97d5
to
be6a1fa
Compare
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.
Thanks for working on this!
@@ -185,6 +185,7 @@ class HttpClientFactory { | |||
} | |||
|
|||
~HttpClientFactory() { | |||
eventBase_->runInEventBaseThread([pools = std::move(sessionPools_)] {}); |
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.
Is this a way to destroy "sessionPools_" in even base thread?
Why do we need this?
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.
Because it is pinned to one event base and the destructor need to release some resource associated with it. It is documented in the comment of the class.
STR_PROP(kExchangeMaxErrorDuration, "3m"), | ||
STR_PROP(kExchangeRequestTimeout, "10s"), | ||
STR_PROP(kExchangeConnectTimeout, "0s"), | ||
STR_PROP(kExchangeConnectTimeout, "20s"), |
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.
We should add these changes in a separate change, in case something goes wrong, so we son't have to rollback the whole PR.
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 separate it here: #21379
@@ -100,13 +105,43 @@ class PrestoExchangeSource : public velox::exec::ExchangeSource { | |||
uint32_t maxBytes, | |||
uint32_t maxWaitSeconds) override; | |||
|
|||
static std::shared_ptr<ExchangeSource> create( | |||
// HTTP connection pool for a specific endpoint with its associated event | |||
// base. All the operations on the SessionPool must be performed on the |
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.
nit: double space.
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 double space after a full sentence is the rule (especially for fixed-width font)?
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.
Never heard about it.
Space is always single.
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.
Searched online and it appears to be an old convention and now becomes a religious war :(
Double space allows me to use M-e and M-a to jump through the sentences in Emacs so I would prefer it for pragmatic reason.
for (auto& [_, pool] : pools) { | ||
pool.eventBase->runInEventBaseThread( | ||
[sessionPool = std::move(pool.sessionPool)] {}); | ||
} |
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.
-
Why do we need to clear sessionPool objects in the Event Base Thread?
-
Does this 'runInEventBaseThread' run synchronously?
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 required by design
- No
class ConnectionPools { | ||
public: | ||
~ConnectionPools() { | ||
destroy(); | ||
} | ||
|
||
const ConnectionPool& get( | ||
const proxygen::Endpoint& endpoint, | ||
folly::IOThreadPoolExecutor* ioExecutor); | ||
void destroy(); | ||
|
||
private: | ||
folly::Synchronized<folly::F14FastMap< | ||
proxygen::Endpoint, | ||
ConnectionPool, | ||
proxygen::EndpointHash, | ||
proxygen::EndpointEqual>> | ||
pools_; | ||
}; |
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 feels very weird that ConnectionPools is declared inside of PrestoExchangeSource class.
Because it is actually owned by someone else.
It made me confused for a while.
Should we consider declaring ConnectionPools in the global namespace?
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 put it here to make it clear these connection pools are used by exchange source (not HTTP server or anything else)
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.
@Yuhta
We could add a comment for this class.
Usually classes declared within other classes, when the objects of the internal classes are created/managed/used by the external class.
Not our case.
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.
@Yuhta
Few general questions:
- With this change - would the connection pools for particular endpoints stay forever?
- Limiting # sessions per endpoint to 10 for all exchange sources in the flight - can it cause issues? Before this change it was 10 * number of exchange sources.
|
ee84be5
to
cbb3c97
Compare
Currently each exchange source owns one unique `SessionPool`, so the connection is only reused for one specific point to point communication. This creates many connections between the same upstream and downstream nodes, decreasing the performance, increasing the chance of network error, and wasting precise ephemeral TCP ports (can only have 32K of them on one host) on client side. Fix this by pooling the connections, decreasing the open socket count from 52K to 15K during peak, and have consistently lower socket usage during all time (see image attached). Also set a connect time out and increase the error duration so that connection error can be retried.
Currently each exchange source owns one unique
SessionPool
, so the connection is only reused for one specific point to point communication. This creates many connections between the same upstream and downstream nodes (for different tasks), decreasing the performance, increasing the chance of network error, and wasting precious ephemeral TCP ports (can only have 32K of them on one host) on client side.Fix this by pooling the connections, decreasing the open socket count from 52K to 15K during peak, and have consistently lower socket usage during all time (see image attached).
Also set a connect time out and increase the error duration so that connection error can be retried.