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.

Configuration is entirely environment-variable based. There is no config file.

S3 backend

export URSULA_COLD_BACKEND=s3
export URSULA_COLD_S3_BUCKET=my-ursula-bucket
export URSULA_COLD_S3_REGION=us-east-1
export URSULA_COLD_ROOT=ursula-prod-20260518   # optional prefix

Standard AWS credential discovery applies - Ursula reads credentials via the AWS SDK chain (instance profile, env vars, profile, etc.). Explicit credentials can be supplied via:

export URSULA_COLD_S3_ACCESS_KEY_ID=AKIA...
export URSULA_COLD_S3_SECRET_ACCESS_KEY=...
export URSULA_COLD_S3_SESSION_TOKEN=...   # optional, for STS

For S3-compatible stores (MinIO, R2, etc.):

export URSULA_COLD_S3_ENDPOINT=http://127.0.0.1:9000

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.

VariableDefaultMeaning
URSULA_COLD_FLUSH_INTERVAL_MS1000Background tick interval
URSULA_COLD_FLUSH_BYTES8 MiBTarget bytes flushed per group per tick
URSULA_COLD_FLUSH_MAX_CONCURRENCY4Parallel cold writes in flight
URSULA_COLD_MAX_HOT_BYTES_PER_GROUP64 MiBBackpressure ceiling: appends to a group above this size return 503 until cold flush catches up

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 URSULA_COLD_FLUSH_MIN_HOT_BYTES and URSULA_COLD_FLUSH_MAX_BYTES, but the single URSULA_COLD_FLUSH_BYTES knob is the normal path.

Operating notes

  • The URSULA_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.