Skip to content

[SPARK-20014] Optimize mergeSpillsWithFileStream method#17343

Closed
sitalkedia wants to merge 3 commits intoapache:masterfrom
sitalkedia:upstream_mergeSpillsWithFileStream
Closed

[SPARK-20014] Optimize mergeSpillsWithFileStream method#17343
sitalkedia wants to merge 3 commits intoapache:masterfrom
sitalkedia:upstream_mergeSpillsWithFileStream

Conversation

@sitalkedia
Copy link
Copy Markdown

@sitalkedia sitalkedia commented Mar 19, 2017

What changes were proposed in this pull request?

When the individual partition size in a spill is small, mergeSpillsWithTransferTo method does many small disk ios which is really inefficient. One way to improve the performance will be to use mergeSpillsWithFileStream method by turning off transfer to and using buffered file read/write to improve the io throughput.
However, the current implementation of mergeSpillsWithFileStream does not do a buffer read/write of the files and in addition to that it unnecessarily flushes the output files for each partitions.

How was this patch tested?

Tested this change by running a job on the cluster and the map stage run time was reduced by around 20%.

@sitalkedia sitalkedia force-pushed the upstream_mergeSpillsWithFileStream branch from e9ac76e to 1834db6 Compare March 19, 2017 00:27
@sitalkedia
Copy link
Copy Markdown
Author

cc - @rxin, @squito, @zsxwing

@SparkQA
Copy link
Copy Markdown

SparkQA commented Mar 19, 2017

Test build #74798 has finished for PR 17343 at commit e9ac76e.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Mar 19, 2017

Test build #74800 has finished for PR 17343 at commit 1834db6.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link
Copy Markdown

SparkQA commented Mar 19, 2017

Test build #74802 has finished for PR 17343 at commit 00da825.

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

@SparkQA
Copy link
Copy Markdown

SparkQA commented Mar 19, 2017

Test build #74805 has finished for PR 17343 at commit 368dd29.

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

@mridulm
Copy link
Copy Markdown
Contributor

mridulm commented Mar 19, 2017

If we make flush() noop, then buffered (uncommitted) data wont be written to the stream; am I missing something here, or is this change broken ?

@mridulm
Copy link
Copy Markdown
Contributor

mridulm commented Mar 19, 2017

Background - you need to do a flush() to ensure the indices generated are valid.

@mridulm
Copy link
Copy Markdown
Contributor

mridulm commented Mar 19, 2017

Ah, looks like I missed that CountingOutputStream was introduced after BOS and not before.
Looks good to me.

@rxin
Copy link
Copy Markdown
Contributor

rxin commented Mar 19, 2017

Can you add some documentation inline so in the future we'd know why specific implementations were chosen?

@sitalkedia
Copy link
Copy Markdown
Author

@rxin - Updated documentation.

@sitalkedia sitalkedia force-pushed the upstream_mergeSpillsWithFileStream branch from 5fe279e to 06c1909 Compare March 20, 2017 18:46
@SparkQA
Copy link
Copy Markdown

SparkQA commented Mar 20, 2017

Test build #74893 has finished for PR 17343 at commit 5fe279e.

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

@SparkQA
Copy link
Copy Markdown

SparkQA commented Mar 20, 2017

Test build #74897 has finished for PR 17343 at commit 06c1909.

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

@sitalkedia
Copy link
Copy Markdown
Author

ping @rxin, @mridulm.

@mridulm
Copy link
Copy Markdown
Contributor

mridulm commented Mar 25, 2017

LGTM will wait a bit to allow for others to comment.
@zsxwing can you also take a look ?

@sitalkedia
Copy link
Copy Markdown
Author

ping @zsxwing.

Copy link
Copy Markdown
Member

@sameeragarwal sameeragarwal left a comment

Choose a reason for hiding this comment

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

Thanks @sitalkedia, the optimization looks solid. I've some extremely minor stylistic comments (unfortunately spark's style-checker doesn't work on .java files so many of these errors weren't caught automatically). Additionally, just to make sure, is this code covered under existing tests?

import java.nio.channels.FileChannel;
import java.util.Iterator;

import org.apache.spark.io.NioBufferedFileInputStream;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: import order


private class CloseAndFlushShieldOutputStream extends CloseShieldOutputStream {

public CloseAndFlushShieldOutputStream(OutputStream outputStream) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This needn't be public


final OutputStream bos = new BufferedOutputStream(
new FileOutputStream(outputFile),
(int) sparkConf.getSizeAsKb("spark.shuffle.unsafe.file.output.buffer", "32k") * 1024);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a reason to introduce an extra config? Can we not use spark.shuffle.file.buffer here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@sameeragarwal - Thanks for taking a look. Tha rational behind having a separate config for write buffer is that it is useful to have a larger write buffer than the read buffer, because for jobs spilling a large amount of data to disk might create multiple spill files on disk. So we will have multiple read buffer but only one write buffer. Having a larger write buffer allows us to do the merge all in memory without hitting the disk frequently for writes. We have observed this config helps speed up our large jobs significantly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Makes sense.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: please create a field to store it rather than parsing the conf for each call.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hmm.. I am not sure if I get it. The function mergeSpillsWithFileStream will be called only once per task?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, you are right. NVM.

/**
* Merges spill files using Java FileStreams. This code path is slower than the NIO-based merge,
* {@link UnsafeShuffleWriter#mergeSpillsWithTransferTo(SpillInfo[], File)}, so it's only used in
* Merges spill files using Java FileStreams. This code path is typically slower than the NIO-based merge,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: some of these lines are great than 100ch (in comments and code). Can you please fix those?

for (int i = 0; i < spills.length; i++) {
spillInputStreams[i] = new FileInputStream(spills[i].file);
spillInputStreams[i] = new NioBufferedFileInputStream(spills[i].file,
(int) sparkConf.getSizeAsKb("spark.shuffle.file.buffer", "32k") * 1024);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: the formatting seems a bit off

@sitalkedia
Copy link
Copy Markdown
Author

Thanks @sameeragarwal, addressed the check style issues. Yes, the exisiting unit tests in UnsafeShuffleWriter#mergeSpillsWithTransferToAndLZF covers this code.

@SparkQA
Copy link
Copy Markdown

SparkQA commented May 25, 2017

Test build #77382 has finished for PR 17343 at commit d4f09c2.

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

@jiangxb1987
Copy link
Copy Markdown
Contributor

cc @zsxwing Could you find some time to review this?

@sameeragarwal
Copy link
Copy Markdown
Member

LGTM

Copy link
Copy Markdown
Member

@zsxwing zsxwing left a comment

Choose a reason for hiding this comment

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

Looks pretty good except some nits.


final OutputStream bos = new BufferedOutputStream(
new FileOutputStream(outputFile),
(int) sparkConf.getSizeAsKb("spark.shuffle.unsafe.file.output.buffer", "32k") * 1024);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: please create a field to store it rather than parsing the conf for each call.

spillInputStreams[i] = new FileInputStream(spills[i].file);
spillInputStreams[i] = new NioBufferedFileInputStream(
spills[i].file,
(int) sparkConf.getSizeAsKb("spark.shuffle.file.buffer", "32k") * 1024);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: please create a field to store it rather than parsing the conf inside the loop.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done.

@zsxwing
Copy link
Copy Markdown
Member

zsxwing commented May 26, 2017

LGTM pending tests.

@SparkQA
Copy link
Copy Markdown

SparkQA commented May 26, 2017

Test build #77430 has finished for PR 17343 at commit 4bc6e3e.

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

@zsxwing
Copy link
Copy Markdown
Member

zsxwing commented May 26, 2017

LGTM. Thanks! Merging to master.

@asfgit asfgit closed this in 473d755 May 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants