Repository navigation
Conversation
From Spark 4.0 (SPARK-45762) SparkContext creates the shuffle manager right after it initializes the plugins, from the same SparkConf, and executors take their conf from the driver's when they register. CometDriverPlugin can therefore choose the manager for an application that did not, instead of leaving Comet to disable itself. An application that sets spark.shuffle.manager keeps its value. Before 4.0 the SparkEnv already holds the manager when plugins initialize, so the plugin does nothing there.
Use Spark's SHUFFLE_MANAGER key throughout, state the Spark 4.0 rule in fewer places, add an upgrade guide entry, and run the plugin's real-session test in CometPluginsUnifiedModeSuite rather than a session of its own.
kazuyukitanimura
left a comment
There was a problem hiding this comment.
I read the executor side of the Spark source the same way you did. CoarseGrainedSchedulerBackend.sparkProperties is a lazy sc.conf.getAll, and Executor initializes plugins before initializeShuffleManager(). Every test runs in local mode, though, where executors share the driver's SparkEnv, so nothing exercises that path. If the reasoning were wrong, the driver would plan Comet shuffles that SortShuffleManager on the executors can't write. Would you be able to do one manual run on a standalone or Kubernetes cluster with Spark 4.0, the plugin, and no spark.shuffle.manager? Running sc.parallelize(1 to 100, 10).map(_ => org.apache.spark.SparkEnv.get.shuffleManager.getClass.getName).distinct.collect plus a GROUP BY query would do, with the result noted in the description.
docs/source/contributor-guide/plugin_overview.md:43 and docs/source/about/faq.md:130
▎ Two pages still describe the old behavior. plugin_overview.md lists each step CometDriverPlugin takes, and the new shuffle-manager step isn't there. Its Shuffle section also says the manager must be registered. The FAQ bullet "Comet's shuffle manager is not set" says Comet disables itself whenever spark.shuffle.manager does not name Comet's
▎ manager. That's no longer true on Spark 4.0 with CometPlugin. Could you update both in this PR?
docs/source/user-guide/latest/migration-guide.md:66
▎ The applications this entry affects are the ones that never ran Comet, so they're also the most likely to have left spark.executor.memoryOverhead at Spark's default. Comet's native memory outside the off-heap pool comes out of that overhead, and YARN or Kubernetes can kill an executor that runs out of it. The plugin warns at startup, but that
▎ warning is easy to miss after an upgrade. Could the entry link to Configuring Comet Memory?
spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleManager.scala:283
▎ With this PR, CometShuffleManager runs every shuffle in more applications, including RDD shuffles and Spark exchanges that Comet doesn't replace. I found three places where it handles those ordinary shuffles differently from SortShuffleManager. They predate this PR, so could you file a tracking issue and link it here?
▎ - Spark's ShuffleExchangeExec copies every row, because the manager isn't a SortShuffleManager.
▎ - getWriter delegates to the inner sortShuffleManager, which records each map task in its own taskIdMapsForShuffle. unregisterShuffle never calls sortShuffleManager.unregisterShuffle, so those entries stay on the executor heap until the application ends.
▎ - The resolver is built with a fresh map at line 107 instead of taskIdMapsForShuffle. IndexShuffleBlockResolver records blocks migrated in during decommissioning in that map, so unregisterShuffle never deletes them.
| // disable itself. Only from Spark 4.0 (SPARK-45762) does SparkContext create the manager after | ||
| // it initializes the plugins, from the same conf that executors then fetch. An application's own | ||
| // choice, even Spark's, is kept: it may depend on that manager, as Celeborn does. | ||
| private[apache] def maybeSetShuffleManager(conf: SparkConf): Unit = { |
There was a problem hiding this comment.
Thanks for working this out from the Spark 4.0 source. I checked the same ordering in v4.0.0 and it holds on the driver and the executors. One case concerns me. maybeSetShuffleManager checks spark.comet.enabled and Comet shuffle, but isCometLoaded can still disable Comet afterwards. That happens on a big-endian host, when spark.sql.parquet.int96TimestampConversion=true, or when the native library fails to load and spark.comet.nativeLoadRequired is left at false. In those applications this PR swaps SortShuffleManager for CometShuffleManager, and Comet never runs. Spark's ShuffleExchangeExec.needToCopyObjectsBeforeShuffle returns true for any manager that is not a SortShuffleManager, so every Spark exchange then copies each row before the shuffle. On 1.2 the same application ran on Spark's manager with no copy. Could the plugin skip setting the manager when it can see one of those conditions at startup? A small helper shared with isCometLoaded would keep the two from drifting. A test with one of those settings would lock it in.
There was a problem hiding this comment.
Done in bfc14c7. CometSparkSessionExtensions.unsupportedEnvironmentReason now holds the big-endian, INT96 and native-library checks. isCometLoaded and maybeSetShuffleManager both call it, so the two cannot drift. One difference: if the library fails to load and spark.comet.nativeLoadRequired is true, isCometLoaded throws, but the plugin treats that as supported and still sets the manager, so the failure shows up where it did before rather than at startup. CometDriverPluginShuffleManagerSuite has a test with spark.sql.parquet.int96TimestampConversion=true. The other two conditions can't be set in a unit test. The check only sees the startup value of the INT96 setting, since a session can still change it later.
| } | ||
| } | ||
|
|
||
| class CometDriverPluginShuffleManagerSuite extends SparkFunSuite { |
There was a problem hiding this comment.
CometDriverPluginShuffleManagerSuite is a new top-level suite. CI runs the plugin suites from an explicit list passed as -DwildcardSuites in .github/workflows/pr_build_linux.yml (around line 582) and pr_build_macos.yml (around line 248). Nothing in either list matches this name, so the version-gate tests and the keep-the-user's-value tests don't run in CI. Could you add it to both lists? Once it's registered, the run-all-spark-profiles label would cover 3.4 and 4.2, which the local runs in the description didn't include.
There was a problem hiding this comment.
Added to both pr_build_linux.yml and pr_build_macos.yml in bfc14c7.
comphead
left a comment
There was a problem hiding this comment.
Thanks @andygrove. I read the ordering again in v4.0.1 and v4.1.1 and it holds. sc.conf is the _conf passed to the driver SparkEnv, executors read sparkProperties lazily after the driver plugin ran, and registerWithExternalShuffleServer takes the class name from the conf. I have not run it on a cluster.
|
|
||
| ## Upgrading to Comet 1.3.0 | ||
|
|
||
| ### Shuffle Manager Set by the Plugin on Spark 4.0 and Later |
There was a problem hiding this comment.
The guide's introduction says every behavior change below names a spark.comet.legacy.* key, and the 1.2.0 section says up front when none is needed. This entry names no key. Running an application in Comet instead of Spark is the "which operators run natively" kind of change that the introduction excludes, so could the 1.3.0 section say it needs no legacy key, as 1.2.0 does?
There was a problem hiding this comment.
The 1.3.0 section now says up front that it needs no spark.comet.legacy.* key, as 1.2.0 does (bfc14c7).
|
cc @snmvaughan |
… update docs The plugin no longer sets CometShuffleManager on a big-endian host, with spark.sql.parquet.int96TimestampConversion=true, or when the native library fails to load, since Comet would not run and Spark's exchanges would copy every row. isCometLoaded and the plugin share one helper for these checks. Register CometDriverPluginShuffleManagerSuite in the PR build workflows, and bring plugin_overview.md, the FAQ and the upgrade guide up to date.
|
Thanks for turning these around so quickly. I noticed nothing has run on bfc14c7 yet. CI (fork) says no run was found on your fork for that commit, and Required Checks here passes without a build. The commit changes isCometLoaded, which every Comet session goes through, so could you start the fork run? I'll add run-all-spark-profiles too, so 3.4, Following up on the cluster run. @comphead and I both read the executor side the same way you did, but none of us has run it. Every test runs in local mode, where executors share the driver's SparkEnv, so nothing in CI covers this. If the reasoning were wrong, every Comet shuffle would fail on the executors. Could you do one run on a standalone or Kubernetes cluster with Spark 4.0, the plugin, and no spark.shuffle.manager before this merges? sc.parallelize(1 to 100, 10).map(_ => org.apache.spark.SparkEnv.get.shuffleManager.getClass.getName).distinct.collect plus a GROUP BY would be enough. |
Which issue does this PR close?
N/A. There is no tracking issue.
Rationale for this change
An application has to set
spark.shuffle.managertoCometShuffleManageritself. If it does not, Comet disables itself and logs a warning, so the plugin alone gives a user nothing.On Spark 3.4 and 3.5 the plugin cannot fix this, because
SparkEnv.createbuilds the shuffle manager before any plugin runs. From Spark 4.0 (SPARK-45762)SparkContextcreates it right after it initializes the plugins (SparkContext.scala:PluginContainer(...), then_env.initializeShuffleManager()), from the sameSparkConf. Executors take their conf from the driver'ssc.conf.getAllwhen they register, which happens after the plugin has run, and their owninitializeShuffleManager()also follows their plugin initialization. So the driver plugin can choose the manager for the whole application.What changes are included in this PR?
CometDriverPlugin.initcalls a newmaybeSetShuffleManager, which setsspark.shuffle.managertoCometShuffleManageron Spark 4.0 and later. It does so only whenspark.comet.enabledand Comet shuffle are on and the application did not setspark.shuffle.manager. An explicit value is always kept, includingsortand the Celeborn manager, and Comet then disables itself as before. It runs before the cache serializer check, which only installs Comet's serializer with one of Comet's shuffle managers.spark.sql.parquet.int96TimestampConversion=true, or when the native library fails to load andspark.comet.nativeLoadRequiredis false. Comet would not run there, and Spark's exchanges would copy every row for want of aSortShuffleManager.CometSparkSessionExtensions.unsupportedEnvironmentReasonholds these checks, andisCometLoadedand the plugin both call it. If the library fails to load andnativeLoadRequiredis true, the plugin still sets the manager and leaves the error toisCometLoaded, as before.spark.comet.shuffle.enableddescription, the shuffle tuning guide, the plugin overview and the FAQ, and a new 1.3.0 entry in the upgrade guide. The entry covers the one behavior change: an application on Spark 4.0 or later that registers the plugin without a shuffle manager used to run without Comet and now runs with it. It needs nospark.comet.legacy.*key, and it points to Configuring Comet Memory, since these applications may have leftspark.executor.memoryOverheadat Spark's default.How are these changes tested?
CometDriverPluginShuffleManagerSuitetests the decision: the version gate, a user-set value being kept (sort,tungsten-sort, Celeborn, a custom class), and Comet or Comet shuffle disabled, including through the deprecatedspark.comet.exec.shuffle.enabledkey, and an environment where Comet disables itself (spark.sql.parquet.int96TimestampConversion=true). The suite is in the plugin suite lists ofpr_build_linux.ymlandpr_build_macos.yml.CometPluginsUnifiedModeSuitenames no shuffle manager and registers the plugin. A new test checks that on 4.0 and laterSparkEnvholdsCometShuffleManagerand the plan has Comet shuffle, and that on 3.5 Comet stays disabled.CometDriverPluginShuffleManagerSuite,CometPluginsUnifiedModeSuite,CometPluginsSuite,CometPluginsSparkShuffleManagerSuiteandCometPluginsExtensionOnlySuiteon the 4.0 profile, and the first two plusCometSparkSessionExtensionsSuiteon 3.5. Executors only run in the local-mode tests, so the executor side rests on reading the Spark 4.0.0 source. It has not been run on a standalone or Kubernetes cluster.The shuffle manager's handling of shuffles that Comet does not replace is tracked in #7488.