Uh oh!
There was an error while loading. Please reload this page.
PARQUET-2171: Support Hadoop vectored IO - #1139
Conversation
Uh oh!
There was an error while loading. Please reload this page.
@steveloughran This looks really great! I think my only comment would be about wether we can expose the implementation in a way that might be more pluggable. In Iceberg we have a similar parallel to the InputFile and SeekableStream, but it's not apparent to me that we would be able to adapt our IO implementation to leverage vectored reads. Open to thoughts on how we might do that as well. Maybe this would be possible by implementing the vectoredIO methods in the Iceberg adaptor class here? |
shangxinli
commented
Sep 17, 2023
@steveloughran Thanks a lot for creating this PR! This is an important feature that we improve the reading performance of Parquet. I just took a brief look and they look great! I will spend some time later to review it. |
steveloughran
commented
Sep 18, 2023
@shangxinli looking forward to your comments -anything you can do to test will be wonderful too! |
steveloughran
commented
Sep 18, 2023
@danielcweeks that's a good point about pluggability.
getting iceberg to pass down which stripes it wants to read is critical for this to work best with s3, abfs and gcs. how are you reading the files at present? |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
steveloughran
commented
Sep 19, 2023
@gszadovszky thanks for your comments, will update the PR |
parthchandra
commented
Sep 28, 2023
Iceberg can use the base Parquet File reader out of the box so should be able to use vector IO as it is.
However if the S3FileIO feature is enabled, Iceberg provides its own InputStream and InputFile implementation that use AWS SDK V2. Maybe an option to provide your own input stream to vector io might work. |
parthchandra
commented
Sep 28, 2023
@mukund-thakur@steveloughran this is a great PR! Some numbers from an independent benchmark. I used Spark to parallelize the reading of all rowgroups (just the reading of the raw data) from TPC-DS/SF10000/store_sales using various APIS and here are some numbers for you. 32 executors, 16 cores
Summary - The various V2 SDK clients provide lower latency and better upload speeds but for raw data scans, they are all pretty much the same. |
mukund-thakur
commented
Sep 29, 2023
@parthchandra Thanks for running the benchmarks. the numbers are impressive. |
@parthchandra just wanted to check, are these numbers with Iceberg and S3FileIO? With S3A now using SDKV2, I'm looking at running a similar benchmark too with async CRT clients, but have been seeings some issues around connection pool exhaustion. |
parthchandra
commented
Oct 17, 2023
@ahmarsuhail No these numbers are not with iceberg and S3FileIO. |
steveloughran
commented
Oct 17, 2023
Thanks for the numbers; I am deep in the aws v2 sdk migration right now and haven't had a chance to work on this. |
steveloughran
commented
Nov 17, 2023
...back on this. @parthchandra you know that hadoop trunk is built on the v2 sdk now? |
7e02d53 to
da3db9bComparesteveloughran
commented
Nov 17, 2023
OK, I've tried to address the changes as well as merge with master The one thing I'm yet to do is the one by @danielcweeks : have an interface for which the hadoop vector IO would be just one implementation. We effectively have that in SeekableInputStream; two new default methods: one a probe for the api availability and the other an invocation. |
wgtmac
left a comment
There was a problem hiding this comment.
Thanks for the change! I've just scanned it for the 1st pass. Do you have any outstanding work on this PR?
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
steveloughran
commented
Nov 29, 2023
Code wise, no, other than reviews from others about what is the best place for things, such as that awaitFuture stuff or any other suggestions which people who know the parquet codebase think is best. Code works and we have been testing this through Amazon S3 Express storage for extra speed up. To be ruthless: there's no point paying the premium for that until you've embraced the extra speed ups you get from this first |
@steveloughran Can you fix the compatibility issue? |
steveloughran
commented
Nov 30, 2023
Uh oh!
There was an error while loading. Please reload this page.
steveloughran
commented
Dec 18, 2023
Thanks. I'm away from my laptop until 2024 but really do want to get this in. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
parthchandra
commented
Apr 1, 2024
+1 from me as well. |
tested across the different profiles, all good. i am seeing hadoop 3.4 mr test failures, but that happens on master too. One thing I do want to change now is actually propose changing the package name from vectorio to something more like "wrapped io" the reason for this is that in apache/hadoop#6686
Having a unified package for this stuff makes sense, and vectorio is too narrow |
…pedio This is to prepare the package as a future home for other ongoing reflection support for parquet to get better cloud performance, initially HADOOP-19131. Assist reflection IO with WrappedOperations class, which adds a static method invoking FileSystem.openFile() with various options to make it easy for parquet to adopt. Move org.apache.hadoop.util.functional.FutureIO from BindingUtils to to org.apache.parquet.hadoop.util.wrappedio.FutureIO Change-Id: I414086c95d87710bdc14ac304fdf22aabf86002a Goal: make any future move to hadoop release versions easier.
steveloughran
commented
Apr 2, 2024
Update
We could consider making BindingUtils package private. |
It's pretty generic and might be useful elsewhere so I feel it is ok to keep it public. |
wgtmac
left a comment
There was a problem hiding this comment.
Just reviewed for another pass. I've left some minor comments. Overall LGTM, thanks @steveloughran!
| @Override | ||
| public String toString() { | ||
| return "range[" + this.offset + " - " + (this.offset + (long) this.length) + "]"; |
There was a problem hiding this comment.
| return"range[" + this.offset + " - " + (this.offset + (long) this.length) + "]"; | |
| return"range[" + this.offset + " - " + (this.offset + (long) this.length) + ")"; |
There was a problem hiding this comment.
why this change, given range starts with the "[" symbol? I'm happy to merge it, just not sure why unless you want to delineate that the second value in the range is inclusive, which is isn't, now I look at it. maybe it should be
returnString.format("range[%,d to %,d]",
offset, (offset + (length > 0 ? (length - 1 ) : 0));There was a problem hiding this comment.
Yes, my intention is to let readers know whether each end is exclusive or inclusive.
Uh oh!
There was an error while loading. Please reload this page.
| /** | ||
| * Is the {@link #readVectored(List, ByteBufferAllocator)} method available? | ||
| * @param allocator the allocator to use for allocating ByteBuffers |
There was a problem hiding this comment.
I searched for a while on why allocator param is required and found that internally it checks !allocator.isDirect().
It seems that we can remove the extra param from readVectoredAvailable and modify ParquetFileReader.shouldUseVectoredIO() instead like below:
private boolean shouldUseVectoredIO(final List<ConsecutivePartList> allParts) {
return options.useHadoopVectoredIO()
&& f.readVectoredAvailable()
&& !options.getAllocator().isDirect()
&& arePartsValidForVectoredIO(allParts);
}
WDYT?
There was a problem hiding this comment.
aah, you've noticed that! It's because I've realised that on s3/abfs/gcs network failures which don't recover after retries, we need a way to return the buffer to the pool. See https://issues.apache.org/jira/browse/HADOOP-19105
I actually need to do some more in general on s3a read() recovery: we retry on the GET calls and then keep the connection active only as long as it takes to read the data -so no risk of stale connections is low- but I do need to add the full resilience logic there
- abort http connections considered unrecoverable, rather than return to pool
- retry outstanding entries in each range
- maybe actually handle failures by decombining adjacent ranges.
Having parquet pass the allocator as far down as it does means that supporting releases with the "return to pool" callback doesn't change the rest of the code, instead the bridge would first look for the new method, falling back to the original one if not found.
There was a problem hiding this comment.
That makes sense. Thanks for the explanation!
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…FileReader.java Co-authored-by: Gang Wu <ustcwg@gmail.com>
* use Io rather than IO in fields, classnames * package is now org.apache.parquet.hadoop.util.wrapped.io * comment in pom clarifies that the FutureIO method is excluded from japicmp because it fails otherwise. Change-Id: Id82d1239b8b0ee5d38f0487e20b9e128e8cad8eb
wgtmac
commented
Apr 5, 2024
Do you want to double check this again? @danielcweeks@Fokko |
VectorIOBridge.readVectoredRanges() is non static Change-Id: Ic23068f8123d0b86b971b5627a5b724e86d9ddcd
steveloughran
commented
Apr 9, 2024
Right, I think I have addressed all the issues except for the design of a public API for other input sources. I do think that would be good, not just for iceberg integration, but because it will let local filesystem clients do this through LocalInputFile. This is already in hadoop, where it only takes 100 LoC to implement (https://github.com/apache/hadoop/blob/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/RawLocalFileSystem.java#L319). (The hadoop API used java.io.nio when designing ours, so this isn't surprising). Can we get this in and then I can collaborate with you and anyone else interested on having a broader API? I would obviously like what we've done to be ~the reference design, but the binding, testing and including this in the benchmarks are areas I need help from the experts in the project to understand how to fit it in the best. Incidentally, you should be aware that the next bit of parquet work I want to do is to pass in seek policy and file status when opening files. This is trivial to do on Hadoop 3.3+ saves a HEAD request through the ABFS and S3A connectors, and let them tune prefetching/caching/GET range policy. However, trying to get that builder API through reflection is very complicated. What I am doing is create some reflection-friendly static methods (apache/hadoop#6686), ship this in hadoop 3.3.9 and 3.4.1 and use the BindingUtils and DynMethods code to invoke. Parquet always calls getFileStatus() before opening a file, so the HEAD is completely superfluous. Note: that hadoop PR lifts and repackages the DynMethods classes so that for testing there we can be confident it works. |
wgtmac
commented
Apr 11, 2024
@gszadovszky@shangxinli@ggershinsky Could you help review this for another pass? Thanks! |
Now:
String.format("range[%,d - %,d)", offset, offset + length)
Change-Id: I5acde3bd2fa9a9d5f19b603082a894c44c9f51adsteveloughran
commented
Apr 17, 2024
@wgtmac tweaked that FileRange.toString(); now ...that shows that the range is inclusive and gives , separators on large ranges. This is just for debugging -but that doesn't mean it shouldn't be meaningful |
* Make clear ranges must be disjoint * Fill out exception list Change-Id: I55db835f3b7d376d0a5cc3d627b85cf1e475a3ec
Negative offsets on read are raised as IllegalArgumentException This isn't what the hadoop inner code does, but that is irrelevant because the parquet-side validations happen first. Change-Id: I94249ba8437372789dc8582b1b09a076ac7ab4e3
Change-Id: I5074de86870f5f773695e7c05d1f43bc2fa90253
wgtmac
commented
Apr 24, 2024
I will merge this by the end of this week if no objection. We need to release parquet 1.14.0 and this is a must-have feature. |
steveloughran
commented
Apr 24, 2024
thanks! FWIW ORC shipped with this feature recently too. |
steveloughran
commented
Apr 25, 2024
thanks for the approval. I have more plans. but first want to make it really easy for parquet to pick up hadoop-3.2/3.3 APIs through reflection; apache/hadoop#6686 get that into 3.3.9/3.4.1 and then parquet will be able to
if we can do vectored IO through reflection, then other stuff is there for the taking too. |
parthchandra
commented
Apr 25, 2024
@wgtmac it would be great to get this in. I'm waiting with a followup to add simple metrics for the vector io read path and it would be nice if that might make it to the release as well. |
wgtmac
commented
Apr 26, 2024
I just merged it. Thanks all! |
steveloughran
commented
Apr 29, 2024
thanks! looking forward to other people's results. I also have plans for more... |
| @Rule | ||
| public final TemporaryFolder temp = new TemporaryFolder(); | ||
| @Parameterized.Parameters(name = "vectored : {0}") |
There was a problem hiding this comment.
Somehow we need to add a validation that when tests with vectored IO enabled run, vectored IO actually gets triggered.
Make sure you have checked all steps below.
Jira
Tests
TestVectorIOBridge
TestFileRangeBridge
It also parameterizes existing tests run with/without vector IO enabled.
TestParquetFileWriterTestInputFormatColumnProjectionTestInputOutputFormatCommits
Documentation