Skip to content

Conversation

@LuciferYang
Copy link
Contributor

@LuciferYang LuciferYang commented Jul 31, 2019

What changes were proposed in this pull request?

If MEMORY_OFFHEAP_ENABLED is true, add MEMORY_OFFHEAP_SIZE to resource requested for executor to ensure instance has enough memory to use.

In this pr add a helper method executorOffHeapMemorySizeAsMb in YarnSparkHadoopUtil.

How was this patch tested?

Add 3 new test suite to test YarnSparkHadoopUtil#executorOffHeapMemorySizeAsMb

@LuciferYang LuciferYang changed the title [SPARK-28577]Ensure executorMemoryHead requested value not less than offHeapSize when offHeap is enabl [SPARK-28577]Ensure executorMemoryOverHead requested value not less than offHeapSize when offHeap is enable Jul 31, 2019
@LuciferYang LuciferYang changed the title [SPARK-28577]Ensure executorMemoryOverHead requested value not less than offHeapSize when offHeap is enable [SPARK-28577]Ensure executorMemoryOverHead requested value not less than offHeapSize when offHeap enable Jul 31, 2019
@LuciferYang
Copy link
Contributor Author

cc @xuanyuanking

@LuciferYang LuciferYang changed the title [SPARK-28577]Ensure executorMemoryOverHead requested value not less than offHeapSize when offHeap enable [SPARK-28577][YARN]Ensure executorMemoryOverHead requested value not less than offHeapSize when offHeap enable Jul 31, 2019
@LuciferYang
Copy link
Contributor Author

@kiszk Thx for ur review ~
commit c44a33e fix this

Copy link
Member

@xuanyuanking xuanyuanking left a comment

Choose a reason for hiding this comment

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

+1 for choosing a safer config, just one nit for the log. cc @jerryshao.

sparkConf.getSizeAsMb(MEMORY_OFFHEAP_SIZE.key, MEMORY_OFFHEAP_SIZE.defaultValueString)
require(size > 0,
s"${MEMORY_OFFHEAP_SIZE.key} must be > 0 when ${MEMORY_OFFHEAP_ENABLED.key} == true")
logInfo(s"${MEMORY_OFFHEAP_ENABLED.key} is true, ${MEMORY_OFFHEAP_SIZE.key} is $size, " +
Copy link
Member

Choose a reason for hiding this comment

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

How about only gives a warning log when we find the overhead is less than offHeap? We use the warning to notice user the changes of the config and explain why we change it, so there's no extra log for the same behavior as before.

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 2, 2019

Choose a reason for hiding this comment

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

@xuanyuanking Thx for ur review , in 9421fbe change to print a warn log when offHeapSize more than overhead

}
size
} else 0
math.max(overhead, offHeap).toInt
Copy link
Contributor

@jerryshao jerryshao Aug 2, 2019

Choose a reason for hiding this comment

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

I was wondering if it is better to change to overhead = overhead + offHeap if off-heap is enabled. Mainly because off heap memory is not only used for Spark itself related, but also for Netty and other native libraries. If we only guarantee overhead > offHeap, then it would somehow occupy the usage of Netty and others. Just my two cents :).

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 2, 2019

Choose a reason for hiding this comment

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

Got it ~, So should we add 2 field like isOffHeapEnabled and executorOffHeapMemory to YarnAllocator then use executorMemory + memoryOverhead + pysparkWorkerMemory + executorOffHeapMemory to request resource and no longer modify memoryOverhead?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, that's a bit complex as for now:

  1. If we assume overhead memory includes all the off-heap memory Spark used (include everything). Then user should be aware of the different off-heap memory settings, and carefully set the overhead number to cover all the usages.
  2. If we assume that overhead memory only related to some additional memory usage (not explicitly set by Spark, like off-heap memory). Then the overall executor memory should add all as mentioned above.

I think it would be better to involve other's opinion. CC @vanzin @tgravescs .

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah I always thought this was a bit weird off heap was just included in the overhead, but never took the time to go back to see if it was discussed.

I think it's better to specifically add the off heap instead of include in the overhead. Just like we did for the pyspark memory. executorMemory + memoryOverhead + pysparkWorkerMemory + executorOffHeapMemory. I think that keeps things more consistent and obvious to the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tgravescs Agree with you, overhead should be used to describe memory not use by Spark, like Netty used or JVM used as @jerryshao said, and we should clearly describe it in the configuration document.

So change to use executorMemory + memoryOverhead + pysparkWorkerMemory + executorOffHeapMemory to request resource?

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 6, 2019

Choose a reason for hiding this comment

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

image
@beliefer Now YarnAllocator line 150 use executorMemory + memoryOverhead + pysparkWorkerMemory to new Resource Instance, Is this wrong?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On the other hand, if the user configures offheapMemory and pysparkWorkerMemory,
He still needs to configure overhead Memroy and ensure that the configuration is reasonable(memoryOverhead > offheapMemory + pysparkWorkerMemory) in Yarn mode, so that users may need to care about more details.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jerryshao Is the current approach feasible?

Copy link
Contributor

@beliefer beliefer Aug 6, 2019

Choose a reason for hiding this comment

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

I have check the code and doc, there exists some inconsistent. According to the docs, memoryOverhead should comprise pysparkWorkerMemory. But the code have different behavior.
We need to fix the inconsistent. I think should reduce parameter to control memory, because more simple. @JoshRosen Could you take a look at this PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @tgravescs 's opinion.

yeah, I understand that, if we are going to change it, 3.0 is a good time to change that behavior. Like I said, I had found the off heap included in the overhead as confusing because you already had another separate config, why do I as a user have to add it into another config.

If overhead memory includes off-heap memory, pysparkWorkMemory and others, it makes user hard to set a proper overhead memory, users should know every other settings and figure out a proper number. As of time 3.0, I think we should give a good definition of overhead memory, it can be inconsistent with old version.

@LuciferYang LuciferYang changed the title [SPARK-28577][YARN]Ensure executorMemoryOverHead requested value not less than offHeapSize when offHeap enable [SPARK-28577][YARN]Resource capability requested for each executor add offHeapSize Aug 2, 2019
@LuciferYang LuciferYang changed the title [SPARK-28577][YARN]Resource capability requested for each executor add offHeapSize [SPARK-28577][YARN]Resource capability requested for each executor add offHeapMemorySize Aug 2, 2019
@jerryshao
Copy link
Contributor

ok to test.

@SparkQA
Copy link

SparkQA commented Aug 6, 2019

Test build #108704 has finished for PR 25309 at commit 4fb5362.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@beliefer
Copy link
Contributor

beliefer commented Aug 7, 2019

@jerryshao IMHO, Spark should reduce configuration parameters first. And then I think no matter what memory is, we use the unified parameter to control is better. Maybe separate parameter looks easy to understand.

@jerryshao
Copy link
Contributor

@beliefer I'm a little confused, do you want a unified parameter, or separated parameters, could you explain more?

IMHO, Spark should reduce configuration parameters first. And then I think no matter what memory is, we use the unified parameter to control is better. Maybe separate parameter looks easy to understand.

val sizeInMB =
sparkConf.getSizeAsMb(MEMORY_OFFHEAP_SIZE.key, MEMORY_OFFHEAP_SIZE.defaultValueString).toInt
require(sizeInMB > 0,
s"${MEMORY_OFFHEAP_SIZE.key} must be > 0 when ${MEMORY_OFFHEAP_ENABLED.key} == true")
Copy link
Contributor

Choose a reason for hiding this comment

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

Please check if MEMORY_OFFHEAP_SIZE could equal to 0. The definition of MEMORY_OFFHEAP_SIZE checks that it could be >= 0.

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 8, 2019

Choose a reason for hiding this comment

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

A little conflict with the MemoryManager as following:
image

if MEMORY_OFFHEAP_ENABLED is enable, MemoryManager.tungstenMemoryMode will enter OFF_HEAP branch and need MEMORY_OFFHEAP_SIZE > 0 and I think we should be consistent.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then I think we should change the code here.

.checkValue(_ >= 0, "The off-heap memory size must not be negative")

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 8, 2019

Choose a reason for hiding this comment

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

0 is defaultValue, change to

.checkValue(_ > 0, "The off-heap memory size must be positive")
.createWithDefault(1)

?
otherwise will throw IllegalArgumentException when offHeapEnabled is false and defaultValue is 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe we should give a suitable defaultValue ,like 1073741824(1g)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jerryshao Do we need to change 0 to a suitable defaultValue?

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, then I would suggest not to change it. Seems there's no good value which could cover most of the scenarios, so good to leave as it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok~

Copy link
Contributor

Choose a reason for hiding this comment

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

its odd that check is >= 0 in the config, seems like we should change but can you file a separate jira for that?

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 23, 2019

Choose a reason for hiding this comment

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

OK~ I will add a new jira to discuss this issue.

s"memory capability of the cluster ($maxMem MB per container)")
val executorMem = executorMemory + executorMemoryOverhead + pysparkWorkerMemory
val executorMem =
executorMemory + executorOffHeapMemory +executorMemoryOverhead + pysparkWorkerMemory
Copy link
Contributor

Choose a reason for hiding this comment

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

white space after +.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

assert(executorOffHeapMemory == offHeapMemoryInMB)
}

test("executorMemoryOverhead when MEMORY_OFFHEAP_ENABLED is true, " +
Copy link
Contributor

Choose a reason for hiding this comment

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

Just wondering if we could add some yarn side UT to verify the container memory size, rather than verifying the correctness of off-heap configuration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok ~ I'll try to add it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add a new test suite SPARK-28577#YarnAllocator.resource.memory should include offHeapSize when offHeapEnabled is true. in YarnAllocatorSuite

@SparkQA
Copy link

SparkQA commented Aug 8, 2019

Test build #108823 has finished for PR 25309 at commit c03db87.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@LuciferYang
Copy link
Contributor Author

@jerryshao Should we continue to complete this patch?

@SparkQA
Copy link

SparkQA commented Aug 23, 2019

Test build #109620 has finished for PR 25309 at commit 40ad336.

  • This patch fails due to an unknown error code, -9.
  • This patch merges cleanly.
  • This patch adds no public classes.

@tgravescs
Copy link
Contributor

test this please

@SparkQA
Copy link

SparkQA commented Aug 23, 2019

Test build #109642 has finished for PR 25309 at commit 40ad336.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

def executorOffHeapMemorySizeAsMb(sparkConf: SparkConf): Int = {
if (sparkConf.get(MEMORY_OFFHEAP_ENABLED)) {
val sizeInMB =
Utils.byteStringAsMb(s"${sparkConf.get(MEMORY_OFFHEAP_SIZE)}B").toInt
Copy link
Contributor

Choose a reason for hiding this comment

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

you should be able to use memoryStringToMb instead.

// Convert to bytes, rather than directly to MiB, because when no units are specified the unit
// is assumed to be bytes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tgravescs Thx for ur advice~

@SparkQA
Copy link

SparkQA commented Aug 26, 2019

Test build #109713 has finished for PR 25309 at commit 0020a02.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

s"memory capability of the cluster ($maxMem MB per container)")
val executorMem = executorMemory + executorMemoryOverhead + pysparkWorkerMemory
val executorMem =
executorMemory + executorOffHeapMemory + executorMemoryOverhead + pysparkWorkerMemory
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should also update the doc to reflect the changes here.

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 26, 2019

Choose a reason for hiding this comment

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

ok, I'll try to update description about MemoryOverhead & OffHeapMemory in configuration.md, in this pr or new one ?

Copy link
Contributor

Choose a reason for hiding this comment

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

It would be better to change the doc in this PR.

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 27, 2019

Choose a reason for hiding this comment

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

b3b5f83 update the configuration.md.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's some strange behavior about spark.executor.pyspark.memory:
if we config spark.executor.pyspark.memory , the pyspark executor memory is Independent , but if we not config spark.executor.pyspark.memory , the memoryOverhead include it.

s"offHeap memory ($executorOffHeapMemory) MB, overhead ($executorMemoryOverhead MB), " +
s"and PySpark memory ($pysparkWorkerMemory MB) is above the max threshold ($maxMem MB) " +
s"of this cluster! Please check the values of 'yarn.scheduler.maximum-allocation-mb' " +
s"and/or 'yarn.nodemanager.resource.memory-mb'.")
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to add string interpolation for this line and above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

02c0f2a fix this

@SparkQA
Copy link

SparkQA commented Aug 26, 2019

Test build #109729 has finished for PR 25309 at commit 02c0f2a.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

Copy link
Contributor

@tgravescs tgravescs left a comment

Choose a reason for hiding this comment

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

+1 looks good to me

@SparkQA
Copy link

SparkQA commented Aug 27, 2019

Test build #109788 has finished for PR 25309 at commit b3b5f83.

  • This patch fails due to an unknown error code, -9.
  • This patch merges cleanly.
  • This patch adds no public classes.

@kiszk
Copy link
Member

kiszk commented Aug 27, 2019

retest this please

@SparkQA
Copy link

SparkQA commented Aug 27, 2019

Test build #109811 has finished for PR 25309 at commit b3b5f83.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

(e.g. increase <code>spark.driver.memoryOverhead</code> or
<code>spark.executor.memoryOverhead</code>).
<em>Note:</em> If off-heap memory is enabled, may need to raise
<code>spark.driver.memoryOverhead</code> size.
Copy link
Contributor

Choose a reason for hiding this comment

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

actually this brings up a good question, the size configs say they work for off heap size for executors, so what cases does this need to apply to the driver. Is this config really applying to both driver and executors for things like broadcast blocks, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have the same question :),broadcast in driver side may not use offheap, TorrentBroadcast.writeBlocks method call blockManager.putSingle method use StorageLevel.MEMORY_AND_DISK and call blockManager.putBytes method use StorageLevel.MEMORY_AND_DISK_SER, both these 2 StorageLevel not use offheap memory, maybe we should remove these 2 line.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I found @beliefer add these description in #24671, can you help us to explain where offheap is used in driver side? Thx ~

Copy link
Contributor

Choose a reason for hiding this comment

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

Originally, off-heap memory will not affect the container memory, so we must consider it and config spark.driver.memoryOverhead bigger.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But which component uses offheap in driver side?

private[yarn] val resource: Resource = {
val resource = Resource.newInstance(
executorMemory + memoryOverhead + pysparkWorkerMemory, executorCores)
executorMemory + executorOffHeapMemory + memoryOverhead + pysparkWorkerMemory, executorCores)
Copy link
Contributor

@beliefer beliefer Aug 28, 2019

Choose a reason for hiding this comment

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

According line 258 to 260 in docs/configuration.md, memoryOverhead includes pysparkWorkerMemory, but looks difference here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Described in the document is Additional memory includes PySpark executor memory (when <code>spark.executor.pyspark.memory</code> is not configured), I think we need a new jira to discuss how to solve this problem.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, this makes me confused.

Copy link
Member

Choose a reason for hiding this comment

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

Isn't this what spark.executor.memoryOverhead already adds via memoryOverhead?
I guess I'm wondering what MEMORY_OFFHEAP_SIZE does that's supposed to be different.

Copy link
Contributor Author

@LuciferYang LuciferYang Sep 2, 2019

Choose a reason for hiding this comment

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

@srowen memoryOverhead include MEMORY_OFFHEAP_SIZE before this pr, and memoryOverhead and MEMORY_OFFHEAP_SIZE had to be modified at the same time to ensure request enough resources from yarn if I want to increase MEMORY_OFFHEAP_SIZE , this is not user friendly, and this has always been confusing, why we need to modify two memory-related parameters simultaneously for one purpose? This pr let them be independent.

processes running in the same container. The maximum memory size of container to running executor
is determined by the sum of <code>spark.executor.memoryOverhead</code> and
<code>spark.executor.memory</code>.
<em>Note:</em> Additional memory includes PySpark executor memory
Copy link
Contributor

Choose a reason for hiding this comment

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

another problem is Additional better than Non-heap?

Copy link
Contributor Author

@LuciferYang LuciferYang Aug 28, 2019

Choose a reason for hiding this comment

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

How to explain Non-heap? Now MemoryOverHead not includes offheap, and maybe PySpark executor memory should add a default value and separate from MemoryOverHead, should we redefinition this concept.
Any other suggested names?

Copy link
Contributor

Choose a reason for hiding this comment

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

So this PR looks a little conflict with origin definition.
Non-heap includes all the memory but java heap.

Copy link
Contributor

Choose a reason for hiding this comment

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

that is the point, we are changing it so that you don't have to include off heap inside of overhead memory. User is already specifying off heap size so why should they have to add it to overhead memory? it works just the other configs - pyspark memory, heap memory,

Copy link
Contributor

Choose a reason for hiding this comment

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

I know the meaning of this PR. Maybe the new idea is a way. As I know, the origin decision is to unify all the different part.

<td>executorMemory * 0.10, with minimum of 384 </td>
<td>
Amount of non-heap memory to be allocated per executor process in cluster mode, in MiB unless
Amount of additional memory to be allocated per executor process in cluster mode, in MiB unless
Copy link
Contributor Author

Choose a reason for hiding this comment

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

maybe we should remove interned strings, it use heap space after Java8

@SparkQA
Copy link

SparkQA commented Sep 4, 2019

Test build #110085 has finished for PR 25309 at commit bb29488.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

Copy link
Contributor

@tgravescs tgravescs left a comment

Choose a reason for hiding this comment

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

+1

@asfgit asfgit closed this in a07f795 Sep 4, 2019
@xuanyuanking
Copy link
Member

@LuciferYang Because it has been merged to master by Thomas. :)
Thanks for your contribution.

@LuciferYang
Copy link
Contributor Author

Thanks to all reviewers ~ @jerryshao @tgravescs @xuanyuanking @kiszk @beliefer @srowen

@LuciferYang LuciferYang deleted the spark-28577 branch June 6, 2022 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants