Configure cold storage

Ursula keeps recent data in an in-memory hot ring on every replica and flushes older segments and snapshot blobs to a cold backend. Multi-node clusters should use S3 or an S3-compatible object store so every replica can read chunks flushed by any leader.

Cold storage is configured in the Ursula config file. Helm and EC2 scripts generate this file from their deployment inputs.

S3 backend

[storage.cold]
backend = "s3"
root = "ursula-prod-20260518"

[storage.cold.s3]
bucket = "my-ursula-bucket"
region = "us-east-1"
# endpoint = "http://127.0.0.1:9000"
# access_key_id = "AKIA..."
# secret_access_key = "..."
# session_token = "..."

Standard AWS credential discovery still applies - when access_key_id and secret_access_key are omitted, Ursula reads credentials via the AWS SDK chain (instance profile, environment, profile, etc.). Set endpoint for S3-compatible stores such as MinIO, R2, or TOS.

Flush tuning

The cold-flush worker runs in the background and decides when to move hot segments to the cold backend. Defaults are conservative. Tune them under load.

Config keyDefaultMeaning
storage.cold.flush_interval1sBackground tick interval
storage.cold.flush_size8MiBTarget bytes flushed per group per tick
storage.cold.flush_max_concurrency4Parallel cold writes in flight
storage.cold.max_hot_size_per_group64MiBBackpressure ceiling

A typical benchmark profile drops the interval to 200ms, raises concurrency to 32, and bumps the per-group ceiling.

Advanced deployments can still split the flush threshold and batch size with storage.cold.flush_min_hot_size and storage.cold.flush_max_size, but the single storage.cold.flush_size knob is the normal path.

Operating notes

  • The storage.cold.root prefix is appended to every cold key. Use a date-stamped value (ursula-prod-20260518T000000Z) when running benchmarks so you can clean up afterwards without touching production data.
  • scripts/ursula_ec2.py --config cluster.json cleanup-s3 --root <prefix> deletes a single root prefix from the bucket configured in the manifest. There is no built-in retention policy beyond Ursula's snapshot GC.
  • Cold reads can be served by any replica that has applied the stream metadata referencing the cold chunks. All replicas must point at the same shared bucket so follower reads and post-leadership-change reads can fetch the same objects on demand.