-
Notifications
You must be signed in to change notification settings - Fork 278
feat: Various improvements to memory pool configuration, logging, and documentation #2538
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
Changes from 29 commits
b3b0a85
191bbc4
2b1242e
f42be8f
6e987af
8ef56eb
43e83c2
ecce61e
f3051ba
f364962
edc3d0d
5f5f95e
8c8ad98
83ecd6e
07c69e7
7e4a482
648f3ee
767866b
d04d676
7fc62b6
c1a2053
e36785b
4848f64
5e812de
31e9914
2e125a1
e35f7e8
303ba75
c333959
c39afd9
4816437
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,41 +36,15 @@ than before. See the [Determining How Much Memory to Allocate] section for more | |
|
|
||
| [Determining How Much Memory to Allocate]: #determining-how-much-memory-to-allocate | ||
|
|
||
| Comet supports Spark's on-heap (the default) and off-heap mode for allocating memory. However, we strongly recommend | ||
| using off-heap mode. Comet has some limitations when running in on-heap mode, such as requiring more memory overall, | ||
| and requiring shuffle memory to be separately configured. | ||
| ### Configuring Comet Memory | ||
|
|
||
| ### Configuring Comet Memory in Off-Heap Mode | ||
|
|
||
| The recommended way to allocate memory for Comet is to set `spark.memory.offHeap.enabled=true`. This allows | ||
| Comet to share an off-heap memory pool with Spark, reducing the overall memory overhead. The size of the pool is | ||
| Comet shares an off-heap memory pool with Spark. The size of the pool is | ||
| specified by `spark.memory.offHeap.size`. For more details about Spark off-heap memory mode, please refer to | ||
| [Spark documentation]. For full details on configuring Comet memory in off-heap mode, see the [Advanced Memory Tuning] | ||
| section of this guide. | ||
|
|
||
| [Spark documentation]: https://spark.apache.org/docs/latest/configuration.html | ||
|
|
||
| ### Configuring Comet Memory in On-Heap Mode | ||
|
|
||
| ```{warning} | ||
| Support for on-heap memory pools is deprecated and will be removed from a future release. | ||
| ``` | ||
|
|
||
| Comet is disabled by default in on-heap mode, but can be enabled by setting `spark.comet.exec.onHeap.enabled=true`. | ||
|
|
||
| When running in on-heap mode, Comet memory can be allocated by setting `spark.comet.memoryOverhead`. If this setting | ||
| is not provided, it will be calculated by multiplying the current Spark executor memory by | ||
| `spark.comet.memory.overhead.factor` (default value is `0.2`) which may or may not result in enough memory for | ||
| Comet to operate. It is not recommended to rely on this behavior. It is better to specify `spark.comet.memoryOverhead` | ||
| explicitly. | ||
|
|
||
| Comet supports native shuffle and columnar shuffle (these terms are explained in the [shuffle] section below). | ||
| In on-heap mode, columnar shuffle memory must be separately allocated using `spark.comet.columnar.shuffle.memorySize`. | ||
| If this setting is not provided, it will be calculated by multiplying `spark.comet.memoryOverhead` by | ||
| `spark.comet.columnar.shuffle.memory.factor` (default value is `1.0`). If a shuffle exceeds this amount of memory | ||
| then the query will fail. For full details on configuring Comet memory in on-heap mode, see the [Advanced Memory Tuning] | ||
| section of this guide. | ||
|
|
||
| [shuffle]: #shuffle | ||
|
|
||
| [Advanced Memory Tuning]: #advanced-memory-tuning | ||
|
|
@@ -93,7 +67,7 @@ Baseline Spark Performance | |
|
|
||
| Comet Performance | ||
|
|
||
| - Comet requires at least 5 GB of RAM in off-heap mode and 6 GB RAM in on-heap mode, but performance at this level | ||
| - Comet requires at least 5 GB of RAM, but performance at this level | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is it onheap or offheap? |
||
| is around 340 seconds, which is significantly faster than Spark with any amount of RAM | ||
| - Comet running in off-heap with 8 cores completes the benchmark in 295 seconds, more than 2x faster than Spark | ||
| - It is worth noting that running Comet with only 4 cores and 4 GB RAM completes the benchmark in 520 seconds, | ||
|
|
@@ -114,79 +88,36 @@ Workarounds for this problem include: | |
|
|
||
| ## Advanced Memory Tuning | ||
|
|
||
| ### Configuring Off-Heap Memory Pools | ||
| ### Configuring Comet Memory Pools | ||
|
|
||
| Comet implements multiple memory pool implementations. The type of pool can be specified with `spark.comet.exec.memoryPool`. | ||
|
|
||
| The valid pool types for off-heap mode are: | ||
| The valid pool types are: | ||
|
|
||
| - `fair_unified` (default when `spark.memory.offHeap.enabled=true` is set) | ||
| - `fair_unified_global` (default when `spark.memory.offHeap.enabled=true` is set) | ||
| - `fair_unified` | ||
| - `greedy_unified` | ||
|
|
||
| Both of these pools share off-heap memory between Spark and Comet. This approach is referred to as | ||
| All of these pools share off-heap memory between Spark and Comet. This approach is referred to as | ||
| unified memory management. The size of the pool is specified by `spark.memory.offHeap.size`. | ||
|
|
||
| The `greedy_unified` pool type implements a greedy first-come first-serve limit. This pool works well for queries that do not | ||
| need to spill or have a single spillable operator. | ||
| Comet's memory accounting isn't 100% accurate and this can result in Comet using more memory than it reserves, | ||
| leading to out-of-memory exceptions. To work around this issue, it is possible to | ||
| set `spark.comet.exec.memoryPool.fraction` to a value less than `1.0` to restrict the amount of memory that can be | ||
| reserved by Comet. | ||
|
|
||
| The `fair_unified` pool type prevents operators from using more than an even fraction of the available memory | ||
| The `fair_unified` pool types prevents operators from using more than an even fraction of the available memory | ||
| (i.e. `pool_size / num_reservations`). This pool works best when you know beforehand | ||
| the query has multiple operators that will likely all need to spill. Sometimes it will cause spills even | ||
| when there is sufficient memory in order to leave enough memory for other operators. | ||
|
|
||
| ### Configuring On-Heap Memory Pools | ||
|
|
||
| ```{warning} | ||
| Support for on-heap memory pools is deprecated and will be removed from a future release. | ||
| ``` | ||
|
|
||
| When running in on-heap mode, Comet will use its own dedicated memory pools that are not shared with Spark. | ||
| `fair_unified_global` allows any task to use the full off-heap memory pool. | ||
|
||
|
|
||
| The type of pool can be specified with `spark.comet.exec.memoryPool`. The default setting is `greedy_task_shared`. | ||
|
|
||
| The valid pool types for on-heap mode are: | ||
|
|
||
| - `greedy` | ||
| - `greedy_global` | ||
| - `greedy_task_shared` | ||
| - `fair_spill` | ||
| - `fair_spill_global` | ||
| - `fair_spill_task_shared` | ||
| - `unbounded` | ||
|
|
||
| Pool types ending with `_global` use a single global memory pool between all tasks on same executor. | ||
|
|
||
| Pool types ending with `_task_shared` share a single memory pool across all attempts for a single task. | ||
|
|
||
| Other pool types create a dedicated pool per native query plan using a fraction of the available pool size based on number of cores | ||
| `fair_unified` restricts each task to using a fraction of the off-heap memory pool based on number of cores | ||
| and cores per task. | ||
|
|
||
| The `greedy*` pool types use DataFusion's [GreedyMemoryPool], which implements a greedy first-come first-serve limit. This | ||
| pool works well for queries that do not need to spill or have a single spillable operator. | ||
|
|
||
| The `fair_spill*` pool types use DataFusion's [FairSpillPool], which prevents spillable reservations from using more | ||
| than an even fraction of the available memory sans any unspillable reservations | ||
| (i.e. `(pool_size - unspillable_memory) / num_spillable_reservations`). This pool works best when you know beforehand | ||
| the query has multiple spillable operators that will likely all need to spill. Sometimes it will cause spills even | ||
| when there was sufficient memory (reserved for other operators) to avoid doing so. Unspillable memory is allocated in | ||
| a first-come, first-serve fashion | ||
|
|
||
| The `unbounded` pool type uses DataFusion's [UnboundedMemoryPool], which enforces no limit. This option is useful for | ||
| development/testing purposes, where there is no room to allow spilling and rather choose to fail the job. | ||
| Spilling significantly slows down the job and this option is one way to measure the best performance scenario without | ||
| adjusting how much memory to allocate. | ||
|
|
||
| [GreedyMemoryPool]: https://docs.rs/datafusion/latest/datafusion/execution/memory_pool/struct.GreedyMemoryPool.html | ||
| [FairSpillPool]: https://docs.rs/datafusion/latest/datafusion/execution/memory_pool/struct.FairSpillPool.html | ||
| [UnboundedMemoryPool]: https://docs.rs/datafusion/latest/datafusion/execution/memory_pool/struct.UnboundedMemoryPool.html | ||
|
|
||
| ### Configuring spark.executor.memoryOverhead in On-Heap Mode | ||
|
|
||
| In some environments, such as Kubernetes and YARN, it is important to correctly set `spark.executor.memoryOverhead` so | ||
| that it is possible to allocate off-heap memory when running in on-heap mode. | ||
|
|
||
| Comet will automatically set `spark.executor.memoryOverhead` based on the `spark.comet.memory*` settings so that | ||
| resource managers respect Apache Spark memory configuration before starting the containers. | ||
| The `greedy_unified` pool type implements a greedy first-come first-serve limit. This pool works well for queries that do not | ||
| need to spill or have a single spillable operator. | ||
|
|
||
| ## Optimizing Joins | ||
|
|
||
|
|
||
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.
Default is 1.0 so that this change is not a breaking change