|
For the latest stable version, please use Korvet 0.19! |
Remote Storage (Parquet on object store)
Korvet includes a built-in storage offload worker that archives sealed Redis stream segments to per-segment Parquet files on S3.
|
In Korvet tiered storage terminology, the local tier uses Redis Streams and the remote tier uses Parquet files. Korvet uses local/remote in its configuration and APIs. |
Overview
The remote tier is per-segment Parquet files. The storage offload worker:
-
Reads sealed LOCAL segments from each topic-partition’s manifest
-
Streams the segment contents from Redis (one page resident at a time) into a single Parquet file
-
Flips the manifest entry from
LOCALtoREMOTE— the manifest is the commit point -
Runs in-process as part of the Korvet server; there is no separate archive daemon
There is no mirror stream, no transaction log, and no multi-file atomic commit. One sealed segment maps to one Parquet file; the manifest tier-flip is the single commit unit. If the storage offload worker crashes before the flip, the manifest entry stays LOCAL and the next scan re-streams the (still untouched) Redis segment.
Cold storage is broker-private: Korvet controls the path layout, schema, and footer caching, and there is no expectation that external query engines read these files directly.
Configuration
Enable remote storage by setting korvet.storage.remote-path in your application.yml:
korvet:
storage:
remote-path: s3://my-bucket/korvet
s3:
region: us-west-1
offload:
tick-interval: 1m
Setting korvet.storage.remote-path makes the cold tier available. The leader-locked storage offload worker is enabled by default and rolls eligible segments, offloads sealed segments, and enforces local and remote retention. Topics are archived only when they also have remote.storage.enable=true.
|
Storage Properties
| Property | Default | Description |
|---|---|---|
|
required |
Cold-tier root URI. Currently supports |
|
unset |
AWS region for the S3 object store. |
|
unset |
Optional endpoint URL for S3-compatible stores such as MinIO or LocalStack. |
|
unset |
Use path-style addressing. Required for most non-AWS S3-compatible stores. |
|
unset |
Static access-key id. Prefer IAM roles in production. |
|
unset |
Static secret access key. Prefer IAM roles in production. |
Maintenance Properties
| Property | Default | Description |
|---|---|---|
|
|
Enables the storage offload worker in this JVM. |
|
|
Tick cadence for the offload loop. |
|
|
Redis leader-lock lease duration. Must exceed |
Per-Topic Retention Configuration
Control when data moves from the local tier to the remote tier using topic-level configuration:
| Configuration | Default | Description |
|---|---|---|
|
|
Enable tiered storage for this topic (Kafka KIP-405 standard). |
|
|
Time to keep in the local tier. |
|
|
Size to keep in the local tier. |
|
|
Total retention across all tiers. |
Remote-tier retention is implicit: retention.ms - local.retention.ms.
Example: Keep 1 day local and the rest remote (1 year total):
kafka-configs --bootstrap-server localhost:9092 \
--entity-type topics --entity-name my-topic --alter \
--add-config remote.storage.enable=true,retention.ms=31536000000,local.retention.ms=86400000
Storage Format
File Layout
One Parquet file per sealed segment. The default path mapper produces:
<root>/<streamKey>/<segmentId>.parquet
There is no transaction-log directory, no _delta_log/, no manifest file inside the object-store prefix — the manifest lives in Redis.
Parquet Schema
Each file contains the messages of a single sealed segment with this schema:
required STRING id;
required MAP<STRING, BINARY> fields;
| Column | Type | Description |
|---|---|---|
|
STRING |
Full Redis stream message id (e.g. |
|
MAP<STRING, BINARY> |
Opaque key/value map. The storage layer has no Kafka knowledge — Kafka headers and the value blob are just entries in the map. |
AWS Authentication
The cold tier writes through Iceberg’s S3FileIO. Configure common S3 settings under korvet.storage.s3; otherwise the AWS SDK default credential provider chain is used.
Credential providers
Common production choices:
| Provider | Use when |
|---|---|
EC2, ECS, or EKS node roles |
Leave static credentials unset and let the AWS SDK use instance metadata. |
EKS IAM Roles for Service Accounts (IRSA) |
Leave static credentials unset. |
Static access key + secret |
Use |
IRSA (EKS IAM Roles for Service Accounts)
korvet:
storage:
remote-path: s3://my-bucket/korvet
s3:
region: us-east-1
When IRSA is configured on the cluster, AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE are injected into the pod and picked up automatically.
Performance
The storage offload worker achieves high throughput when archiving to same-region S3:
| Configuration | Throughput | Notes |
|---|---|---|
Single stream |
~32,000 msg/s |
Baseline |
4 streams (parallel) |
~115,000 msg/s |
Near-linear scaling |
See Remote Storage Benchmarks for detailed results.
Performance tips
-
Same-region S3: deploy Korvet in the same AWS region as your bucket.
-
Multiple partitions: archival parallelism is per (topic, partition); more partitions = more archive concurrency.
-
Segment size: larger sealed segments produce larger Parquet files with better compression and fewer object-store operations. Tune topic-level
segment-time,segment-bytes, andaverage-message-bytessettings.