You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by ag...@apache.org on 2026/07/16 18:14:01 UTC
(datafusion-ballista) branch main updated: fix: enable the executor client pool by default (#2069)
This is an automated email from the ASF dual-hosted git repository.
andygrove pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-ballista.git
The following commit(s) were added to refs/heads/main by this push:
new 66af2392a fix: enable the executor client pool by default (#2069)
66af2392a is described below
commit 66af2392a26102dbfa4f147519600fbead6069ab
Author: Andy Grove <ag...@apache.org>
AuthorDate: Thu Jul 16 12:13:57 2026 -0600
fix: enable the executor client pool by default (#2069)
`client_ttl` defaulted to 0, which disables the client pool entirely. Without a
pool the shuffle-read path opens and discards a new TCP connection per fetch, so
a single shuffle-heavy query exhausts the host's ephemeral ports and fails with
`AddrNotAvailable` — as does every query after it, until the sockets leave
TIME_WAIT.
A single executor never shows this, because shuffle reads are served from local
files and no remote fetch happens. It appears as soon as a second executor
exists, which is every real deployment.
Default `client_ttl` to 30 seconds so the pool is on unless explicitly disabled.
The pooling machinery already exists and the shuffle reader is written assuming
it ("multiplexing over few connections"); it was simply off unless the operator
knew to pass `--client-ttl`.
Measured on the SF1 TPC-DS gate with 1 scheduler + 2 executors, all defaults:
before after
peak TIME_WAIT 16343 12
gate 11 OK/77 FAIL 88 OK/0 FAIL
The ephemeral range on the test host is 16384 ports, so one query consumed all
of it.
---
ballista/executor/src/config.rs | 23 ++++++++++++++++++++---
ballista/executor/src/executor_process.rs | 7 +++++--
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/ballista/executor/src/config.rs b/ballista/executor/src/config.rs
index 48b5a28c9..dc6d8fb19 100644
--- a/ballista/executor/src/config.rs
+++ b/ballista/executor/src/config.rs
@@ -180,11 +180,12 @@ pub struct Config {
help = "Max number of sessions whose shared runtime state (object-store clients, Parquet footer cache) is retained on the executor (LRU). 0 disables caching."
)]
pub session_runtime_cache_capacity: usize,
- /// Number of seconds established client connection should be cached if not used (0 means no cache)
+ /// Number of seconds an established client connection is cached while idle
+ /// (0 disables the cache, so every shuffle fetch opens a new connection)
#[arg(
long,
- default_value_t = 0,
- help = "Number of seconds established client connection should be cached if not used (0 means no cache, connection will be disposed)."
+ default_value_t = 30,
+ help = "Number of seconds established client connection should be cached if not used (0 means no cache, connection will be disposed; a shuffle-heavy query can then exhaust the host's ephemeral ports)."
)]
pub client_ttl: u64,
}
@@ -256,4 +257,20 @@ mod tests {
assert!(parse_memory_pool_size("banana").is_err());
assert!(parse_memory_pool_size("").is_err());
}
+
+ /// The client pool is what keeps shuffle fetches from opening a fresh TCP
+ /// connection each time; with it off, one shuffle-heavy query can exhaust
+ /// the host's ephemeral ports and take the executor down with it. Pin the
+ /// default on so it cannot regress to the disabled state unnoticed.
+ #[cfg(feature = "build-binary")]
+ #[test]
+ fn client_pool_is_enabled_by_default() {
+ use clap::Parser;
+ let opt = super::Config::parse_from(["ballista-executor"]);
+ assert!(
+ opt.client_ttl > 0,
+ "client_ttl must default to a pooling value, got {}",
+ opt.client_ttl
+ );
+ }
}
diff --git a/ballista/executor/src/executor_process.rs b/ballista/executor/src/executor_process.rs
index 360a89491..80b4874b3 100644
--- a/ballista/executor/src/executor_process.rs
+++ b/ballista/executor/src/executor_process.rs
@@ -187,7 +187,10 @@ pub struct ExecutorProcessConfig {
pub override_arrow_flight_service: Option<Arc<ArrowFlightServerProvider>>,
/// Override function for customizing gRPC client endpoints before they are used
pub override_create_grpc_client_endpoint: Option<EndpointOverrideFn>,
- /// Number of seconds established client connection should be cached (0 means no cache)
+ /// Number of seconds an established client connection is cached while idle.
+ /// `0` disables the pool, so every shuffle fetch opens and drops its own
+ /// connection and a shuffle-heavy query can exhaust the host's ephemeral
+ /// ports.
pub client_ttl: u64,
}
@@ -238,7 +241,7 @@ impl Default for ExecutorProcessConfig {
override_physical_codec: None,
override_arrow_flight_service: None,
override_create_grpc_client_endpoint: None,
- client_ttl: 0,
+ client_ttl: 30,
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org