|
For the latest stable version, please use Korvet 0.19! |
Redis Data Structures Reference
This page provides a reference of all Redis keys and data structures used by Korvet.
| This page is for contributors and operators debugging storage layout. It is not required for normal client usage. |
Keyspace Reference
All keys live under a configurable namespace prefix (default korvet). In the patterns below,
<angle brackets> denote placeholders; curly braces {…} are literal characters in the key,
used as Redis Cluster hash tags so related keys map to the same slot. <stream> denotes a
topic-partition stream key of the form <topic>:<partition>.
| Key pattern | Type | Purpose |
|---|---|---|
Registry and metadata |
||
|
JSON |
Topic registry: one document keyed by topic name (see Topic Metadata Keys) |
|
JSON |
Per-topic metrics document (message counts, sizes) maintained by the metrics store |
|
JSON |
Schema registry subjects and versions |
Broker coordination and security |
||
|
JSON |
Broker node registry: one document mapping broker id to host, port, rack, and heartbeat timestamp |
|
JSON |
SASL credentials for one user (mechanism, password hash, server key, salt, iterations) |
|
JSON |
ACL rules for one principal, mapping topic names to granted operations |
|
String |
Atomic counter ( |
Consumer groups and committed offsets |
||
|
Hash |
Committed offsets for one consumer group: the |
|
Search index |
|
|
String |
Legacy per-group-per-partition committed offset. Only the migrate command reads or writes this layout; the braces are a literal hash tag |
Local storage |
||
|
Stream |
Message log for one topic partition (see Stream Keys). With tiered storage, physical streams append a segment id: |
Tiered storage |
||
|
JSON |
Segment state for one partition: array of segment descriptors (id, status, offsets, location) |
|
Hash |
Per-group read cursors for a tiered partition: field is the group ID, value is the last-read message ID |
|
Stream |
Pending-entry list for one tiered consumer group; entries reference segment IDs awaiting acknowledgment |
|
String |
Storage-worker leader lock: holder token written with |
Iceberg catalog (under the configured catalog key prefix, default |
||
|
JSON |
Catalog root registry: namespaces, table name to UUID mapping, and properties |
|
JSON |
Per-table metadata: table name and a map of version number to metadata file location |
The tiered cursor and PEL keys wrap <stream> in a literal {…} hash tag so all
coordination keys for one partition share a cluster slot. Committed-offset group hashes are
deliberately not hash-tagged so they spread across slots.
|
Korvet uses Redis Streams for message delivery, plus Redis-backed metadata structures for topics and explicit committed offsets:
korvet)Partition Streams:
├─ korvet:storage:local:orders:0 (Stream)
│ ├─ 1234567890123-0: {value: <bytes>, key: <bytes>, headers: <bytes>, timestamp: <ascii>}
│ └─ 1234567890123-1: {value: <bytes>, timestamp: <ascii>}
│
├─ korvet:storage:local:orders:1 (Stream)
│ └─ 1234567890456-0: {value: <bytes>, key: <bytes>, timestamp: <ascii>}
│
└─ korvet:storage:local:orders:2 (Stream)
└─ 1234567890789-0: {value: <bytes>, timestamp: <ascii>}
Consumer Groups (Redis Streams native):
├─ korvet:storage:local:orders:0 has consumer group "my-group"
│ └─ Managed by Redis: XGROUP, XREADGROUP, XACK
│
└─ korvet:storage:local:orders:1 has consumer group "my-group"
└─ Managed by Redis: XGROUP, XREADGROUP, XACK
Committed Offsets:
└─ korvet:broker:commit:my-group (Hash)
├─ group -> "my-group"
├─ orders:0 -> "44"
└─ orders:1 -> "17"
Each Kafka record is stored as a single Redis Stream entry whose body breaks the record out into
separate, directly-readable fields: value, key, headers (all headers in one self-delimiting blob,
preserving order and duplicate keys), and timestamp (ASCII decimal). A field is omitted when its
component is absent (a missing value is a tombstone), so a keyless, headerless record carries just
{value, timestamp}. The value field holds the record value verbatim and is what a non-Kafka client
reads directly via XRANGE — unless the topic’s storage.compression.type compresses that field.
|
Stream Keys
Each Kafka topic partition maps to a single Redis Stream:
korvet:storage:local:<topic>:<partition> # Stream: message log
Examples (using default keyspace korvet):
korvet:storage:local:orders:0 # Topic "orders", partition 0 korvet:storage:local:orders:1 # Topic "orders", partition 1 korvet:storage:local:payments:0 # Topic "payments", partition 0
This is the logical partition stream key. With tiered storage, the physical Redis streams
append a trailing segment id (korvet:storage:local:orders:0:0, …:0:1, …). See
Stream Structure.
|
Topic Metadata Keys
Topic metadata is stored in Redis using a single RedisJSON document:
<keyspace>:topics # JSON object keyed by topic name
Examples (using default keyspace korvet):
korvet:topics # JSON object containing "orders", "payments", "users"
Topic JSON Shape:
{
"orders": {
"name": "orders",
"id": "X5M48X5pT0q1Qgz7RdfQ5w",
"config": {
"partitions": 3,
"retentionTime": 604800000,
"retentionBytes": -1,
"compression": "none",
"storageCompression": "lz4",
"valueType": "AUTO",
"offsetSequenceBits": 14
}
}
}
Topic JSON Fields:
id # Topic UUID (Kafka topic ID) name # Topic name, also used as the parent JSON object key config # Topic configuration object config.partitions # Number of partitions config.retentionTime # Retention time in milliseconds config.retentionBytes # Retention size in bytes config.compression # Compression type (none, gzip, snappy, lz4, zstd) config.storageCompression # Compression type used for Redis storage config.valueType # Value type (AUTO, JSON, RAW) config.offsetSequenceBits # Number of bits for sequence in offset encoding
Offset Encoding
Kafka offsets are stateless - encoded from Redis Stream entry IDs:
Entry ID format: {timestamp}-{sequence}
Kafka offset: (timestamp << N) | sequence
Where N = number of bits for sequence (range 1-16 bits, default 14)
Example (with the default offsetSequenceBits=14):
Entry ID: "1234567890123-5" Offset: (1234567890123 << 14) | 5 = 20227160311775237
Consumer Groups
Consumer groups use Redis Streams native consumer groups for delivery state, plus a separate committed-offset store for explicit Kafka commits:
# Create consumer group
XGROUP CREATE korvet:storage:local:orders:0 my-group 0
# Read as group member
XREADGROUP GROUP my-group consumer-1 COUNT 100 STREAMS korvet:storage:local:orders:0 >
# Acknowledge delivered entries
XACK korvet:storage:local:orders:0 my-group {entryId}
# Persist committed Kafka offsets separately (one hash per group)
HSET korvet:broker:commit:my-group group my-group orders:0 44
OffsetCommit and OffsetFetch operate on the per-group hash: the group field holds the canonical
group ID (indexed by korvet:broker:commit-idx for durable group discovery), and every other field
maps a stream key (<topic>:<partition>) to its committed offset.
Earlier releases stored one string per group and partition
(korvet:broker:commit:{orders:0:my-group}, with a literal hash tag). Only the migrate command
still reads and writes that legacy layout.
|