Ben Cornelis
10/17/2025, 5:37 PMdf = daft.read_parquet(
"<abfs://my_container@my_service_account.dfs.core.windows.net/in_table_path/>"
)
df = df.groupby("group_col").agg(col("count_col").count())
df.write_parquet("<abfs://my_container@my_service_account.dfs.core.windows.net/out_table_path/>")
(it's worth noting that I have daft pinned to 0.5.19 since I currently get an error using write_parquet to azure blob store on later versions. It is the same issue as here: https://github.com/Eventual-Inc/Daft/issues/5336)
When I submit a job running this script to my ray cluster, it eventually fails with this error:
ray.exceptions.OutOfMemoryError: Task was killed due to the node running low on memory.
Memory on the node (IP: 10.224.2.36, ID: 637c809d2d9dfed8dd5c109e7ff9b81e4c10a024322086029a8f6def) where the task (actor ID: 53ff539b6349c1bee7efc01802000000, name=flotilla-plan-runner:RemoteFlotillaRunner.__init__, pid=1631, memory used=24.82GB) was running was 30.46GB / 32.00GB (0.951874), which exceeds the memory usage threshold of 0.95.
Is this unexpected that the flotilla runner on the head node is consuming so much memory?Ben Cornelis
10/17/2025, 5:43 PM== Physical Plan ==
* Project: col(0: group_col), col(1: count_col) as count_col
| Resource request = None
|
* Group-By Aggregate: col(0: group_col)
| Aggregations = sum(col(1: count_col))
|
* Repartition: Hash
| Num partitions = Some(200)
| By = col(0: group_col)
| Num partitions = 200
|
* Group-By Aggregate: col(1: group_col)
| Aggregations = count(col(0: count_col), Valid)
|
* Project: col(1: count_col), col(0: group_col)
| Resource request = None
|
* ScanTaskSource:
| Num Scan Tasks = 50000
| Estimated Scan Bytes = 1992341647247
| Pushdowns: {projection: [count_col, group_col]}
...Ben Cornelis
10/17/2025, 5:45 PMBen Cornelis
10/17/2025, 5:49 PMPID MEM(GB) COMMAND
1645 24.48 ray::RemoteFlotillaRunner.get_next_partition
217 0.50 ray-dashboard-DataHead-0 (/home/ray/anaconda3/bin/python3.9 -c from multiprocessing.spawn import spa...
222 0.50 ray-dashboard-ServeHead-0 (/home/ray/anaconda3/bin/python3.9 -c from multiprocessing.spawn import sp...
42 0.40 /home/ray/anaconda3/lib/python3.9/site-packages/ray/core/src/ray/gcs/gcs_server --log_dir=/tmp/ray/s...
134 0.30 /home/ray/anaconda3/bin/python3.9 /home/ray/anaconda3/lib/python3.9/site-packages/ray/dashboard/dash...
221 0.30 ray-dashboard-ReportHead-0 (/home/ray/anaconda3/bin/python3.9 -c from multiprocessing.spawn import s...
218 0.29 ray-dashboard-EventHead-0 (/home/ray/anaconda3/bin/python3.9 -c from multiprocessing.spawn import sp...
223 0.28 ray-dashboard-StateHead-0 (/home/ray/anaconda3/bin/python3.9 -c from multiprocessing.spawn import sp...
705 0.28 /home/ray/anaconda3/lib/python3.9/site-packages/ray/core/src/ray/raylet/raylet --raylet_socket_name=...
219 0.26 ray-dashboard-JobHead-0 (/home/ray/anaconda3/bin/python3.9 -c from multiprocessing.spawn import spaw...Colin Ho
10/17/2025, 6:25 PM* Repartition: Hash
| Num partitions = Some(200)
| By = col(0: group_col)
| Num partitions = 200
This will basically split each input into 200 partitions, and repartition the data by the group_col.
This means that there will be 50000 * 200 = 10M intermediate objectsColin Ho
10/17/2025, 6:27 PMColin Ho
10/17/2025, 6:27 PMColin Ho
10/17/2025, 6:28 PMColin Ho
10/17/2025, 6:29 PMBen Cornelis
10/17/2025, 6:43 PMColin Ho
10/17/2025, 6:47 PMSo during a repartition, all object refs are held in memory on the head node, and the pre-shuffle merge reduces the number of object refs?Exactly. The preshuffle merge will coalesce partitions up till a 1gb threshold, and only then do the repartition on this one partition. Since you have ~1.8tb of data across 50k files, assuming each file is roughly the same size, that means roughly 40mb per file, and so 24-25 files per gb. pre shuffle merge should be able to do some aggressive merging then, and should help a bit.
Colin Ho
10/17/2025, 6:48 PMBen Cornelis
10/17/2025, 7:03 PM