-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-19112][CORE] Support for ZStandard codec #18805
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
|
cc - @srowen, @tgravescs, @rxin, @sameeragarwal |
|
Old PR - #17303 |
|
Any benchmark data? |
|
Test build #80140 has finished for PR 18805 at commit
|
|
Test build #80141 has finished for PR 18805 at commit
|
4ee4d2b to
287a9da
Compare
|
Test build #80142 has finished for PR 18805 at commit
|
|
cc @dongjinleekr too. |
|
@rxin - Updated with benchmark data on our production workload. |
|
Please note that few minor improvements I have made as comapred to old PR - #17303
|
|
jenkins retest this please. |
|
Test build #80144 has finished for PR 18805 at commit
|
|
Any idea what is the build failure about? |
| "lzf" -> classOf[LZFCompressionCodec].getName, | ||
| "snappy" -> classOf[SnappyCompressionCodec].getName) | ||
| "snappy" -> classOf[SnappyCompressionCodec].getName, | ||
| "zstd" -> classOf[SnappyCompressionCodec].getName) |
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.
you mean ZStandardCompressionCodec ?
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.
Ah, my bad. Fixed it.
|
|
||
| /** | ||
| * :: DeveloperApi :: | ||
| * ZStandard implementation of [[org.apache.spark.io.CompressionCodec]]. |
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.
would be good to add this link pointing to more details : http://facebook.github.io/zstd/
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.
done.
| class ZStandardCompressionCodec(conf: SparkConf) extends CompressionCodec { | ||
|
|
||
| override def compressedOutputStream(s: OutputStream): OutputStream = { | ||
| val level = conf.getSizeAsBytes("spark.io.compression.zstandard.level", "1").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.
please add a comment explaining the reason why we chose level 1 over other levels
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.
done.
|
|
||
| override def compressedOutputStream(s: OutputStream): OutputStream = { | ||
| val level = conf.getSizeAsBytes("spark.io.compression.zstandard.level", "1").toInt | ||
| val compressionBuffer = conf.getSizeAsBytes("spark.io.compression.lz4.blockSize", "32k").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.
- wondering if we should share this config value OR have a new one.
- do you want to set the default to something higher like 1mb or 4mb ?
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.
You are right, we should not share the config with lz4, created a new one.
Lets keep the default to 32kb which is aligned with the block size used by other compressions.
|
In |
|
re build failure: you can repro that locally by running "./dev/test-dependencies.sh". Its failing due to introducing a new dep... you need to add it to |
|
How big is the dependency that's getting pulled in? If we are adding more compression codecs maybe we should retire some old ones, or move them into a separate package so downstream apps can optionally depend on them. |
|
Test build #80148 has finished for PR 18805 at commit
|
|
Why does this need to be in Spark? and what are the licensing terms of the native code underneath (just suspicious because it's often GPL)? can a user not just add this with their app? I tend to think we support what Hadoop supports for us here. Doesn't a later Hadoop pull this in? |
@srowen you already asked that question and it has been answered on the jira as well as the old pr. A user cannot add zstd compression to the internal spark parts: spark.io.compression.codec. In this particular case he is saying its the shuffle output where its making a big difference. |
|
Got it, thanks for the reminder. I think the question is mostly about license and dependency weight then. I think we'd want to use whatever Hadoop provides. |
docs/configuration.md
Outdated
| <code>org.apache.spark.io.LZ4CompressionCodec</code>, | ||
| <code>org.apache.spark.io.LZFCompressionCodec</code>, | ||
| and <code>org.apache.spark.io.SnappyCompressionCodec</code>. | ||
| <code>org.apache.spark.io.SnappyCompressionCodec</code>. |
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.
nit: '.' -> ','
| <tr> | ||
| <td><code>spark.io.compression.zstd.level</code></td> | ||
| <td>1</td> | ||
| <td> |
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.
nit: leve -> level
| // Default compression level for zstd compression to 1 because it is | ||
| // fastest of all with reasonably high compression ratio. | ||
| val level = conf.getSizeAsBytes("spark.io.compression.zstd.level", "1").toInt | ||
| val bufferSize = conf.getSizeAsBytes("spark.io.compression.zstd.bufferSize", "32k").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.
Would it be better to have this variable as a private variable to get this property only once?
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.
Agree, it's simpler and cleaner, as it avoids duplicating this property in this file
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.
@sitalkedia how about comments like this?
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.
Sorry somehow missed these comments. Will address.
|
Our compression codec is actually completely decoupled from Hadoops, but dependency management (and licensing) can be annoying to deal with. |
|
retest this please |
|
Test build #82644 has finished for PR 18805 at commit
|
|
Same test failed, so looks like there's a real non-infra-related issue... |
|
retest this please |
|
Test build #82729 has finished for PR 18805 at commit
|
|
I haven't been able to reproduce the issue locally, but looking at the jenkins logs I see a bunch of exceptions like these: And: Note that the first error mentions the app name used by |
|
(I'll file a bug and send a PR for it separately, btw.) |
|
Turns out that's caused by SparkContext failing to clean up after itself when the |
|
This seems to be caused by a issue in the |
|
Yeah but that would also cause it to fail locally if it were the cause, and it passes for me. I can't really figure out from the rest of the logs if something obvious is wrong, so I guess the best bet now is to ask for changes in the |
|
Good news is that I can reproduce it on the amplab machine, so I'll try to play around with the zstd-jni code a bit. |
Mystery solved; library is compiled with a newer glibc requirement than the amplab machines have. Can we ask them to tweak their compilation to support older Linux distros? |
|
Created luben/zstd-jni#47. |
|
Test build #82911 has finished for PR 18805 at commit
|
|
ping. |
srowen
left a comment
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.
Aside from one minor question from an old comment that's looking good. The licenses seem in order.
| // Default compression level for zstd compression to 1 because it is | ||
| // fastest of all with reasonably high compression ratio. | ||
| val level = conf.getSizeAsBytes("spark.io.compression.zstd.level", "1").toInt | ||
| val bufferSize = conf.getSizeAsBytes("spark.io.compression.zstd.bufferSize", "32k").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.
@sitalkedia how about comments like this?
| override def compressedOutputStream(s: OutputStream): OutputStream = { | ||
| // Default compression level for zstd compression to 1 because it is | ||
| // fastest of all with reasonably high compression ratio. | ||
| val level = conf.getSizeAsBytes("spark.io.compression.zstd.level", "1").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.
Is this getInt instead of getSizeAsBytes?
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 eye, fixed.
|
Test build #83204 has finished for PR 18805 at commit
|
| @DeveloperApi | ||
| class ZStdCompressionCodec(conf: SparkConf) extends CompressionCodec { | ||
|
|
||
| val bufferSize = conf.getSizeAsBytes("spark.io.compression.zstd.bufferSize", "32k").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.
This should be private. The intent was to lift both config values out of the method, so level can do here too.
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.
done.
|
Test build #83282 has finished for PR 18805 at commit
|
hvanhovell
left a comment
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.
LGTM
|
Merging to master. Thanks for seeing this through! |
What changes were proposed in this pull request?
Using zstd compression for Spark jobs spilling 100s of TBs of data, we could reduce the amount of data written to disk by as much as 50%. This translates to significant latency gain because of reduced disk io operations. There is a degradation CPU time by 2 - 5% because of zstd compression overhead, but for jobs which are bottlenecked by disk IO, this hit can be taken.
Benchmark
Please note that this benchmark is using real world compute heavy production workload spilling TBs of data to disk
How was this patch tested?
Tested by running few jobs spilling large amount of data on the cluster and amount of intermediate data written to disk reduced by as much as 50%.