You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@spark.apache.org by "Yannick Goetschel (Jira)" <ji...@apache.org> on 2026/08/07 18:47:00 UTC

[jira] [Created] (SPARK-58649) Allow SparkApplication drivers ingress to SparkCluster workers

Yannick Goetschel created SPARK-58649:
-----------------------------------------

             Summary: Allow SparkApplication drivers ingress to SparkCluster workers  
                 Key: SPARK-58649
                 URL: https://issues.apache.org/jira/browse/SPARK-58649
             Project: Spark
          Issue Type: Bug
          Components: Kubernetes
    Affects Versions: kubernetes-operator-1.0.0
         Environment:   We run per-user Spark Connect sessions as SparkApplications attached to a shared
  standalone SparkCluster. Most jobs are fine, but every so often one dies like this:


{code:java}
Job aborted due to stage failure: Task 11 in stage 2.0 failed 4 times, most recent
failure: Lost task 11.3 in stage 2.0 (TID 86) (<executor-ip> executor 3):
TaskResultLost (result lost from block manager)
{code}

The driver log explains why only some of them:

{code:java}
 java.io.IOException: Connecting to /<executor-ip>:<ephemeral-port> timed out (120000 ms)
        at org.apache.spark.network.client.TransportClientFactory.createClient(...)
        at org.apache.spark.network.netty.NettyBlockTransferService$$anon$2.createAndStart(...)
        at org.apache.spark.network.shuffle.RetryingBlockTransferor.transferAllOutstanding(...)
        at org.apache.spark.storage.BlockManager.fetchRemoteManagedBuffer(...)
        at org.apache.spark.scheduler.TaskResultGetter$$anon$3.run(...)
 {code}

The driver cannot reach the executors' block manager. That only matters once a task
result goes over {{spark.task.maxDirectResultSize}} (1 MB): below it the result rides
along inline in the RPC, above it the executor parks the result in its block manager and
hands the driver an {{IndirectTaskResult}} to go and fetch. The tasks that stayed under
the limit never noticed anything. The three that went over timed out, retried three
times and gave up, and the stage aborted on the fourth attempt.

The culprit is the worker NetworkPolicy the operator generates for every SparkCluster in
{{SparkClusterResourceSpec#buildWorkerNetworkPolicy}}:

{code:yaml}
  podSelector:
    matchLabels: {spark-role: worker, spark.operator/spark-cluster-name: <cluster>}
  ingress:
  - from:
    - podSelector:
        matchLabels: {spark.operator/spark-cluster-name: <cluster>}
  policyTypes: [Ingress]
  {code}

Only pods carrying the cluster label may talk to the workers. But a SparkApplication
attached to the cluster is a separate resource: its driver is labelled
{{spark-role: driver}} and {{spark.operator/spark-app-name: <app>}}, never the cluster
label. So the driver is locked out of its own executors.

The executor-to-driver direction works perfectly well —
 executors register, tasks get dispatched, tasks run. Only the return path for large
 results is broken, so the cluster looks healthy right up until a job happens to cross
 the 1 MB threshold.

            Reporter: Yannick Goetschel


The worker \{{NetworkPolicy}} generated for every \{{SparkCluster}} by
  \{{SparkClusterResourceSpec#buildWorkerNetworkPolicy}} admits ingress only from pods
  labelled \{{spark.operator/spark-cluster-name: <cluster>}}:

  \{code:yaml}
  podSelector:
    matchLabels: \{spark-role: worker, spark.operator/spark-cluster-name: <cluster>}
  ingress:
  - from:
    - podSelector:
        matchLabels: \{spark.operator/spark-cluster-name: <cluster>}
  policyTypes: [Ingress]
  \{code}

  A \{{SparkApplication}} that attaches to a standalone \{{SparkCluster}}
  (\{{spark.master=spark://<cluster>-master-svc:7077}}) is a separate resource. Its driver
  pod is labelled \{{spark-role: driver}} and \{{spark.operator/spark-app-name: <app>}},
  never the cluster label, so every driver-to-worker connection is dropped.

  The gap is invisible under normal load. Worker egress is unrestricted and no policy
  selects driver pods, so executors register with the driver and tasks run normally. Spark
  only uses the driver-to-executor direction when a task result exceeds
  \{{spark.task.maxDirectResultSize}} (1 MB): the executor then stores the result in its
  block manager and returns an \{{IndirectTaskResult}} for the driver to fetch. That fetch
  times out, \{{RetryingBlockTransferor}} retries three times, and the task fails with:

  \{code}
  TaskResultLost (result lost from block manager)
  \{code}

  After four attempts the stage aborts. The failure is not reachable any other way: that
  branch in \{{TaskResultGetter#enqueueSuccessfulTask}} only runs for an
  \{{IndirectTaskResult}}.

  It cannot be worked around from the client side either. Executors read
  \{{spark.task.maxDirectResultSize}} from the driver \{{SparkConf}} at launch, so a Spark
  Connect client cannot raise it after the session has started.

  Observed on a Spark Connect session attached to a standalone \{{SparkCluster}}, on a CNI
  that enforces NetworkPolicy. Three of 25 tasks in a write stage produced results above
  the threshold and the job aborted; every other task in the same stage succeeded. Driver
  log:

  \{code}
  java.io.IOException: Connecting to /<executor-ip>:<ephemeral-port> timed out (120000 ms)
        at org.apache.spark.network.client.TransportClientFactory.createClient(...)
        at org.apache.spark.network.netty.NettyBlockTransferService$$anon$2.createAndStart(...)
        at org.apache.spark.network.shuffle.RetryingBlockTransferor.transferAllOutstanding(...)
        at org.apache.spark.storage.BlockManager.fetchRemoteManagedBuffer(...)
        at org.apache.spark.scheduler.TaskResultGetter$$anon$3.run(...)
  \{code}

  Proposed fix: add a second ingress peer to the generated policy admitting same-namespace
  pods labelled \{{spark-role: driver}}. This only widens ingress and cannot deny traffic
  that was previously allowed.
  \{code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@spark.apache.org
For additional commands, e-mail: issues-help@spark.apache.org