Scenario 05.3.2 · Reading from the remote tier
Kafka tiered storage: a consumer reads from the remote tier
An offloaded prefix raises localStartOffset; a lagging consumer reading below it is served from remote (remote_read), then crosses back into the local log.
Run this scenario in the playgroundRemote storage on · consumer offline. t+0.000s
The topic has remote.storage.enable=true. The consumer c1 is taken offline (kill_consumer) so it falls behind while the old prefix is offloaded - its committed position stays at 0.
Open at this step: step 1, Remote storage on · consumer offline9 records produced - all in the local log. t+0.600s
Producer p1 writes 9 records (offsets 0-8). The high watermark is 9 and every record still lives on the broker's LOCAL log: localStartOffset is unset (= logStartOffset = 0), so nothing has been tiered yet.
Open at this step: step 2, 9 records produced - all in the local logOld prefix offloaded to remote. t+1.000s
tier_offload copies the [0,6) prefix to the remote tier and raises localStartOffset to 6. The records aren't deleted - they're just no longer on local disk. The local log now begins at offset 6; offsets 0-5 live only in remote storage but stay fully readable.
Open at this step: step 3, Old prefix offloaded to remotePoll from offset 0 - served from remote. t+2.200s
The consumer comes back (restart_consumer) and polls from offset 0. Because 0 is below localStartOffset (6), the broker serves those records from the REMOTE tier - a remote_read at offset 0. max.poll.records=3 returns offsets 0-2; the position advances to 3, still below localStartOffset.
Open at this step: step 4, Poll from offset 0 - served from remoteStill below localStartOffset - remote again. t+3.000s
The next poll starts at offset 3 - still below localStartOffset (6) - so it is another remote_read (at offset 3), delivering offsets 3-5. The position reaches 6: the consumer has drained the entire offloaded prefix from remote storage.
Open at this step: step 5, Still below localStartOffset - remote againCrossed into the local log - caught up. t+3.800s
The final poll starts at offset 6 = localStartOffset, so these records come straight from the LOCAL log - no remote_read. Offsets 6-8 are delivered and the position catches up to the high watermark (9). Tiered storage is transparent to the consumer: it read all 9 records, remote then local, with nothing lost.
Open at this step: step 6, Crossed into the local log - caught upWhat you start with
Once a prefix is offloaded to the remote tier, the partition localStartOffset rises above logStartOffset. A consumer reading below localStartOffset is served from remote storage (a remote_read) until it catches up and crosses back into the locally retained log (KIP-405 tiered storage).
Step by step
- Remote storage on · consumer offline t+0.000s The topic has remote.storage.enable=true. The consumer c1 is taken offline (kill_consumer) so it falls behind while the old prefix is offloaded - its committed position stays at 0. Open at this step: step 1, Remote storage on · consumer offline
- 9 records produced - all in the local log t+0.600s Producer p1 writes 9 records (offsets 0-8). The high watermark is 9 and every record still lives on the broker's LOCAL log: localStartOffset is unset (= logStartOffset = 0), so nothing has been tiered yet. Open at this step: step 2, 9 records produced - all in the local log
- Old prefix offloaded to remote t+1.000s tier_offload copies the [0,6) prefix to the remote tier and raises localStartOffset to 6. The records aren't deleted - they're just no longer on local disk. The local log now begins at offset 6; offsets 0-5 live only in remote storage but stay fully readable. Open at this step: step 3, Old prefix offloaded to remote
- Poll from offset 0 - served from remote t+2.200s The consumer comes back (restart_consumer) and polls from offset 0. Because 0 is below localStartOffset (6), the broker serves those records from the REMOTE tier - a remote_read at offset 0. max.poll.records=3 returns offsets 0-2; the position advances to 3, still below localStartOffset. Open at this step: step 4, Poll from offset 0 - served from remote
- Still below localStartOffset - remote again t+3.000s The next poll starts at offset 3 - still below localStartOffset (6) - so it is another remote_read (at offset 3), delivering offsets 3-5. The position reaches 6: the consumer has drained the entire offloaded prefix from remote storage. Open at this step: step 5, Still below localStartOffset - remote again
- Crossed into the local log - caught up t+3.800s The final poll starts at offset 6 = localStartOffset, so these records come straight from the LOCAL log - no remote_read. Offsets 6-8 are delivered and the position catches up to the high watermark (9). Tiered storage is transparent to the consumer: it read all 9 records, remote then local, with nothing lost. Open at this step: step 6, Crossed into the local log - caught up
The takeaway
Reads below localStartOffset transparently fetch from the remote tier - the consumer sees one continuous log and pays only extra latency for the offloaded segments.
Configs in this scenario
-
remote.Turns on tiered storage (KIP-405) for the topic: older log segments are offloaded from local disk to a remote tier once they pass local.retention.ms, and a consumer reading past them hits a remote read. Total data is still bounded by retention.ms - tiering changes WHERE the data lives, not how long it is kept.storage. enable -
max.The most records one poll() returns (default 500); a smaller value shortens the processing between two polls, which keeps a group member inside max.poll.interval.ms.poll. records
Embed this scenario
Paste this into a blog post, a course page or your team's docs. The scenario plays inside your page, and the link under it points readers to this walkthrough.
<iframe src="https://monedula.dev/kafka-simulator/embed/?scenario=05.3.2" title="Kafka Simulator: Reading from the remote tier" width="100%" height="520" style="border:1px solid #d0d0d0;border-radius:8px" loading="lazy"></iframe>
<p><a href="https://monedula.dev/kafka-simulator/scenarios/reading-from-remote-tier/">Kafka tiered storage: a consumer reads from the remote tier</a></p> Further reading
More in Storage
- Kafka retention.ms and a consumer that falls behind
- Kafka retention.bytes: size-based log retention
- Kafka OFFSET_OUT_OF_RANGE with auto.offset.reset=none
- Kafka log compaction: cleanup.policy=compact explained
- Kafka tombstones: deleting a key with delete.retention.ms
- Kafka cleanup.policy=compact,delete: both policies at once
- Kafka tiered storage: offloading old segments to remote
- Kafka local.retention.ms vs retention.ms in tiered storage
- Diskless Kafka topics (KIP-1163): the write path
- Diskless vs classic Kafka: cross-AZ replication traffic
- Diskless Kafka produce latency: the price of object storage