Skip to content

feat: bump default gRPC max message size 16 MiB -> 128 MiB - #2173

Open
andygrove wants to merge 5 commits into
apache:mainfrom
andygrove:grpc-message-size-defaults
Open

feat: bump default gRPC max message size 16 MiB -> 128 MiB#2173
andygrove wants to merge 5 commits into
apache:mainfrom
andygrove:grpc-message-size-defaults

Conversation

@andygrove

Copy link
Copy Markdown
Member

Summary

At SF1000 several TPC-H plans (Q11, Q21, Q22) encode above the 16 MiB default gRPC message-size ceiling and fail with:

Status { code: OutOfRange, message: "Error, decoded message length too large:
        found ~22 MB, the limit is: 16777216 bytes" }

Raising the runtime flags on scheduler/executor pods (--grpc-server-max-*-message-size=...) only lifts the server-side receive limits. Several paths still use GrpcClientConfig::default() (16 MiB) unconditionally — most notably the scheduler-to-executor gRPC client in ExecutorManager::new:

https://github.com/apache/datafusion-ballista/blob/main/ballista/scheduler/src/state/executor_manager.rs#L88

So task-assignment RPCs with large plans reject even when the servers have been raised, unless the user knows to also configure a config-producer override. Same story in flight_proxy_service.rs and the executor's client pool Default lookups.

This PR bumps every default that fed a 16 MiB ceiling to 128 MiB.

Context: I hit this in #2168 while running SF1000 TPC-H and got stuck for a while before realizing the scheduler-side flags don't cover this path.

What changed

  • ballista/core/src/config.rsBALLISTA_CLIENT_GRPC_MAX_MESSAGE_SIZE default (the SessionConfig-driven client path used by distributed_query).
  • ballista/core/src/utils.rsGrpcClientConfig::default() max_message_size (used by scheduler-to-executor, flight proxy, executor client pool default lookups).
  • ballista/scheduler/src/config.rs and ballista/executor/src/config.rs — both CLI flags (--grpc-server-max-{decoding,encoding}-message-size) and the matching struct defaults.
  • ballista/executor/src/executor_process.rs — matching ExecutorProcessConfig defaults.
  • Help strings updated.

The value is a ceiling, not a preallocation, so bumping it has no runtime cost for messages below the old limit.

New test

Adds a round-trip test that ballista.client.grpc_max_message_size, set on a SessionConfig via options_mut().set(...), reaches BallistaConfig::grpc_client_max_message_size() unchanged. That path (options.set → ExtensionOptions → get_usize_setting) had no existing coverage, and it's the one Python clients rely on via their cluster_config overrides.

Test plan

  • cargo test --workspace --lib — all green (all pre-existing suites + 2 new/updated).
  • cargo fmt --all.
  • cargo clippy --workspace --all-targets -- -D warnings clean.
  • Reviewer sanity-check: any other places I missed that hard-code 16 MiB in a default? (Non-default hard-coded values in examples/ were left alone.)

At SF1000, some TPC-H plans (Q11, Q21, Q22) encode above the 16 MiB
default gRPC message-size ceiling, so submitting them fails with:

    Status { code: OutOfRange, message: "Error, decoded message length
    too large: found ~22 MB, the limit is: 16777216 bytes" }

Raising the runtime flags on scheduler and executor pods only lifts the
server-side receive limits. Several paths still use
`GrpcClientConfig::default()` (16 MiB) unconditionally — most notably
the scheduler-to-executor client in `ExecutorManager::new` — so
task-assignment RPCs with large plans reject even when the servers were
raised.

Bump every default that fed a 16 MiB ceiling to 128 MiB:

- ballista/core/src/config.rs — `BALLISTA_CLIENT_GRPC_MAX_MESSAGE_SIZE`
  default (SessionConfig-driven client path).
- ballista/core/src/utils.rs — `GrpcClientConfig::default()`
  `max_message_size` (used by scheduler-to-executor, flight proxy,
  executor client pool default lookups).
- ballista/scheduler/src/config.rs and
  ballista/executor/src/config.rs — both CLI flags
  (`--grpc-server-max-{decoding,encoding}-message-size`) and the
  matching struct defaults.
- ballista/executor/src/executor_process.rs — matching
  ExecutorProcessConfig defaults.

The value is a ceiling, not a preallocation, so bumping it has no
runtime cost for messages below the old limit.

Adds a round-trip test confirming that
`ballista.client.grpc_max_message_size` set on a SessionConfig reaches
`BallistaConfig::grpc_client_max_message_size()` unchanged, since that
path (options.set -> ExtensionOptions -> get_usize_setting) had no
existing coverage.

Updates the `default_config` unit test to reflect the new default.

Signed-off-by: Andy Grove <agrove@apache.org>
Signed-off-by: Andy Grove <agrove@apache.org>
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 24, 2026
Bumping GrpcClientConfig::default().max_message_size to 128 MiB helps
most cases but leaves no runtime knob for the scheduler's outbound gRPC
client to executors — the client the task-assignment RPC actually flows
through. Its config was only overridable via a Rust-side
`override_config_producer`, which end users of the shipped binary can't
set.

Add `--grpc-client-max-message-size` on the scheduler CLI (default
134217728 == the new default), and use it to override
`GrpcClientConfig::max_message_size` in `ExecutorManager::new` when no
`override_config_producer` is wired. The producer path still takes
precedence so embedders keep full control.

Users can now scale beyond 128 MiB without recompiling.

Signed-off-by: Andy Grove <agrove@apache.org>
@milenkovicm

Copy link
Copy Markdown
Contributor

There is also outstanding pr which helps reducing message size #1853

@phillipleblanc phillipleblanc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good to me, one thing to check is whether we want to wire this into create_grpc_client_endpoint to pass along the max message size value.

i.e.

   SchedulerConfig.grpc_client_max_message_size
           v
   GrpcClientConfig.max_message_size
           v
   create_grpc_client_endpoint(config) // here
           v
   ExecutorGrpcClient::new(channel)

create_grpc_client_endpoint reads settings such as:

  • connection timeout
  • keepalive interval
  • HTTP/2 window sizes

But it never reads config.max_message_size. Message-size limits are Tonic codec settings, not HTTP/2 Endpoint settings.

It would need something like:

  let client = ExecutorGrpcClient::new(connection)
      .max_encoding_message_size(grpc_client_config.max_message_size)
      .max_decoding_message_size(grpc_client_config.max_message_size);

Comment thread ballista/executor/src/config.rs Outdated
Comment thread ballista/executor/src/config.rs Outdated
andygrove and others added 2 commits July 27, 2026 10:52
Co-authored-by: Martin Grigorov <martin-g@users.noreply.github.com>
Co-authored-by: Martin Grigorov <martin-g@users.noreply.github.com>
@martin-g

Copy link
Copy Markdown
Member

I wonder whether 128MiB is too much ?!
Having a lower value led to an optimisation like #1853.
With a big value like 128MiB it will be harder to notice that some message(s) became too heavy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants