Skip to content

upload/download transfers files within a part sequentially — add file-level parallelism (file_transfer_concurrency) #1454

Description

@minguyen9988

Problem

UploadPath and DownloadPath in pkg/storage/general.go transfer the files of a part strictly sequentially:

  • DownloadPath (pkg/storage/general.go:699) walks the remote prefix and downloads one file at a time inside bd.Walk(...).
  • UploadPath (pkg/storage/general.go:766) iterates for _, filename := range files and calls PutFile one file at a time.

upload_concurrency / download_concurrency parallelize across parts/tables, but each part's files still move one-by-one. For wide MergeTree parts (dozens to hundreds of small/medium column files) against high-latency object storage (S3/GCS), per-file round-trip latency dominates and a single part transfers far below the available bandwidth. On multi-TiB backups with many wide tables this leaves most of the network idle.

Proposal

Add a file_transfer_concurrency option (general section, env FILE_TRANSFER_CONCURRENCY) and parallel variants UploadPathParallel / DownloadPathParallel (plus a manifest-aware DownloadPathParallelWithManifest) that transfer the files of a single part with N concurrent workers using errgroup:

  • Call sites in pkg/backup/upload.go and pkg/backup/download.go pick the parallel variant when file_transfer_concurrency > 1, otherwise the existing sequential code path runs unchanged.
  • Bandwidth throttling still honors upload_max_bytes_per_second / download_max_bytes_per_second as an aggregate cap: one shared bwlimit.Limiter is created per path-transfer and shared by all workers, so parallelism does not multiply the configured max speed.
  • Default file_transfer_concurrency: 1 preserves current behavior exactly (opt-in).

We run this in a production fork backing up multi-TiB ClickHouse clusters; file-level parallelism is the single biggest wall-clock win we measured for wide tables (parts with many files) on object storage.

I have a PR ready to submit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions