Skip to content

Tuning

Write latency is bounded below by one object store PUT, and cost is roughly proportional to how many PUTs are made. Every knob on this page moves along that line: latency against request count, freshness against request count, or failover speed against false positives.

WAL batchbatchInterval250 msstream objectswal_upload_interval10sKV snapshotkv_snapshot_interval10mlake snapshotlake_freshness3macknowledgedread from objectsrecovery startread from the lake

Write latency

A write is acknowledged when its WAL batch is on object storage. The WAL seals a batch at maxBytesInBatch (8 MiB) or when batchInterval (250 ms) lapses, so a lone write on a quiet bucket pays up to the interval on top of the upload. The interval is a parameter on the WAL URI.

bash
--wal-uri "0@s3://mink?region=us-east-1&batchInterval=5"
ParameterDefaultPurpose
batchInterval250 msLongest a batch waits before upload
maxBytesInBatch8 MiBBatch size that seals early
maxUnflushedBytes1 GiBBackpressure. Writes wait once this much WAL is not yet uploaded
maxInflightUploadCount50Concurrent WAL uploads
readaheadDataSize100 MiBReadahead when replaying the WAL on failover

5 ms gives near-floor latency at one PUT per flush. Busy buckets are insensitive to the interval because size seals the batch first. The compose stacks use batchInterval=5.

An S3 Express One Zone directory bucket as the WAL cuts the PUT itself to single-digit milliseconds while the data bucket stays on standard S3. Detected from the --x-s3 name suffix, or forced with s3Express=true.

Throughput

Throughput comes from parallelism, not from faster individual writes.

LeverEffect
Rows per writeOne durability wait per batch. mink write --batch-rows, mink bench --batch
Bucket countEach bucket is an independent log with its own leader and WAL pipeline. --bucket-count at create, default_bucket_count for the cluster
Concurrent writersWrites to different buckets run on different nodes. Writes to one bucket are serialized by the leader
Idempotent writersA writer id and sequence per bucket. Retries after a timeout do not duplicate

mink bench reports what a combination achieves against a real cluster, with redirects and leader waits in the numbers.

Recovery time

KeyDefaultTrade
wal_upload_interval10sShorter keeps less WAL to replay on failover, at more object writes
kv_snapshot_interval10mA primary-key bucket recovers from the newest snapshot plus the changelog since. Shorter is a faster open at more snapshot uploads
snapshots_retained1More retained snapshots cost object storage and buy nothing for recovery, since the newest is used

Failover of a primary-key bucket is snapshot download plus changelog replay from the snapshot's offset. The interval bounds the replay.

Failover speed

KeyDefaultTrade
lease_ttl30sA node is dead after this long without a heartbeat. Shorter detects failure sooner and turns a GC pause or network blip into a failover
coordinator_tick5sRe-lead happens on the tick after detection. Shorter is faster reassignment at more metadata reads

Heartbeats renew every lease_ttl / 4, so the TTL has to cover several missed renewals. Detection to serving is lease_ttl + coordinator_tick + WAL replay. The compose stacks use 10s and 1s.

Freshness and cost

SettingDefaultTrade
lake_freshness per table3mHow stale the lake may be. Each round is at least one Parquet file per bucket plus a catalog commit, so shorter freshness is more small files
--lake-auto-compactionOffThe tiering worker rewrites small files. Fewer files for lake readers at extra writes
log_ttl per table7dHow long the log serves history. Reads past it come from the lake through union read, not from Kafka
log_retention_interval5mHow often trims run. Coarser is fewer metadata proposals

Request count dominates the bill on most object stores. The three levers that matter are the WAL batch interval, the WAL upload interval and lake freshness. Compaction and snapshot pruning add a background of requests proportional to churn.

Reads

SettingDefaultPurpose
Scan bytes per response16 MiBServer default for a Scan without an explicit limit
Snapshot rows per batch4096Server default for Snapshot and lookups
Leader wait30sHow long a request waits for a bucket that has no leader before Unavailable
kafka.max_fetch_bytes50 MiBCap on one Kafka fetch
kafka.max_wait30sLongest a Kafka fetch parks waiting for data

Tail readers are woken by the write path, so delivery latency for a live consumer is the write acknowledgement latency. Tightening batchInterval improves end-to-end delivery as a side effect.