ftong2010 opened a new issue, #3849:
URL: https://github.com/apache/celeborn/issues/3849

   ### Is your feature request related to a problem? Please describe.
   Shuffle data volume across production workloads is heavily **bimodal** in 
our production environment:
   
   - **~99% of workloads shuffle less than 10TB** — modest, short-lived staging
     needs;
   - **~1% of workloads shuffle more than 40TB** — monthly/yearly aggregation, 
large joins,
     training intermediates.
   
   Provisioning shuffle storage for that distribution with today's options
   forces one of three bad trades:
   
   | Option | What happens |
   |---|---|
   | **Pure SSD/HDD sized for the tail** | Cluster dimensioned for the 1%; the 
other 99% of the time the capacity sits idle. Over-provisioning at this ratio 
is very high financial waste, and local disk provides **no elasticity at all** 
when a larger-than-planned job lands anyway. |
   | **S3/HDFS-only** | Every write pays remote-store latency in the 
mapper-critical path — sub-optimal performance — and on public cloud the 
sustained concurrent-PUT shuffle pattern is **heavily throttled** by 
object-store rate limits. |
   | **Mixed tiering (status quo)** | Files routed to the remote tier still 
write synchronously through it; throttling and latency land directly on 
mappers, and capacity planning doesn't actually improve. |
   
   Official document states that celeborn supports s3 as storage backend, and 
user can specify s3 in "availableStorageType" following memory and ssd/hdd 
disks, which looks like a sequence based tiering solution. But in fact that is 
   **misleading**: s3/hdfs can only be combined with memory, and it is 
exclusive againinst local disks. Only SSD/HDD exists in the list, DFS tiering 
no longer works.
   
   What the distribution calls for is **tiering by time, not by file**: write
   local first (fast, unthrottled, failure-isolated), then asynchronously move
   *sealed* (immutable, map-side-complete) files to object storage and free the
   local disk under pressure. Local SSD becomes a cache whose high-water mark — 
not its size —
   defines worker capacity: the 99% run entirely on fast local disk; the 1%
   spill cold data to S3 with no operator intervention.
   
   This design also protects against data is written unbound to disk, as 
currently "disk capacity" configuration in "celeborn.worker.storage.dirs" does 
not stop client from writing when capacity is reached. It will force partition 
splitting but big job will eventually find a way keeping writing data to 
celeborn workers, until disk is full or node is evicted by disk pressure in 
kubernetes environment.
   
   ### Describe the solution you'd like
   
   **1. Seal barrier — hard split as the immutability point.** A file is
   sealable when no mapper can ever append again; hard split already provides
   this (epoch bump, mappers revived away, late pushes rejected). Enforce with
   `trySealForOffload()` (write-lock; post-seal pushes get HARD_SPLIT) plus
   `sealFlushAndWait()` (drain flush buffer and wait for in-flight flushes so
   the bytes are final — we hit and fixed a flushBuffer-tail truncation bug
   here). Sealed files enter an offload queue; the unsealed write path is
   untouched.
   
   **2. Budget-controlled background offloader.** A ~1.5s scanner submits
   sealed files under:
   
   gate     = hysteresis latch on local usage (start / stop watermarks)
   budget   = (usage - stopWatermark) × totalBytes - inFlightBytes
              (stop=0 → drain-while-open)
   selection= FIFO by seal time, submit until budget exhausted
              (one overshoot file allowed — files are atomic)
   
   Uploads are multipart with part-level parallelism (`partConcurrency`,
   default 4; memory bounded by threads×concurrency×8m = 64 MiB at defaults),
   running on a small bounded pool — so **public-cloud throttling slows
   draining but can never stall pushes**, the inverse of the S3-tier behavior.
   Failures retry with backoff and ultimately **fall back to keeping the file
   local** (data is never at risk). On success, an atomic registry maps
   committed file → S3 path, the local file is deleted, and a shuffle-unregister
   hook cleans both local dirs and the S3 prefix.
   
   **3. Worker-proxied reads.** Reducers keep reading from the worker whether
   the file is local or already in S3, via `S3ChunkBuffers` in the normal
   fetch/OpenStream path, supporting **full-chunk and map-range reads** (AQE
   skew-join sub-tasks read map ranges; S3 range GETs make those cheap). One
   upstream fix needed: `S3AInputStream` can't back the sorter's ByteBuffer
   reads, requiring a heap-array fallback. **Clients need zero S3
   credentials, config, or jars** — object-store topology stays worker-side.
   
   **4. Configuration.**
   
   | key | default | meaning |
   |---|---|---|
   | `celeborn.worker.storage.offload.enabled` | false | master switch |
   | `...offload.threads` | 2 | concurrent file uploads |
   | `...offload.partConcurrency` | 4 | MPU parts per file (mem bound 
threads×c×8m) |
   | `...offload.settleDelay` | 3s | quiescence wait after seal |
   | `...offload.diskUsageThreshold` | 0.0 | start watermark (0 = always 
active) |
   | `...offload.diskUsageStopThreshold` | 0.0 | stop watermark → byte budget 
(0 = drain) |
   | `...offload.maxAttempts` / `retryBackoff` | 5 / 30s | per-file retry 
policy |
   
   **Measured** (single worker, 10G SSD cache, S3-compatible store):
   20G shuffle drained through a 10G cache (20 uploads, 0 failures, 0 fetch
   failures; usage oscillated near the watermark instead of hitting
   "No available disks"); gate-open/gate-closed drills show the control plane
   never interferes with the data plane (152 splits, 0 offloads when closed);
   AQE skew-join range reads over offloaded files verified end-to-end; all via
   `FetchS3Chunk*` metrics with zero client-side configuration.
   
   ### Describe alternatives you've considered
   
   - **Pure SSD/HDD, over-provisioned**: no elasticity; sizing for 40TB
     outliers that appear 1% of the time is financially untenable.
   - **S3/HDFS-only / DFS-as-tier (status quo)**: synchronous remote writes in
     the push path put latency and throttling on mappers; every file pays
     remote costs rather than only cold ones. The docs should also be amended
     to state object-store throughput/rate-limit realities.
   - **Client-side direct S3 reads**: ships credentials and storage topology
     into every executor's config/jars, and requires per-engine integration;
     rejected.
   - **Mount S3 as a local filesystem (s3fs / goofys / Mountpoint for S3) and
     register it alongside real SSDs, i.e. mixing SSD/HDD disk types in
     `celeborn.worker.storage.dirs`**: the S3 mount is declared as an
     HDD-type dir and Celeborn's existing multi-disk allocation spreads
     writers across both. This does **not** satisfy tiering: dir selection is
     capacity/slot-based, not temperature-based — new writers and
     hard-split generations are placed on whichever dir has slots, so hot
     in-flight files routinely land on the S3 mount and inherit FUSE context
     switches, network round-trips, and object-store throttling directly in
     the push/flush path, with non-POSIX fsync/rename semantics adding jitter
     to commit. Reads fare no better: millions of small chunk fetches over
     the mount each pay object-store GET latency. It also adds real
     **operational overhead**: per-node mount lifecycle management, FUSE
     daemon monitoring, local cache-dir sizing on the very SSDs you were
     trying to offload, credential rotation on every worker host, and
     misleading observability (`df`-based usage checks and quota math become
     fiction on a mount that reports PBs of free space). Tiering must remain
     an explicit, worker-managed boundary — hot data local, cold data remote —
     rather than an accident of slot allocation.
   - **External lifecycle jobs (cron upload/compaction)**: race with active
     shuffles and need cluster-global coordination; the in-worker seal barrier
     makes offload safe and simple.
   
   ### Future improvement
   * Better dedupe handling when replication is enabled.
   * Support more evict policy
   * Read data back from s3 when data is loaded and disk pressure is gone
   * Throttle client push using current mechanism when disk pressure is high, 
since s3 write throughput is generally slower than ssds aggregated on worker 
cluster.
   
   I am wondering if community is interested in this feature. we can submit PR 
for this feature. 
   It is currently tested in our production environment and will report and new 
finding if anything comes up.
   
   
   
   /cc @who-need-to-know
   
   /assign @who-can-help-you
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to