Repository navigation
Replies: 2 comments 1 reply
|
@infvg thanks for the proposal, looks promising, could we also extend this optimization to other connectors as well? |
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Problem
Before an Iceberg query can read data, it must plan the scan, determining which files to read, how to divide them into work for executors and which filters still need evaluation.
Currently, the scan prep path creates java task objects and task groups.
References to these objects remain in the scan, batch and input partitions. Gluten then makes more objects of the same information.
For queries with many files, those objects and their duplicates increase the driver's memory usage.
Goals
Proposal
Add an early streaming prep path for iceberg reads.
This new path will take the java planning output incrementally and store any information it needs for execution in compact batches. The scan will keep these batches and planning summaries, while the references to java tasks will be removed so they can be garbage collected.
Statistics, partition constructor and executor transport uses these batches.
The plan is to support batch snapshot reads of parquet files without delete files. We can offer this as an optional incremental scan planning config.
Benefit
The main benefit is the lower retained driver heap for scans many files, which means that larger scans/more queries can be run with the same memory budget.
But in general, fewer java objects will be allocated, there should be less metadata copying & smaller task payloads.
Implementation Plan
Objects and replacements
FileScanTaskScanTaskGroupSparkBatchSparkInputPartitionIcebergLocalFilesNodeGlutenPartitionwithoutIcebergLocalFilesNodeSparkBatchholds multipleScanTaskGroups. Each group holds multipleFileScanTasksSparkInputPartitionreferences one group, and the scan caches tasks and groups so the same objects remain reachable through the scan batch and input partitionsGluten creates
IcebergLocalFilesNode, which contains split info, carried insideGlutenPartitionThe new path will replace the task/group references, and the intermediate split nodes with the work + summaries.
Driver side
Add an early scan point
Add a scan path before java task caches fill. Consume tasks and groups incrementally, keeping the compact batch + summaries. Statistics and partition requests will reuse this result without rebuilding the complete task collection.
Add a compact planning result
Add a new object eg
CompactPlanningResultfor each scan request.It will have:
Statistics & partition requests will reuse this result.
Requests that can obtain statistics directly from snapshot metadata will continue to avoid file planning.
Consume java tasks & create batches
Once tasks become available, we validate them and collect required statistics, encode their execution information using the existing protobuf format. Also we'll remove references to task objects once their info is moved.
We will use the existing protobuf format.
after the task info is transferred, remove references to the temporary task object (and the same for the task groups).
We then add a new input partition for the native batches, which contain the task batches and scheduling information.
Each partition will have the information needed for independent retries with this implementation.
Keep compact batches available for retries and recomputation. Planning memory still grows with the amount of encoded work.
Executor side
Task batch decoding
Pass the encoded batches directly to the existing Velox JNI interface.
Executors won't rebuild Java split nodes or Java protobuf objects before passing the bytes to native code.
Draft: #13269
Evidence
I ran some local tests with a early compact prototype vs the existing path:
For 100k parquet files, containing 6.4 million rows:
Memory figures are medians from 3 fresh JVMs per path. Query times are medians from ten measured query per path.
After GC, the new path had no live BaseFileScanTask, SplitScanTask, BaseScanTaskGroup or IcebergLocalFilesNode instances, while the query was still available to execute.
I also ran a larger test with one million files containing 64 million rows
Each result ran twice.
Risk
Future work
All reactions