-
Notifications
You must be signed in to change notification settings - Fork 28.9k
[SPARK-21527][CORE] Use buffer limit in order to use JAVA NIO Util's buffercache #18730
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
Conversation
|
ok to test |
|
looks reasonable, do you have some performance numbers? |
|
|
||
| /** | ||
| * Write this buffer to a channel with slice. | ||
| */ |
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.
can we use this one to replace writeFully?
|
Test build #81018 has finished for PR 18730 at commit
|
|
Test build #81020 has finished for PR 18730 at commit
|
|
retest this please |
|
@cloud-fan Thanks for your time to review this pr.Actually,there is an application in our cluster always failed with direct memory oom.I have not measured performance with some benchmark test,but this feature has run in our cluster for a long time(since last year) and i observed this has not caused any performance issue.By the way, application with direct memory issue caused by 'BufferCache' out of control has not occur since then. |
|
Test build #81023 has finished for PR 18730 at commit
|
|
It would be great to benchmark this improvement, otherwise we are not sure there is no regression. |
| def writeWithSlice(channel: WritableByteChannel): Unit = { | ||
| for (bytes <- getChunks()) { | ||
| val capacity = bytes.limit() | ||
| while (bytes.position() < capacity) { |
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.
Should we replace Math.min(...) with Math.min(capacity, bytes.position + NIO_BUFFER_LIMIT.toLong)? I am afraid about int underflow. For example, if capacity = 0x7FFFFFF0 and bytes.position = 0x7FFFFF00, the result of bytes.position + NIO_BUFFER_LIMIT.toInt is negative (i.e. greater than 0x80000000).
To avoid this underflow, it would be good to compare them by using long.
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.
Good review.I refactor the code.
|
@jiangxb1987 Ok,i will try to do some benchmark tesing. |
|
I mock some local test for two different api. From the simple test result, we can see slice will not affect the performance of write bytes.Test result below: Test code below: |
|
Test build #81068 has finished for PR 18730 at commit
|
|
Test build #81061 has finished for PR 18730 at commit
|
|
Test build #81064 has finished for PR 18730 at commit
|
|
Test build #81069 has finished for PR 18730 at commit
|
|
Thank you for preparing a benchmark. Could you please write a benchmark using Benchmark class? |
|
| private[spark] val BUFFER_WRITE_CHUNK_SIZE = | ||
| ConfigBuilder("spark.buffer.write.chunkSize") | ||
| .internal() | ||
| .doc("The block size limit when use ChunkedByteBuffer to writeFully bytes.") |
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.
The chunk size during writing out the bytes of ChunkedByteBuffer
|
Test build #81085 has finished for PR 18730 at commit
|
|
LGTM, pending jenkins |
|
Thanks for your time @cloud-fan |
|
Test build #81087 has finished for PR 18730 at commit
|
|
Test build #81086 has finished for PR 18730 at commit
|
|
Test build #81089 has finished for PR 18730 at commit
|
|
Test build #81091 has finished for PR 18730 at commit
|
|
Test build #81080 has finished for PR 18730 at commit
|
|
Test build #81081 has finished for PR 18730 at commit
|
|
Test build #81082 has finished for PR 18730 at commit
|
|
Test build #81083 has finished for PR 18730 at commit
|
|
Test build #81112 has finished for PR 18730 at commit
|
|
@cloud-fan can we retest this?Thanks |
|
retest this please |
| while (bytes.remaining > 0) { | ||
| while (bytes.remaining() > 0) { | ||
| val ioSize = Math.min(bytes.remaining(), bufferWriteChunkSize) | ||
| bytes.limit(bytes.position + ioSize.toInt) |
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.
let's avoid this per-loop type cast, we can make bufferWriteChunkSize an int.
| .internal() | ||
| .doc("The chunk size during writing out the bytes of ChunkedByteBuffer.") | ||
| .bytesConf(ByteUnit.BYTE) | ||
| .createWithDefault(64 * 1024 * 1024) |
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.
add a checkValue to make sure the value is smaller than Int.Max
|
Test build #81125 has finished for PR 18730 at commit
|
|
Test build #81128 has finished for PR 18730 at commit
|
|
@cloud-fan Jekins done! |
|
thanks, merging to master! |
What changes were proposed in this pull request?
Right now, ChunkedByteBuffer#writeFully do not slice bytes first.We observe code in java nio Util#getTemporaryDirectBuffer below:
If we slice first with a fixed size, we can use buffer cache and only need to allocate at the first write call.
Since we allocate new buffer, we can not control the free time of this buffer.This once cause memory issue in our production cluster.
In this patch, i supply a new api which will slice with fixed size for buffer writing.
How was this patch tested?
Unit test and test in production.