Skip to content

enhancement(clickhouse sink): add Arrow IPC compression#25758

Open
benjamin-awd wants to merge 2 commits into
vectordotdev:masterfrom
benjamin-awd:feat/clickhouse-arrow-ipc-compression
Open

enhancement(clickhouse sink): add Arrow IPC compression#25758
benjamin-awd wants to merge 2 commits into
vectordotdev:masterfrom
benjamin-awd:feat/clickhouse-arrow-ipc-compression

Conversation

@benjamin-awd

Copy link
Copy Markdown
Contributor

Summary

Adds a compression option (none | lz4_frame | zstd, default none) to the clickhouse sink's arrow_stream batch encoding. It compresses each column buffer inside the Arrow IPC stream, so ClickHouse decompresses it on ingest.

Today the only way to compress an arrow_stream payload is a whole-payload HTTP gzip Content-Encoding — good on size, heavy on CPU. IPC compression is much cheaper (see issue for benchmark)

Note: Compressed Arrow IPC needs ClickHouse ≥ 23.11 (both lz4 and zstd). Older servers accept the insert but can't read typical small compressed batches (Code: 33 CANNOT_READ_ALL_DATA) and would silently drop data, so the sink checks the server version at startup and rejects compression on older servers.

Default is none, so existing configs are unaffected.

Vector configuration

sinks:
  my_clickhouse:
    type: clickhouse
    inputs: [my_source]
    endpoint: http://clickhouse:8123
    database: mydb
    table: mytable
    format: arrow_stream
    batch_encoding:
      codec: arrow_stream
      compression: zstd   # none (default) | lz4_frame | zstd

How did you test this PR?

  • Unit tests (lib/codecs): compressed streams round-trip back to the same RecordBatch and are smaller than uncompressed; version parsing and the minimum-version check.
  • Integration tests against real ClickHouse containers:
    • insert_events_arrow_format_{zstd,lz4}_compression — insert and read back; skip below 23.11.
    • arrow_compression_rejected_on_old_clickhouse — the sink refuses to build with compression on ClickHouse < 23.11.

Change Type

  • Bug fix
  • New feature
  • Dependencies
  • Non-functional (chore, refactoring, docs)
  • Performance

Is this a breaking change?

  • Yes
  • No

Does this PR include user facing changes?

  • Yes. Please add a changelog fragment based on our guidelines.
  • No. A maintainer will apply the no-changelog label to this PR.

References

Notes

  • Please read our Vector contributor resources.
  • Do not hesitate to use @vectordotdev/vector to reach out to us regarding this PR.
  • Some CI checks run only after we manually approve them.
    • We recommend adding a pre-push hook, please see this template.
    • Alternatively, we recommend running the following locally before pushing to the remote branch:
      • make fmt
      • make check-clippy (if there are failures it's possible some of them can be fixed with make clippy-fix)
      • make test
  • After a review is requested, please avoid force pushes to help us review incrementally.
    • Feel free to push as many commits as you want. They will be squashed into one before merging.
    • For example, you can run git merge origin master and git push.
  • If this PR introduces changes Vector dependencies (modifies Cargo.lock), please
    run make build-licenses to regenerate the license inventory and commit the changes (if any). More details on the dd-rust-license-tool.

@benjamin-awd benjamin-awd requested review from a team as code owners July 7, 2026 10:10
@github-actions github-actions Bot added docs review on hold The documentation team reviews PRs only after a PR is approved by the COSE team. domain: sinks Anything related to the Vector's sinks domain: external docs Anything related to Vector's external, public documentation labels Jul 7, 2026
#[configurable_component]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ArrowIpcCompression {

@benjamin-awd benjamin-awd Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took this implementation from the Datadog Zerobus sink to make it easier to consolidate in a follow-up PR

pub enum Compression {
/// No compression.
#[default]
None,
/// LZ4 frame compression.
Lz4Frame,
/// Zstandard compression.
Zstd,
}
impl From<Compression> for Option<arrow::ipc::CompressionType> {
fn from(value: Compression) -> Self {
match value {
Compression::None => None,
Compression::Lz4Frame => Some(arrow::ipc::CompressionType::LZ4_FRAME),
Compression::Zstd => Some(arrow::ipc::CompressionType::ZSTD),
}
}

Moving it here instead of re-defining it in the Clickhouse sink since anything that implements Arrow Stream IPC will likely want to use these compression options

cc @flaviofcruz

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a07062340

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/sinks/clickhouse/arrow/schema.rs Outdated
Comment thread src/sinks/clickhouse/config.rs Outdated
@benjamin-awd benjamin-awd force-pushed the feat/clickhouse-arrow-ipc-compression branch from 3a07062 to ce72f8f Compare July 7, 2026 10:28
…am encoding

Adds a `compression` option to the clickhouse sink's `arrow_stream` batch
encoding for block-level compression of the Arrow IPC record batch buffers
(`none`, `lz4_frame`, or `zstd`, defaulting to `none`). Compression is applied
inside the IPC stream so each column buffer is compressed independently, using
substantially less CPU than an equivalent whole-payload HTTP `gzip`
`Content-Encoding` at a comparable ratio.

Enabling compression requires ClickHouse 23.11 or newer; older servers accept
the insert but cannot read compressed Arrow IPC, so the sink validates the
server version at startup and rejects the configuration on older servers.

The ArrowIpcCompression enum mirrors databricks_zerobus's Compression (variant
names, From conversion, skip_serializing_if) so the two can be consolidated into
a shared codecs type in a follow-up.
@benjamin-awd benjamin-awd force-pushed the feat/clickhouse-arrow-ipc-compression branch from ce72f8f to 6ae87cc Compare July 7, 2026 10:31
… compression is enabled

The sink's top-level `compression` defaults to `gzip`, so enabling Arrow IPC
buffer compression without also setting `compression: none` would gzip a payload
that already contains compressed Arrow buffers, wasting CPU for negligible gain.

When Arrow IPC compression is enabled, force the HTTP `compression` to `none` and
log that it was disabled, so the IPC compression path does not double-compress by
default.
@benjamin-awd benjamin-awd force-pushed the feat/clickhouse-arrow-ipc-compression branch from 6ae87cc to 18fe83d Compare July 7, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs review on hold The documentation team reviews PRs only after a PR is approved by the COSE team. domain: external docs Anything related to Vector's external, public documentation domain: sinks Anything related to the Vector's sinks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add block-level compression for ClickHouse sink (ArrowStream)

1 participant