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 key | Default | Meaning |
|---|---|---|
storage.cold.flush_interval | 1s | Background tick interval |
storage.cold.flush_size | 8MiB | Target bytes flushed per group per tick |
storage.cold.flush_max_concurrency | 4 | Parallel cold writes in flight |
storage.cold.max_hot_size_per_group | 64MiB | Backpressure 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.rootprefix 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.