-
Notifications
You must be signed in to change notification settings - Fork 261
perf: add connection pooling for shuffle reader remote fetches #1388
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
base: main
Are you sure you want to change the base?
Conversation
Adds a BallistaClientPool that caches gRPC connections to executors by (host, port). This avoids the overhead of establishing new connections for each partition fetch during shuffle reads. Key changes: - Add BallistaClientPool struct with get_or_connect() method - Add global_client_pool() function for shared pool access - Update fetch_partition_remote() to use the connection pool - Remove stale connections from pool on fetch errors The pool uses a read-write lock pattern with parking_lot::RwLock: - Fast path: read lock to check for existing connection - Slow path: create connection without holding lock, then write lock to cache (handles races by preferring existing) Error handling: on FetchFailed or GrpcActionError, the connection is removed from the pool so subsequent requests create fresh connections. This handles cases where connections become stale or the remote server closes them. This addresses the TODO comment in shuffle_reader.rs about avoiding creating new connections repeatedly. Co-Authored-By: Claude Opus 4.5 <[email protected]>
70f145d to
4b28e0a
Compare
|
is there a chance we cover #1367 somehow as well? (if it is obvious) |
|
there is a test
which forces remote read always, not sure if that would cover your last task in the list. |
| /// access during connection creation. The `BallistaClient` itself is `Clone` | ||
| /// (wrapping an `Arc`), so cloned clients share the underlying connection. | ||
| #[derive(Default)] | ||
| pub struct BallistaClientPool { |
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.
just wonder would it make sense to use some off-the-shelf like deadpool or r2d2 instead of implementing our own ?
If i'm not mistaken, current implementation can, in theory, leak connections; connection will be removed from the pool only when it fails, but, in theory, we can have a executor removed/replaced and connection never get chance to fail
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 pushed a TTL improvement, but moved this to draft for now
Connections in the pool were only removed when they failed. If an executor was removed/replaced without causing connection errors, stale connections would leak indefinitely. This adds a configurable TTL (default 5 minutes) so connections automatically expire and are replaced with fresh ones on the next access attempt. Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
i guess we can't use |
|
closes #736 i believe |
Summary
Adds a
BallistaClientPoolthat caches gRPC connections to executors by (host, port). This avoids the overhead of establishing new connections for each partition fetch during shuffle reads.Changes
BallistaClientPoolstruct inclient.rswith:get_or_connect(host, port, max_message_size)- gets cached connection or creates new oneremove(host, port)- removes a connection (useful for error recovery)clear()- clears all cached connectionsglobal_client_pool()function for shared pool access across all shuffle readsfetch_partition_remote()in shuffle_reader.rs to use the connection poolImplementation Details
The pool uses a read-write lock pattern with
parking_lot::RwLock:Race handling: if multiple tasks try to connect to the same host simultaneously, each creates a connection but only one gets cached. The others detect this and return the cached one, dropping their extra connection. This is a rare case and avoids holding locks during async connection establishment.
Error Handling
On
FetchFailedorGrpcActionError, the connection is removed from the pool so subsequent requests create fresh connections. This handles cases where:Motivation
This addresses the TODO comment in shuffle_reader.rs:
Connection establishment involves TCP handshake, TLS negotiation (if enabled), and HTTP/2 setup. Reusing connections eliminates this overhead for repeated fetches from the same executor.
Note
This PR was created with AI assistance using Claude Code. All changes were reviewed and approved by a human maintainer.
Test plan
cargo test -p ballista-core shuffle_reader)cargo test -p ballista-core client)