Tiered Storage in Kafka
How Kafka keeps fresh data on fast local disks and older data in cheap object storage, so you can keep months of events without paying for months of expensive broker disks.
Picture a busy restaurant kitchen. The chef keeps salt, oil and today’s vegetables within arm’s reach, because they are used every minute. The boxes of dried goods for the next three months sit in a storeroom down the hall. Nobody puts three months of flour on the cooking counter. There would be no room left to cook.
For most of its life, Apache Kafka worked like a kitchen where everything had to sit on the counter. Every message, whether it arrived a second ago or a year ago, lived on the local disks of the Kafka servers. Tiered storage is Kafka’s storeroom. Fresh data stays on fast local disks, older data moves to cheap and almost unlimited object storage such as Amazon S3, and applications keep reading it exactly as before. This guide explains what that means, how it works inside the broker, what it costs, and where it can hurt you if you are careless.
1The Problem: Kafka Loves Disks, and Disks Are Expensive
Before we learn the solution, we need to feel the pain it removes. Tiered storage exists because of one uncomfortable fact about how Kafka was built.
Storage and compute were glued together
A Kafka broker is a server that receives messages from producers, stores them, and hands them to consumers. In classic Kafka, each broker stores its share of the data on its own attached disks. The same machine that does the work of handling network traffic also holds all the bytes. Engineers call this a shared-nothing design, because no broker depends on a central storage system.
This design was a great choice in the early years. Local disks are fast, and Kafka reads and writes them in a straight line, which is the fastest way a disk can be used. But it has a hidden cost. When you want to keep more data, you must add more disk. And the only way to add more disk is to add more brokers, or buy bigger disks for every broker.
Imagine a bakery where the only way to store more flour is to build another whole bakery, with new ovens, new bakers and new counters. You do not need more ovens. You only need more shelves. But the shelves and the ovens are sold as one package. That is classic Kafka storage.
Why this hurts in real life
Suppose a company ingests 2 terabytes of events per day and wants to keep 30 days of history so that new applications can replay old data. That is 60 terabytes of unique data. Kafka normally keeps three copies of every byte for safety, so the cluster needs about 180 terabytes of disk. To hold that much, the team may run dozens of brokers whose CPUs are barely busy. They are paying for compute they do not need, just to rent disk space.
Three separate pains
Paying for idle machines
Brokers are added for disk, not for traffic. CPU, memory and network sit unused while the bill keeps growing.
Slow, risky rebalancing
When a broker dies or a new one joins, whole partitions must be copied. The more data each broker holds, the longer that takes.
Short memory
Teams delete data early to save money, then discover later that they needed it for an audit, a bug investigation or a new machine learning model.
Copy jobs and extra pipelines
Many companies built connectors that copy Kafka data into a data lake. That works, but now there are two copies of the truth and one more system to run.
Tiered storage does not make Kafka faster. It makes Kafka’s memory cheaper and its operations lighter, by letting storage grow without growing the fleet of brokers.
2Kafka Storage Basics You Need First
Tiered storage is built on top of how Kafka already stores data. If these building blocks are clear, everything that follows will feel natural.
Topics, partitions and offsets
A topic is a named stream of messages, like a channel called “orders” or “payments”. Because one machine cannot handle a busy topic alone, Kafka splits each topic into partitions. Each partition is an ordered list of messages that only ever grows at the end. Every message in a partition gets a number called its offset: 0, 1, 2, 3 and so on. A consumer remembers its offset the way you remember the page number in a book.
The log is a set of segment files
On disk, a partition is stored as a log. But the log is not one giant file. Kafka chops it into pieces called segments. At any moment only the newest segment, called the active segment, accepts new writes. When it gets too big or too old, Kafka rolls it: the active segment is closed and never changes again, and a fresh active segment is started. Closed segments are called inactive or rolled segments.
Think of a diary written in a series of notebooks. You write only in the current notebook. When it is full you close it, put it on the shelf, and start a new one. You never go back and change a closed notebook. Tiered storage is going to move those closed notebooks to a warehouse.
What lives inside a segment
Each segment is really a small family of files that share a name based on the first offset they hold.
| Part | What it holds | Why it exists |
|---|---|---|
| Log file | The actual messages, one after another | This is the data itself |
| Offset index | A sparse map from offset to file position | Lets Kafka jump close to any offset without scanning |
| Time index | A sparse map from timestamp to offset | Lets consumers ask for “messages since 9 AM” |
| Transaction index | Records of aborted transactions | Lets readers skip messages from failed transactions |
| Producer snapshot | State about producers that write idempotently | Prevents duplicates after a restart |
| Leader epoch checkpoint | A history of which leader was in charge, and from which offset | Keeps replicas honest after leader changes |
This list matters later, because tiered storage has to move all of these pieces, not just the messages. A segment without its indexes would be a book without a table of contents: still readable, but painfully slow to search.
Retention: how old data is removed
Kafka is not a database that keeps everything forever. Each topic has a retention rule, such as “keep seven days” or “keep 500 gigabytes per partition”. A background task deletes segments that break the rule. One detail trips up many newcomers: Kafka deletes whole segments, never single messages. A segment is only eligible once its newest message is older than the limit.
Replication: the reason for three copies
Each partition has one leader broker that handles all reads and writes, and one or more followers that copy the leader’s log. If the leader dies, a follower that is fully caught up takes over. The group of caught-up replicas is called the in-sync replica set, or ISR. This is what makes Kafka safe, and it is also what triples the disk you need.
Why Kafka reads are so fast
Kafka leans on the operating system’s page cache, a part of memory the OS uses to hold recently touched file data. A consumer that is close to the tail of the log usually reads straight from memory, never touching the disk. Keep this in mind. The difference between reading fresh data and reading old data is a central theme of tiered storage.
Why segments make tiering natural
Kafka’s habit of writing in straight lines and closing files when they fill up turns out to be the perfect starting point for tiering. A closed segment is a finished, unchangeable package. It can be copied without worrying that someone will edit it halfway through. It can be checked by comparing sizes. It can be read in slices because its index tells you exactly where each offset begins. And it can be deleted as a single unit. If Kafka rewrote old data in place, like a database updating a row, moving that data to another system would be far harder. The append-only log is what makes the whole idea possible.
There is one more useful fact. Each segment has a name based on the first offset it contains, so segments are already in a clear order. Kafka can tell which segment holds any offset just by comparing numbers. This same ordering is used later to name and find segments in the remote tier.
Only closed segments can be moved. The active segment is still being written to, so it always stays on the broker.
3What Tiered Storage Actually Is
The idea is simple to say and subtle to build: split each partition’s history across two kinds of storage and hide the split from applications.
Two tiers, one log
With tiered storage, a partition’s log has two homes. The local tier is the broker’s own disks, fast and expensive per gigabyte. The remote tier is an external storage system, slower and far cheaper per gigabyte, usually object storage such as Amazon S3, Google Cloud Storage or Azure Blob Storage. Recent segments are kept in the local tier. Older segments are copied to the remote tier and, after a while, deleted from the local disks.
The important point is that it is still one logical log. Offset 5 is offset 5 whether it sits on a local disk or in a bucket. A consumer asks for an offset and Kafka finds it, wherever it lives.
A hospital keeps this week’s patient files at the nurses’ station and moves older files to a records building across town. A doctor asks the front desk for a file by patient number. The desk finds it in either place. Fetching from the records building takes longer, but the doctor never needs to know which building held it.
What does not change
No change
Producers still send messages to the partition leader. They never talk to object storage.
No change
Consumers use the same fetch requests and the same offsets. Reading old data simply takes a bit longer.
Opt in per topic
You switch tiering on for the topics that benefit. Others keep working the old way.
Same guarantees
Order within a partition, offsets and delivery semantics are all preserved.
A short history
The idea of separating hot and cold data is old in databases and file systems. In Kafka’s world, several vendors built their own private versions first. Confluent shipped tiered storage in its commercial platform and cloud service, and Amazon offered tiered storage on Amazon MSK for provisioned clusters. Other streaming systems took different routes: Apache Pulsar offloads old segments to object storage, and Redpanda has its own cloud storage feature built into the broker.
The open source community wanted a standard version. The design was written up as KIP-405 (a KIP is a Kafka Improvement Proposal). Engineers from several companies, including Uber and Confluent, refined it over several years. It reached early access in Apache Kafka 3.6 in late 2023, and was declared production ready in Apache Kafka 3.9 in late 2024.
| Milestone | What it meant for users |
|---|---|
| Vendor implementations | Confluent and Amazon MSK offered private, product-specific tiering |
| KIP-405 accepted | A shared design with pluggable storage backends |
| Kafka 3.6 | Early access, good for testing but not for critical workloads |
| Kafka 3.9 | Declared production ready, with the ability to turn tiering off for a topic |
Open source Kafka defines the plumbing but does not ship a storage plugin for S3 or GCS. You bring a plugin, either from a vendor or from an open source project such as the ones published by Aiven, or you use a managed service that has it built in.
4Architecture and Core Components
Four moving parts make tiering work. Learn their names now and the rest of this guide will read like a story.
The four building blocks
| Component | Job | Everyday comparison |
|---|---|---|
| Local log | Holds the active segment and recent closed segments on broker disks | The nurses’ station |
| RemoteLogManager | The coordinator inside every broker; schedules copying, cleaning and remote reads | The records clerk |
| RemoteStorageManager (RSM) | A plugin that knows how to write, read and delete segment files in the chosen storage system | The delivery truck to the records building |
| RemoteLogMetadataManager (RLMM) | A plugin that keeps the catalogue of which segment lives where | The card catalogue at the front desk |
flowchart TB
PR["Producers"] --> LL
CO["Consumers"] --> LL
subgraph LB["Leader Broker"]
LL["Local Log: active and recent segments"]
RLM["RemoteLogManager"]
RSM["RemoteStorageManager plugin"]
RLMM["RemoteLogMetadataManager plugin"]
LL --> RLM
RLM --> RSM
RLM --> RLMM
end
LL --> FB["Follower Brokers: copy the local tier only"]
RSM --> OBJ["Object Storage: S3, GCS, Azure Blob or HDFS"]
RLMM --> MT["Internal topic: __remote_log_metadata"]
Reading the diagram
Producers and consumers connect to the leader broker exactly as they always did. Inside the broker, the local log is the familiar set of segment files. Next to it sits the RemoteLogManager, a new piece of broker code that owns everything related to the remote tier. It does not know how to speak to Amazon S3 or Google Cloud Storage. Instead, it calls the RemoteStorageManager plugin, which does. Swapping storage systems means swapping the plugin, not rewriting Kafka.
The RemoteLogMetadataManager plugin answers a different question: “For partition 7 of the orders topic, which segments exist in remote storage, and what offsets does each cover?” The default implementation keeps this catalogue in an internal Kafka topic, so Kafka uses itself to remember where its own history went.
Why two plugins instead of one
Storing bytes and remembering where the bytes went are separate problems. Object stores are excellent at holding large files but poor at fast, consistent lookups across thousands of small records. Kafka topics are excellent at fast, ordered, replicated records. So the design lets each system do what it is best at. The bulk data goes to the bucket. The small catalogue stays in Kafka.
Who does the work
Only the leader of a partition copies its segments to the remote tier. Followers do not upload, which prevents three brokers from uploading the same segment three times. If leadership moves, the new leader picks up where the old one stopped, guided by the catalogue.
Because the storage backend is a plugin, the same Kafka feature can sit on top of a public cloud bucket, a private object store in your data centre, or a distributed file system such as HDFS.
5What a Storage Plugin Must Do
The RemoteStorageManager plugin is where Kafka meets the outside world. Understanding its job explains many of the behaviours you will see in production.
The four jobs
Kafka asks the plugin to do only four things. Everything else, such as deciding when to copy and what to keep, stays inside the broker. This small contract is what makes the design so portable.
| Operation | What the broker asks | Everyday comparison |
|---|---|---|
| Copy segment | “Store this closed segment and all its companion files” | Sending a sealed box to the warehouse |
| Fetch segment range | “Give me the bytes from position A to position B of that segment” | Asking for chapter 5 of a stored book, not the whole book |
| Fetch index | “Give me the offset index, time index or other companion file” | Asking for the table of contents |
| Delete segment | “Remove everything stored for that segment” | Shredding the box and its contents list |
Good plugins handle the boring details well
Careful object keys
Each object needs a unique name built from the topic’s unique ID, the partition and the offset range. Using the ID instead of the topic name avoids clashes if a topic is deleted and recreated with the same name.
Multipart uploads
Large segments are sent in parts, so a failure only forces a retry of one part, not of the entire file.
Retries with backoff
Storage services occasionally return temporary errors. A good plugin retries politely and gives up cleanly so the broker can try again later.
Range reads and caching
Reading only the needed bytes and caching popular chunks cuts both latency and request bills.
Credentials and encryption
Using role-based identities and supporting encryption keeps secrets out of configuration files. Some plugins also offer extras such as compression or client-side encryption.
Useful metrics
Counts of requests, errors and bytes for each operation help you spot trouble before users do.
Why the key layout matters
Object stores spread data across many machines by looking at the beginning of each object’s name. If every name starts the same way, requests can pile up on the same machines. Well-designed plugins add variety near the start of the key, so traffic spreads out. This is invisible when you are small and painful when you are large, so ask about it when choosing a plugin.
Before you choose a plugin, ask five questions. Which Kafka versions does it support? How does it name objects? How does it authenticate? Does it cache and retry? How active is its maintenance?
6How Data Moves to the Remote Tier
Copying happens quietly in the background. Producers and consumers never wait for it, and it never touches the active segment.
The copy loop
Every broker runs a pool of background threads that belong to the RemoteLogManager. For each partition where the broker is the leader, one task wakes up on a regular schedule (every 30 seconds by default) and asks a simple question: “Are there closed segments that have not been uploaded yet?” If the answer is yes, it starts uploading them, oldest first.
There is one safety rule. A segment is only uploaded when all of its messages are fully settled. That means the messages are replicated to the in-sync followers, and any transactions inside them have finished, either committed or aborted. Kafka tracks this using a marker called the last stable offset. Nothing beyond that marker is allowed to leave the broker. This stops half-finished transactions from being frozen into cold storage.
sequenceDiagram
participant L as Leader Broker RemoteLogManager
participant M as Metadata Manager
participant S as Storage Plugin
participant O as Object Storage
L->>L: Find closed segments not yet copied
L->>M: Record segment as COPY_SEGMENT_STARTED
L->>S: Hand over segment, indexes and snapshots
S->>O: Upload the files
O-->>S: Upload acknowledged
S-->>L: Copy complete
L->>M: Record segment as COPY_SEGMENT_FINISHED
Note over L: Local copy stays until local retention expires
Walking through the steps
Find work
The leader lists its closed segments and compares them with the catalogue to see which are still local only.
Announce the plan
Before uploading a single byte, the leader writes a “copy started” record to the metadata topic. If it crashes mid-upload, everyone knows an unfinished upload exists.
Upload the whole family
The storage plugin sends the message file, the offset and time indexes, the transaction index, the producer snapshot and the leader epoch history.
Confirm
Once the storage system acknowledges the upload, the leader writes “copy finished”. Only now does the segment count as safely tiered.
Wait for local retention
The local copy is not deleted immediately. It is kept until the local retention rule says it is old enough.
What if the upload fails?
Networks fail and buckets have bad days. If an upload does not complete, the segment is simply tried again on the next cycle. The catalogue still says “started”, not “finished”, so no reader is ever pointed at a half-uploaded segment. Leftover partial files are cleaned up later. This is the same idea a careful shipping company uses: the package is not marked as delivered until the receiver signs for it.
Why segment size matters so much
Only closed segments are copied, and a segment closes when it reaches its size limit (1 gibibyte by default) or its age limit (7 days by default), whichever comes first. This has a surprising effect on quiet topics. A topic that receives only a trickle of data may take days to fill a segment, so its data stays on local disks longer than you might expect.
For low-traffic topics, lower the segment age limit so that segments roll more often and reach the remote tier sooner. For very busy topics, make sure segments are not so small that you create millions of tiny objects in the bucket.
The cost of copying
Uploading is not free. Every tiered byte must be read from the broker’s disk (or page cache) and pushed over the network to the storage system. On a busy cluster this adds steady background traffic on top of normal replication. Recent Kafka versions include throttles that cap how fast a broker may copy and how fast it may read back, so tiering cannot starve real-time traffic. Plan for this extra network load when you size your brokers.
7The Life of a Segment
A segment passes through clear stages from birth to deletion. Knowing them helps you read metrics, predict disk usage and debug problems.
stateDiagram-v2
[*] --> Active
Active --> Rolled: segment rolls
Rolled --> Copying: leader starts upload
Copying --> Rolled: upload fails, retry later
Copying --> Tiered: upload finished
Tiered --> RemoteOnly: local retention expires
Tiered --> Deleting: total retention expires
RemoteOnly --> Deleting: total retention expires
Deleting --> [*]: files removed from remote storage
Stage by stage
| Stage | Where the data lives | What is happening |
|---|---|---|
| Active | Local disk only | Receiving new messages from producers |
| Rolled | Local disk only | Closed and waiting for the next copy cycle |
| Copying | Local disk, partly remote | Upload in progress; not yet trusted by readers |
| Tiered | Local disk and remote storage | Safe in both places; readers may use either |
| RemoteOnly | Remote storage only | Local copy deleted; reads go through the remote path |
| Deleting | Remote storage, being removed | Total retention expired; cleanup running |
Two start markers you should know
Kafka tracks two numbers for each partition. The log start offset is the very first offset that still exists anywhere, local or remote. It moves forward only when total retention deletes old data. The local log start offset is the first offset still on the broker’s own disks. It moves forward whenever local retention removes a segment that has already been tiered. The gap between the two numbers is exactly the amount of history that lives only in remote storage.
A worked example
A partition holds offsets 0 to 9,999,999. The remote tier has everything from offset 0 up to 8,999,999. The local disk holds 9,000,000 onward. Here the log start offset is 0 and the local log start offset is 9,000,000. A consumer asking for offset 4,500,000 is served from remote storage. A consumer asking for 9,500,000 is served locally.
The safety guarantee behind local deletion
Kafka will never delete a local segment that has not been confirmed as copied. This single rule protects you from data loss. It also has a flip side that we will meet again in the mistakes chapter: if copying stalls, local disks cannot be cleaned, and they slowly fill up.
Metadata states
The catalogue records four states for every remote segment: copy started, copy finished, delete started and delete finished. The two “delete” states mirror the two “copy” states for the same reason. If a broker crashes halfway through cleanup, the catalogue shows that deletion was in progress, and a later run can safely finish the job.
8How Reads Work
A consumer sends the same fetch request as always. The broker quietly decides whether to answer from the counter or from the storeroom.
flowchart TD
A["Consumer sends a fetch request with an offset"] --> B{"Is the offset in the local log?"}
B -->|"Yes"| C["Read from page cache or local disk"]
B -->|"No, it is older than the local log start"| D["Ask the metadata manager which remote segment holds it"]
D --> E["Remote reader thread fetches the needed bytes through the storage plugin"]
E --> F["Broker returns the data to the consumer"]
C --> F
The local path
If the requested offset is at or after the local log start offset, nothing is different from classic Kafka. The broker looks up the position in the offset index, reads the bytes and returns them. Real-time consumers, which stay close to the tail of the log, live here. They see the same speed as before.
The remote path
If the offset is older than anything on local disk, the broker asks the metadata manager: “Which remote segment covers this offset?” It then asks the storage plugin for just the part it needs. Object stores allow reading a byte range from inside a large object, so the broker does not download a whole 1 gibibyte segment to serve a small fetch. It first reads the small index files to find the right position, then reads the exact range of messages.
Crucially, this work does not happen on the broker’s main network threads. Slow remote reads are handed to a separate pool of remote reader threads, and the fetch request waits in a holding area until the data arrives. This keeps a slow bucket from freezing the broker’s normal traffic.
A librarian at the front desk can hand you a book from the shelf behind her instantly. If you ask for an old book stored in the basement, she does not walk away and leave the desk unattended. She sends a helper to fetch it and keeps serving other visitors until the helper returns.
Speed expectations
Local reads from memory take well under a millisecond. Remote reads must cross a network to an object store, and the first byte typically arrives after tens of milliseconds. That is fine for a job replaying last month’s data, but it would be a poor fit for a service that needs an answer within five milliseconds. Once the first bytes arrive, however, remote throughput can be very high, especially when many partitions are read in parallel, because object stores scale out well.
A hidden benefit: protecting the page cache
In classic Kafka, when a consumer replays old data, the broker must read old segments from disk. Those reads pull cold data into the page cache and push out the hot data that real-time consumers need. The result is a “noisy neighbour” problem: one big replay job can slow everyone else. With tiered storage, old data is served through the remote path instead of the local disk, which reduces this interference.
Indexes are cached
Reading the same small index files from the bucket again and again would be wasteful. The broker keeps a local cache of recently used remote index files, with a configurable total size. This is a small cache, but it makes repeated reads from the same remote segment far faster.
Uber, which runs one of the largest Kafka deployments in the world, has publicly discussed tiered storage as a way to keep data longer without buying brokers in proportion to the amount of history kept.
9The Journey of One Message
Let us follow a single order event through its entire life in a tiered cluster. This ties every earlier chapter together.
Imagine an online shop sends an event called “order 84213 placed” to a topic named orders. The topic keeps data for 30 days in total and one day on the brokers. Here is what happens.
Second 0: the write
The producer sends the event to the leader of the partition chosen for it. The leader appends it to the active segment and assigns it an offset.
Milliseconds later: replication
Followers fetch the new message and copy it into their own active segments. Once enough replicas have it, the message becomes visible to consumers and the producer receives its acknowledgment.
Seconds later: first reads
The shipping service, tailing the log, reads the event straight from memory. Nothing about tiering is involved.
Hours later: the segment closes
The active segment reaches its size limit and rolls. The event is now inside a closed segment, and no more writes will ever touch it.
Within a minute or so: the upload
The next copy cycle on the leader uploads the segment with its indexes. The catalogue records “copy finished”. The event now exists on local disks and in the bucket.
Day 1: local cleanup
Local retention expires. Each broker deletes its local copy of the segment, and the local log start offset moves forward past the event.
Day 10: a replay
A data scientist starts a job that reads the topic from the beginning. When it reaches offset of the event, the broker fetches it from the bucket through the remote path.
Day 31: the end
Total retention expires. The leader marks the segment for deletion, removes its files from the bucket, and the log start offset moves forward. The event is gone.
What this story shows
The event was written once, replicated locally for a short time, copied once into the bucket, and deleted twice: once from the brokers and once from the bucket. Its offset never changed. The application that replayed it on day 10 used the same client library as the shipping service on second 3. The complexity lives inside the broker, which is exactly where it should live.
Between step 4 and step 5 the event exists only in a closed local segment on three brokers. Between step 5 and step 6 it exists in four places. After step 6, the bucket holds the only copies. This is why bucket protection matters so much.
10Retention Rules Explained
With two tiers you need two clocks. Getting these settings right is the difference between a smooth rollout and a full disk at 3 AM.
Two kinds of retention
The familiar retention.ms and retention.bytes settings now describe the total lifetime of the data, across both tiers. Two new settings, local.retention.ms and local.retention.bytes, describe how long data stays on the broker’s own disks. By default the local settings follow the total settings, which means no data would leave the broker early. You must lower the local values to see any benefit.
| Setting | Controls | Example |
|---|---|---|
retention.ms | Total age limit across local and remote tiers | 30 days |
retention.bytes | Total size limit per partition across both tiers | Unlimited |
local.retention.ms | Age limit on broker disks | 1 day |
local.retention.bytes | Size limit per partition on broker disks | Unlimited |
A timeline for one segment
| Age of the segment | Local disk | Remote storage |
|---|---|---|
| Just closed | Yes | Not yet |
| A few minutes old | Yes | Yes, after the next copy cycle |
| 2 days old | No, local limit of 1 day passed | Yes |
| 31 days old | No | No, total limit of 30 days passed |
Infinite retention
Setting total retention to unlimited turns Kafka into a long-term record of everything that ever happened. This is powerful for event sourcing, audit trails and replaying history into new systems. Before tiering, it was too costly for most teams. With object storage, keeping years of data can cost less than a single extra broker.
Rules that must hold
- Local retention should never be larger than total retention. It would make no sense to keep data locally that is already deleted overall.
- Tiering is switched on per topic. Enabling it on a topic that already has data means existing closed segments are copied over time, not instantly.
- Deleting a topic also removes its data from remote storage, so treat topic deletion with the same care as before.
Setting local retention very low is tempting because it saves the most disk. But local disks can only shrink after segments are copied. If your copy speed is lower than your write speed, or if the bucket has an outage, local disks fill up because nothing can be deleted safely. Always leave generous headroom.
Choosing the local window
A helpful rule of thumb is to keep on local disks whatever your normal, latency-sensitive consumers read. If all your real-time consumers stay within an hour of the tail, a local window of several hours to a day gives comfortable room for consumer restarts and small outages. Anything older is a replay, and replays can tolerate the remote path.
11Replication, Leader Changes and Recovery
This is where tiered storage quietly pays off the most. Operations that used to take a day can shrink to an hour.
Followers copy only the local tier
The remote tier already stores each segment once, inside a storage system that keeps its own extra copies for safety. So Kafka does not ask three brokers to each hold a full local copy of the old history. Followers replicate only what is on the leader’s local disks. The leader’s local log start offset tells a follower where to begin.
Think about what happens when a broker dies and a replacement joins. In classic Kafka, the newcomer must copy every partition it now owns, from the very first offset to the last. With tiering, it starts from the leader’s local log start offset and copies only the recent window. The older history stays in the bucket where it always was. The newcomer also downloads a few small pieces of state, such as the leader epoch history and producer snapshots, so it can behave correctly.
When a new librarian joins a branch, she only needs to learn the shelves at the front of the building. She does not need to memorise the entire warehouse. Anyone who wants an old book can still get it from the warehouse.
Leader elections
If the leader fails, a caught-up follower is elected as the new leader, just as before. The new leader does not have to rebuild anything for the remote tier. It reads the catalogue, sees which segments are already uploaded, and continues copying from the next one. The catalogue records the leader epoch for every remote segment. A leader epoch is a counter that goes up each time a new leader is chosen, and it acts like a version number for the log’s history. Using it, Kafka can tell which remote segments belong to the current history and which came from an older history that was cut off by a leader change.
Failure scenarios
| What fails | What still works | What suffers |
|---|---|---|
| One broker crashes | Everything, after leader election | Recovery copies only the local window, so it is quick |
| Object storage is unreachable | Producing and reading recent data | Reads of old data fail; uploads pause; local disks start filling |
| Metadata topic is unhealthy | Producing and reading recent data | Remote reads and uploads cannot find or record segments |
| Upload crashes midway | Everything | The half-finished segment is retried and cleaned up later |
| Bucket data deleted by mistake | Recent data still on local disks | Older history is lost; Kafka cannot rebuild it |
Once old data is deleted locally, the bucket is the only home of that history. Protect it as you would a database: restrict who can delete objects, and consider versioning or object lock features offered by your storage provider.
Rebalancing and scaling out
Adding a broker to spread the load used to be a painful, hours-long event. Now the amount of data that must move is small, so scale-out becomes a routine task. Likewise, replacing a failed disk or an ageing machine no longer feels like an emergency. This is often the strongest argument for tiering on busy production clusters, even for teams that do not care about long retention.
12Guarantees: Ordering, Durability and Availability
A storage feature is only trustworthy if you know exactly which promises it keeps. Here are the promises that survive tiering, and the ones that change shape.
Promises that stay the same
| Promise | What it means | Effect of tiering |
|---|---|---|
| Ordering in a partition | Messages are read in the order they were written | Unchanged; offsets are the same in both tiers |
| Stable offsets | A given offset always refers to the same message | Unchanged; moving a segment does not renumber it |
| Committed data is not lost | A message acknowledged by the required replicas survives a broker failure | Unchanged for recent data |
| Transactional visibility | Readers see only committed transactions if they ask for that | Unchanged; indexes travel with segments |
| Delivery semantics | At-least-once or exactly-once, depending on your setup | Unchanged |
How durability changes
Before tiering, durability of a message came from three broker disks holding copies. With tiering, old data gains a second kind of durability. Once a segment is uploaded, its safety rests on the storage system, which is designed for extreme durability. Amazon S3, for example, is designed for eleven nines of durability, meaning the chance of losing a given object in a year is astronomically small. This is often better than three local disks.
But there is a subtle point. Durability now depends on two different systems, and their protections are configured differently. The brokers protect recent data with replication. The bucket protects old data with its own internal copies. Neither protects you from someone deleting things by mistake. That is why access control and deletion safeguards for the bucket are part of your durability plan, not just your security plan.
How availability changes
The cluster is now available for old data only if both Kafka and the storage system are available. It is available for recent data even when the storage system is down. In other words, the tiering feature adds a dependency for one kind of read, but not for the core work of accepting and serving fresh messages. This partial independence is a deliberate design choice: the bucket being slow or unreachable should hurt replay jobs, not the live business.
A hospital’s emergency room keeps working even if the records building across town loses power. Doctors can still treat new patients using the files at the nurses’ station. Only requests for old records have to wait.
What happens on unclean leader elections
Sometimes every up-to-date replica is lost and Kafka is configured to allow a behind replica to become leader anyway. This is called an unclean leader election, and it can drop the newest messages. With tiering, the leader epoch history stored with remote segments helps Kafka keep the two tiers consistent. Segments written under a history that got cut off are not served as if they belonged to the new history. The rules for what is lost do not become worse, but the extra bookkeeping is one more reason the catalogue must be kept healthy.
Consistency between tiers
A reader who asks for offset 100 gets the same message whether it comes from local disk or remote storage, because both copies were made from the same closed, unchangeable segment. The copy is only trusted after the catalogue records it as finished. There is no time when two readers can see two different versions of the same offset.
Immutability makes all of this work. A closed segment never changes, so copying it, caching it, reading it in pieces and deleting it are all simple, safe operations.
13The Remote Metadata Layer
The catalogue is the brain of tiered storage. If the bucket holds the books, the catalogue knows which shelf each book is on.
What the catalogue must answer
| Question | Why it matters |
|---|---|
| Which remote segments exist for this partition? | Needed to compute how much history is available |
| Which segment holds offset N? | Needed for every remote read |
| Which leader epoch wrote this segment? | Needed to keep history consistent after leader changes |
| Is this segment complete, or half uploaded? | Needed so readers never touch incomplete objects |
| Which segments have passed total retention? | Needed to delete them from the bucket |
The default: a Kafka topic
Kafka ships with a catalogue implementation that stores its records in an internal topic named __remote_log_metadata. Each event, such as “copy started” or “delete finished”, is one message in that topic. Every broker reads the topic and builds an in-memory picture of the segments it cares about. Because the topic is an ordinary replicated Kafka topic, it inherits Kafka’s durability and ordering for free.
The internal topic has its own number of partitions and its own replication factor, both configurable. Different user partitions map to different metadata partitions, which spreads the catalogue’s load. The metadata topic itself is not tiered, and its records are kept indefinitely so the catalogue never forgets a segment that still exists.
Kafka keeps a diary about where it filed its old diaries. It is a little like asking a bank to keep a ledger of which safety deposit boxes exist. The ledger is small, but without it the boxes are useless.
What happens at broker start-up
When a broker restarts, it must read the metadata topic to rebuild its picture. For clusters with an enormous number of tiered segments, this takes time, and remote reads for a partition wait until the broker has caught up on that partition’s metadata. This is one more reason not to create absurd numbers of tiny segments.
Consistency and object stores
Older object stores were only “eventually consistent”, meaning a freshly uploaded file might not be visible right away. This used to make designs like this risky. Modern services such as Amazon S3 now give strong read-after-write consistency, so once an upload is confirmed, it can be read. Even so, Kafka does not rely on this alone. Reads are only pointed at segments the catalogue marks as finished, which adds a second layer of safety.
Custom catalogues
The metadata manager is also a plugin. A company could replace the default with a catalogue stored in a database or in the object store itself. Most teams keep the default because it needs no extra infrastructure.
Monitor the metadata topic like any other critical topic: check its under-replicated partitions and consumer lag. If the catalogue is unhealthy, tiering is unhealthy.
14How Tiering Works With Other Kafka Features
Kafka is more than a log. Transactions, consumer groups, stream processing and mirroring all touch stored data, so it helps to know how each behaves when history is split across two tiers.
Transactions and exactly-once processing
A transaction lets a producer write to several partitions and have them all become visible together, or not at all. Consumers configured to read only committed data must skip messages from transactions that were aborted. To do that, Kafka keeps a small transaction index next to each segment. Tiered storage uploads this index along with the segment, so a consumer reading old data through the remote path still skips aborted messages correctly. The rule that only stable data may be uploaded exists for exactly this reason: a transaction still in progress could otherwise be frozen in an unknown state.
Idempotent producers
An idempotent producer is one that Kafka protects from writing duplicates, even when it retries after a network error. The broker remembers the latest sequence numbers per producer in a producer snapshot file. As you saw earlier, that snapshot is part of the family of files uploaded with each segment. When a new broker takes over, it restores the snapshot so duplicate protection keeps working.
Consumer groups and committed offsets
Consumer groups remember their progress by saving offsets into an internal topic. That internal topic is small and compacted, and it is not tiered. Your committed offsets therefore work exactly as before. If a group has been down for two weeks and resumes, its saved offset simply points into the remote tier, and the group catches up through the remote read path without any special action.
Looking up messages by time
Applications often ask, “Give me the first message after 3 PM last Tuesday.” Kafka answers this using the time index. With tiering, the time index of remote segments is stored in the bucket, so these lookups work across both tiers. The lookup may take a little longer when it has to fetch a small index file from remote storage, but the result is the same.
Kafka Streams, Kafka Connect and mirroring
State rebuilds
Stream processing applications rebuild their local state from changelog topics. Those are usually compacted, so they stay on brokers. Input topics that are tiered can be reprocessed from the start after a bug fix.
Reloading sinks
A sink connector that feeds a database or search index can be pointed at the beginning of a tiered topic to rebuild the target from scratch.
Cross-cluster copies
Tools that mirror topics between clusters read like ordinary consumers. Starting a new mirror from the earliest offset now reads history through the remote path.
Same limits apply
Remote reads still pass through the broker, so client bandwidth quotas continue to govern how fast any one application may read.
Topics that cannot be tiered
Two kinds of topics stay on broker disks. Compacted topics are excluded because compaction rewrites segments. Kafka’s own internal topics, such as those that store consumer offsets and transaction state, are excluded too, because they are compacted and small. This is a good design: the data that needs constant rewriting stays close to the brokers, while the large, append-only event streams are the ones that move.
Nothing about your consumer code needs to change to work with tiered data. What changes is timing. Design batch jobs and rebuild jobs to expect slower first reads, and set client timeouts with that in mind.
15Turning It On: A Configuration Guide
Enabling tiering is a small number of switches, but the order and the values matter. Here is the path in plain steps.
Pick a storage plugin
Choose a plugin for your storage system and place it where every broker can load it. Confirm that it matches your Kafka version.
Prepare the bucket and permissions
Create a bucket in the same region as your brokers. Give the brokers an identity, ideally through a role rather than a fixed password, with just enough permission to read, write and delete objects under one prefix.
Switch it on for the cluster
Set the broker-level flag that enables the remote log storage system, name the storage plugin class, and pass the plugin its own settings. This needs a rolling restart of the brokers.
Choose topics
Enable remote storage on the topics that benefit: high-volume topics with long retention are the best candidates.
Set the two clocks
Set total retention for the topic and a shorter local retention so old segments can leave the disks.
Test before trusting
Start with a non-critical topic. Produce data, wait for segments to be tiered, then read from the beginning and confirm the data is complete.
The settings that matter most
| Setting | Level | Purpose |
|---|---|---|
remote.log.storage.system.enable | Broker | Master switch for the feature on the cluster |
remote.storage.enable | Topic | Turns tiering on for one topic |
local.retention.ms and local.retention.bytes | Topic | How long or how much data stays on broker disks |
segment.bytes and segment.ms | Topic | How quickly segments close and become eligible for copying |
remote.log.manager.task.interval.ms | Broker | How often the copy and cleanup tasks run (30 seconds by default) |
remote.log.reader.threads | Broker | Size of the pool that serves remote reads (10 by default) |
remote.log.index.file.cache.total.size.bytes | Broker | Size of the local cache for remote index files (1 GiB by default) |
Sizing segments sensibly
Segment size is the most underrated knob. Too large and quiet topics take ages to tier and local disks stay full. Too small and you create huge numbers of tiny objects, which slows the catalogue, multiplies storage requests and increases cost. Many teams settle on segments of a few hundred megabytes to one gibibyte for busy topics, and use an age limit to force rolls on quiet ones.
Turning it off
Before Kafka 3.9, tiering could not be safely switched off once enabled. From 3.9 onward it can be disabled on a topic, and you choose whether the remote data is deleted or left in place. Because this is a big decision, treat enabling tiering as a commitment and test the exit route in a staging environment.
Exact setting names and defaults change between Kafka versions. Always check the documentation for the version you run before copying values from any guide, including this one.
16Performance and Scalability Trade-offs
Tiered storage is not a free lunch. It trades a little speed for a lot of savings, and it moves some bottlenecks to new places.
Different readers, different experiences
| Reader type | Where it reads | What changes |
|---|---|---|
| Real-time consumer near the tail | Page cache and local disk | Nothing; it still sees the same low latency |
| Consumer restarting after a short outage | Usually local disk | Nothing, if the local window is long enough |
| Consumer catching up after a long outage | Mostly remote storage | Slower start, then high throughput |
| Analytics job replaying weeks of data | Remote storage | Higher latency per fetch, but no impact on local disks |
| New service bootstrapping its state | Remote storage | Can now read months of history without a special data lake copy |
Where the new bottlenecks appear
Extra traffic
Every tiered byte crosses the network to the bucket, and every remote read crosses it back. Plan broker network capacity for this.
Storage request limits
Object stores charge and limit by number of requests. Many small fetches from many partitions can hit those limits.
Reader pool size
If many consumers replay at once, the remote reader thread pool can become a queue.
Catalogue growth
Long retention means more segments, which means more catalogue records to hold in memory.
Scalability in two directions
Before tiering, if you wanted twice the history you needed roughly twice the disks. Now history grows in the bucket, which has effectively no ceiling, while the number of brokers depends on throughput: how many megabytes per second you write and read. This separation of storage from compute is the deepest benefit of the feature. It lets you size each resource for what it actually does.
Keeping replays from hurting real-time traffic
A well-run cluster puts limits around the remote path. Throttle how fast brokers copy and how fast they serve remote reads, so that a giant replay cannot eat all the network. Client quotas add another layer: they can cap how much bandwidth any one application may use. The goal is to make sure a batch job stays a polite guest.
Tuning consumers that read remote data
Because the first byte from object storage takes longer to arrive, consumers that replay old data should ask for more each time they fetch. Every fetch request pays a fixed waiting cost, so a small fetch wastes most of its time waiting. Raising the maximum bytes per fetch and per partition lets each round trip carry a much larger batch, which spreads that waiting cost across more messages.
Parallelism helps too. A topic with many partitions can be read by many consumer instances in the same group at once, up to one instance per partition. Since each instance issues its own remote reads, throughput scales almost in a straight line until you reach a limit in the network, the reader thread pool or the storage service. Finally, review client timeouts. A replay job that gives up after a few hundred milliseconds will fail needlessly, so give remote fetches a generous allowance.
| Consumer setting idea | For live consumers | For replay jobs |
|---|---|---|
| Fetch size per request | Moderate; favours low latency | Large; favours throughput |
| Number of instances | As needed for the workload | Up to the partition count |
| Request timeout | Short | Longer, to allow for remote reads |
| Client identity for quotas | Normal application | Separate identity with its own limit |
Run a realistic test. Replay a large topic from the beginning while producers and real-time consumers run at normal load, and watch latency. Numbers from your own workload are worth more than any rule of thumb.
17Capacity Planning Step by Step
Three resources need sizing: broker disks, network, and remote storage. Let us reuse the earlier scenario of 2 terabytes per day and work through each.
Step 1: turn daily volume into a rate
Two terabytes per day is about 23 megabytes per second on average (2,000,000 megabytes divided by 86,400 seconds). Traffic is rarely flat. Real systems see peaks of three to five times the average, so design for that peak, not the average.
Step 2: size the local disks
Local disk equals daily volume, times days kept locally, times the replication factor, plus headroom. With one day local and three copies, that is 6 terabytes. Keeping about 30 percent free for growth, uneven partitions and recovery brings it to roughly 8 terabytes across the whole cluster. Compare that with about 180 terabytes without tiering.
Step 3: size the network
Each byte crosses the network several times. Suppose three separate consumer groups read every message.
| Traffic type | Multiplier | Average rate |
|---|---|---|
| Producers writing to leaders | 1x | About 23 MB/s |
| Replication to two followers | 2x | About 46 MB/s |
| Three consumer groups reading | 3x | About 69 MB/s |
| Uploads to the remote tier | 1x | About 23 MB/s |
| Total across the cluster | 7x | About 161 MB/s |
Tiering adds one more multiple of the ingest rate for uploads. Replays of old data add remote reads on top, and those can be large if many jobs run together. Spread the total across your brokers and check each broker’s network card with a comfortable margin.
Step 4: size the remote storage and the catalogue
Remote storage equals daily volume times total retention, which is 60 terabytes here, before any compression. If segments are up to 1 gibibyte, you will have at least sixty thousand segments to track. In practice more, because many partitions close segments earlier than the size limit. Keep an eye on the catalogue’s memory use as this number grows.
Step 5: size the thread pools
Copy and cleanup threads should be enough for uploads to keep ahead of closing segments. Remote reader threads should match how many replays you expect at once. Start with the defaults, watch the queue behaviour, and adjust.
Tiering shrinks the disk requirement but does not shrink the network requirement. It slightly increases it. If your brokers are already network-bound, tiering will not fix that.
18The Cost Model: A Worked Example
Numbers make the idea concrete. Here is a simple, honest calculation you can adapt to your own cluster.
The scenario
A company ingests 2 terabytes of new data per day into Kafka and wants to keep 30 days of history. Replication factor is 3. To keep things simple we assume block storage on the brokers costs about $0.08 per gigabyte per month and object storage costs about $0.023 per gigabyte per month. These are rounded, illustrative list prices. Real prices vary by provider, region and volume, and they change over time.
Without tiered storage
Thirty days at 2 terabytes per day is 60 terabytes of unique data. Three copies mean 180 terabytes of broker disk, or 180,000 gigabytes. At $0.08 that is about $14,400 per month for disks alone. And this ignores the free space real clusters must keep, which pushes the number higher.
With tiered storage
Keep one day on the brokers: 2 terabytes times 3 copies is 6 terabytes, or 6,000 gigabytes, costing about $480. The remote tier holds all 30 days once, which is 60 terabytes, or 60,000 gigabytes, costing about $1,380. The total is roughly $1,860 per month.
| Item | Classic Kafka | With tiering |
|---|---|---|
| Data kept on brokers | 180 TB (60 TB x 3 copies) | 6 TB (2 TB x 3 copies) |
| Data kept in object storage | 0 TB | 60 TB (stored once) |
| Broker disk cost | About $14,400 | About $480 |
| Object storage cost | $0 | About $1,380 |
| Total storage | About $14,400 | About $1,860 |
Costs that appear on the other side
- Request charges. Uploads and downloads are billed per request. With segments around 1 gibibyte, a few thousand uploads a day is tiny. Heavy replays that make millions of small reads are where request charges grow.
- Data transfer. Traffic inside a region to object storage is usually free or cheap, but crossing regions or leaving the cloud is not. Keep the bucket next to the brokers, and use private network endpoints so traffic does not pass through expensive gateways.
- Extra network load on brokers. You may need slightly stronger network capacity, but this is small compared with the disk you no longer need.
- Fewer brokers. The bigger saving often comes from shrinking the fleet. If brokers were added only for disk, many can go away, saving compute costs as well.
Savings depend on how long you keep data compared with how much you keep locally. A cluster that only keeps a day or two of data has little to gain from the storage side. The gains come from long retention, or from the operational relief of faster scaling.
19Security, Monitoring and Operations
Moving data out of the brokers moves your security responsibilities too. The bucket is now part of your Kafka system.
Security: protect the bucket like a broker
Kafka access control lists protect topics on the brokers. They do not protect files in a bucket. Anyone who can read the objects can read the messages inside, because segments hold messages in Kafka’s ordinary format. So the bucket must be locked down as tightly as the brokers themselves.
Least privilege
Give brokers a role that can read, write and delete only under their own prefix. Do not use broad administrator rights.
Encrypted connections
Storage plugins should talk to the bucket over encrypted connections, ideally over a private network path.
Server-side encryption
Turn on encryption for the bucket, and use managed keys with audit logs when your rules require it.
No public access
Block public access on the bucket at the account level, and review bucket policies regularly.
Guard against deletion
Restrict who may delete objects by hand. Versioning or retention locks can rescue you from mistakes.
Erasure and residency
Segments cannot be edited, so deleting one person’s data on request means waiting for retention. Plan around this, and keep the bucket in the right region.
Choosing the network path to the bucket
The route that bytes take to reach the bucket affects both safety and cost. If brokers reach the storage service over the public internet, traffic leaves your private network and may be exposed to more risk. If it travels through a shared gateway that charges by the gigabyte, a busy tiering setup can create a surprising bill. Most cloud providers offer a private endpoint, which connects your network to the storage service directly, keeps traffic off the public internet and avoids the gateway charges. Using it is usually the right default. Also confirm that brokers in every availability zone can reach the endpoint, or a zone failure could take tiering down with it.
What to monitor
Kafka exposes new broker metrics for the remote tier. Names differ across versions, but they cover the same ideas: bytes copied per second, bytes fetched from remote per second, request rates, error counts for copy, fetch and delete, and the total size of the remote log. Recent versions also report how far behind the copy process is.
| Signal | Why it matters | Worry when |
|---|---|---|
| Copy lag | Shows how far uploads trail behind closed segments | It grows steadily |
| Copy and delete errors | Show storage or permission problems | Any sustained non-zero rate |
| Remote fetch latency | Shows the health of the read path | It jumps well above your normal baseline |
| Remote reader thread usage | Shows whether replays are queuing | Threads are saturated for long periods |
| Local disk usage | Shows whether cleanup is working | It climbs while local retention should be deleting |
| Metadata topic health | The catalogue must be available | Under-replicated partitions or consumer lag |
| Bucket size and request costs | Shows trends in cost | Growth beyond what retention predicts |
Logging
Broker logs record what the RemoteLogManager and the storage plugin are doing. Upload failures, permission errors and timeouts appear here first. Make sure these logs are shipped to your central logging system and that you have alerts on repeated errors.
Operating routines
- Test restoring a broker from scratch while tiering is on, and time it.
- Practise a bucket outage in staging so the team knows what a full local disk looks like.
- Upgrade brokers and plugins together, and read release notes for tiered storage changes.
- Do not add bucket lifecycle rules that delete or archive Kafka’s objects. Kafka manages deletion itself, and outside interference breaks the catalogue’s promises.
20Troubleshooting Guide
When something looks wrong, start with the symptom. This table covers the problems teams meet most often.
| Symptom | Likely cause | What to check |
|---|---|---|
| Local disks keep filling | Uploads are failing or slow, or local retention is too generous | Copy errors, copy lag, storage permissions, local retention values |
| Tiering cannot be enabled on a topic | Cluster flag is off, plugin did not load, or the topic is compacted | Broker startup logs, topic cleanup policy, broker version |
| Old-data reads time out | Storage latency, too few reader threads, or bucket in the wrong region | Remote fetch latency, thread usage, network path to the bucket |
| Replays slow down live consumers | No throttles, or network saturation | Quotas, network usage per broker, remote fetch rates |
| Permission denied errors | Role lacks rights, or bucket policy blocks the broker | Identity in use, bucket policy, key management rights |
| Huge number of small objects | Segments roll far too often | Segment size and age settings, partition count |
| Slow broker restarts | Large metadata topic to replay | Number of remote segments, metadata topic size |
| Unexpected storage bill | Heavy replays, cross-region traffic, or tiny objects | Request counts, data transfer reports, segment size |
| Remote data missing after a change | Manual deletion or a bucket lifecycle rule | Bucket audit logs and lifecycle configuration |
A calm way to investigate
Decide which path is sick
Is it the copy path, the read path, the cleanup path, or the catalogue? The metrics are grouped that way for a reason.
Check the storage first
Most problems are permissions, network paths or storage service limits, not Kafka bugs.
Look at one partition
Pick a single affected partition and follow it: its local start offset, its remote segments and its errors.
Change one thing at a time
Adjust a single setting, wait through at least one copy cycle, and observe the result before changing more.
21Limitations, Anti-patterns and Common Mistakes
Every useful feature has edges. Knowing them in advance saves painful surprises.
Built-in limitations
Works well for
- Topics that keep data for a long time
- High-volume topics where disk dominates the bill
- Clusters where scaling and recovery are slow
- Replaying history into new systems
Not a fit for
- Compacted topics, which keep the latest value per key, are not supported
- Workloads that need every read to be under a few milliseconds
- Very small clusters with short retention
- Environments with no reliable object storage nearby
Compaction rewrites old segments to remove outdated values. That does not fit with immutable, already-uploaded segments, which is why compacted topics are excluded. Also remember that early releases had gaps, so check the notes for your version before relying on a feature.
Common mistakes
Enabling it everywhere
Tiering adds moving parts. Start with the few topics that dominate your storage.
Forgetting the local setting
Leaving local retention at its default means nothing ever leaves the brokers and there are no savings.
Tiny segments
Millions of tiny objects slow the catalogue and inflate request bills.
Bucket in the wrong place
A bucket in a distant region adds latency and transfer charges.
Ignoring quotas
Without throttles, one replay can crowd out normal traffic.
Never testing an outage
The first time you see a bucket failure should not be in production.
Context
A team wants the biggest possible saving, so it sets local retention to just a few minutes on every topic.
What goes wrong
Segments only close every few hours, and they can only be removed after they are uploaded. Real-time consumers that lag by even a short time now fall onto the slower remote path. During a storage outage, uploads stall and disks fill, because the safe cleanup rule blocks deletion.
Better approach
Set the local window to cover what normal consumers read, plus generous room for restarts and outages. Then measure disk usage and adjust slowly.
A short checklist before go-live
- Have you confirmed the plugin supports your exact Kafka version?
- Have you chosen local retention using real consumer behaviour?
- Are throttles and quotas set?
- Do alerts exist for copy lag, errors and local disk?
- Have you rehearsed a bucket outage?
22Real-World Usage Patterns
Where does tiering pay off in practice? These patterns show up again and again in production.
Long-term event history for audit and replay
Payment and trading platforms often need to reconstruct what happened months ago. With tiering, the event log itself can keep that history at a manageable cost, instead of being duplicated into a separate archive that must be kept in sync.
Fast scaling for very large platforms
Companies that operate huge Kafka fleets, Uber being a well-known example, care about how long it takes to replace a broker or add capacity. Keeping only a recent window on each broker makes these operations far quicker.
Backfills and machine learning
Data teams frequently need to feed months of past events into a new model or a new service. Reading the history straight from Kafka means one source of truth and no need to run a separate export job first.
Telemetry and log pipelines
Clickstreams, metrics and application logs are big and only occasionally re-read. They are ideal for a short local window and a long remote history.
The vendor landscape
| Platform | How tiering is offered |
|---|---|
| Apache Kafka (open source) | Built-in framework from KIP-405, with pluggable storage backends. Production ready from 3.9 |
| Confluent | Tiered storage in its commercial platform and cloud service, with its own tuned implementation |
| Amazon MSK | Tiered storage for provisioned clusters, backed by Amazon’s own storage layer |
| Redpanda | Built-in cloud storage tiering, designed into the broker from the start |
| Apache Pulsar | Offloads older segments of its storage layer to object storage |
Questions to ask a managed service provider
Many teams will not run the plugin themselves but will buy tiered storage as part of a managed Kafka service. That is a sensible choice, but the details still matter. Before you sign, ask a few plain questions and expect plain answers.
What are the limits?
Is there a maximum total retention, a minimum local retention or a cap on storage per topic?
What is billed?
Is remote storage billed per gigabyte only, or are requests and data transfer included? Are reads of old data charged separately?
Which topics qualify?
Are compacted topics excluded? Can tiering be turned on for existing topics?
Can I leave?
If you move away from the service, can you get your history back out in a usable form?
Who holds the keys?
Where is the bucket, who can access it, and can you bring your own encryption keys?
How are incidents handled?
What alerts and metrics do you get about the remote tier, and who is responsible when it misbehaves?
Deciding whether you need it
| Your situation | Verdict |
|---|---|
| Retention of days to years on high-volume topics | Strong fit |
| Brokers added mostly to get more disk | Strong fit |
| Rebalancing takes many hours | Strong fit |
| Small cluster, one or two days of data | Probably unnecessary |
| Mostly compacted topics | Not supported for those topics |
23Tiered Storage Compared With Other Approaches
Tiering is one answer to the long-retention problem. Here is how it stacks up against the alternatives teams often consider.
| Approach | How it works | Strengths | Weaknesses |
|---|---|---|---|
| Bigger disks or more brokers | Keep everything local and pay for it | Simplest; fastest reads for all data | Costly; slow recovery; wasted compute |
| Export to a data lake with a connector | Copy topic data into files for analytics tools | Great for queries and reports | Second copy; different format; replays back into Kafka need extra work |
| Archive cluster with cheap disks | Mirror topics into a second Kafka cluster | Kafka clients work unchanged | Still pays for disk and brokers; more clusters to run |
| Kafka tiered storage | One log split across local disks and object storage | One source of truth; cheap history; faster operations | Slower old reads; more parts to secure and monitor |
| Other systems with built-in offload | Choose a platform that separates storage by design | Deep integration | Migration effort; different ecosystem |
Tiering and the data lake are friends
Teams sometimes think they must choose between tiered storage and a data lake. They solve different problems. Tiering keeps history inside Kafka for replay by streaming applications. A data lake stores data in analytics-friendly formats for queries, dashboards and reports. Many mature platforms run both: Kafka with tiering for the event log, and a connector that lands selected topics into the lake.
Tiered storage is like a museum that keeps its own basement archive of original artefacts. A data lake is like a photo book made from those artefacts for visitors who want to browse. The photo book is easier to flip through. But if you need the real artefact, you go to the basement.
Looking ahead
The Kafka community is discussing designs that go further than tiering, such as writing data straight to object storage without local replication for some topics. These ideas trade latency for even lower cost and simpler operations. They are proposals and experiments today. Choose the tools that are stable in your Kafka version, and revisit the field as it matures.
24Advantages, Disadvantages and Trade-offs
A fair look at both sides, so you can decide with clear eyes.
Advantages
- Storage cost drops sharply for long retention
- Storage grows independently of the number of brokers
- Broker replacement and scale-out become much faster
- Consumers and producers need no code changes
- Months or years of history live in one place
- Replays are less likely to disturb real-time readers
Disadvantages
- Reads of old data are slower to start
- More moving parts: plugins, bucket, catalogue
- Compacted topics are not supported
- The bucket becomes a critical dependency and a security target
- Extra network traffic and request charges
- Older Kafka versions lack production-ready support
Classic Kafka against tiered Kafka
| Dimension | Classic Kafka | Kafka with tiered storage |
|---|---|---|
| Where old data lives | Broker disks, three copies | Object storage, one logical copy |
| Cost of long retention | High and linear | Low and gentle |
| Broker recovery time | Grows with total data | Grows with the local window only |
| Latency for old data | Disk speed | Network and object store speed |
| Failure surface | Brokers only | Brokers, bucket, catalogue |
| Best use | Short retention, ultra-low latency | Long retention, elastic operations |
You give up a little read speed on old data and accept a larger system, and in return you gain cheap history and easy operations. For many teams, that is an excellent bargain. For latency-obsessed, short-retention workloads, it is not.
25Best Practices and Design Patterns
A compact playbook drawn from everything above.
Start with the heavy hitters
List your topics by disk usage. Tier the top few first and measure the effect before widening.
Size the hot window from real behaviour
Look at how far behind the tail your normal consumers read, add room for outages and restarts, and set local retention from that.
Tune segment size
Use moderate sizes for busy topics, and an age limit for quiet ones, so segments reach the remote tier in good time.
Put guard rails around the remote path
Apply copy and read throttles and client quotas so that batch jobs never crowd out real-time traffic.
Keep the bucket close and private
Same region, private network path, encryption on, public access blocked, least-privilege identity.
Alert before it hurts
Watch copy lag, error rates and local disk usage. A rising disk line is the earliest sign that uploads are stuck.
Rehearse failures
Simulate a bucket outage, a broker loss and a metadata topic problem in staging, and write down what you saw.
Design patterns that work well
Hot window, cold history
Short local retention for speed and a long total retention for memory. The most common setup.
Replay in its own lane
Give replay jobs their own client identity and quota, so they are easy to limit and easy to observe.
Event log as system of record
Treat Kafka with unlimited retention as the master record, and rebuild downstream stores from it when needed.
Gradual rollout
Enable on one topic, then a team, then the cluster, checking cost and latency at each step.
26A Safe Rollout Plan
The safest way to adopt tiering is slowly, with a way back at every step. This plan works for both small and large clusters.
Phase 1: prepare
Upgrade to a Kafka version where tiered storage is production ready, or use a managed service that offers it. Choose and test a plugin in a staging cluster. Create the bucket, the role, the encryption keys and the network path. Write down who owns the bucket, because ownership gaps cause the worst incidents.
Phase 2: pilot on one topic
Choose a large but low-risk topic. Enable tiering, but leave local retention equal to total retention at first. This means nothing is deleted locally yet, so if anything goes wrong, all data is still on the brokers. Wait until the copy lag metric falls to near zero and the remote log size matches your expectation.
Phase 3: verify reads
Before removing any local data, prove that remote reads work. Use a test consumer to read from the beginning of a tiered segment range and compare counts and sample content with the original. Test with restarts and with a simulated leader change.
Phase 4: shrink the local window gradually
Now lower local retention in steps, for example from 30 days to 14, then 7, then 3, then 1. After each change, wait long enough to see disk usage fall, and check latency for your real-time consumers. Stop as soon as a consumer complains or metrics show pressure.
Phase 5: expand and operate
Repeat for other large topics. Add alerts, dashboards and run books. Practise the failure scenarios. Review costs each month against your prediction.
Copy lag is stable
Uploads keep pace with closing segments even at peak load.
Reads verified
A full-history read returns the exact expected data.
Alerts fire in tests
A deliberate permission failure in staging triggers the right page.
Rollback rehearsed
The team has practised disabling tiering on a test topic and knows what happens to the remote data.
Never reduce local retention until you have watched a full read from remote storage succeed. Trust, then verify, then shrink.
27Plain-English Glossary
A quick reference for every term used in this guide, in the simplest words we can find.
| Term | Meaning |
|---|---|
| Broker | A Kafka server that receives, stores and serves messages |
| Topic | A named stream of messages, such as orders or payments |
| Partition | One ordered slice of a topic, spread across brokers for parallel work |
| Offset | The position number of a message inside a partition |
| Segment | One file-sized piece of a partition’s log |
| Active segment | The newest segment, still open for new writes |
| Rolled or closed segment | A segment that no longer accepts writes and never changes again |
| Replica | A copy of a partition kept on a broker |
| Leader and follower | The replica that handles all traffic, and the replicas that copy it |
| In-sync replica set | The replicas that are fully caught up with the leader |
| Leader epoch | A counter that increases each time a new leader is chosen |
| Retention | The rule that says how long or how much data to keep |
| Local tier | Data stored on the broker’s own disks |
| Remote tier | Data stored in an external system such as object storage |
| Log start offset | The first offset that still exists anywhere in either tier |
| Local log start offset | The first offset that still exists on the broker’s own disks |
| Last stable offset | The point below which all transactions are finished |
| RemoteLogManager | The broker component that coordinates everything about the remote tier |
| RemoteStorageManager | The plugin that stores and retrieves segment files |
| RemoteLogMetadataManager | The plugin that keeps the catalogue of remote segments |
| Object storage | A service that stores large files as named objects, such as Amazon S3 |
| Page cache | Memory the operating system uses to hold recently used file data |
| Throttle or quota | A limit on how fast data may be copied or read |
| Replay | Reading old messages again from an earlier offset |
28Frequently Asked Questions
29Summary and Key Takeaways
Key Takeaways
- One log, two homes. Recent segments stay on fast broker disks, older segments live in cheap object storage, and clients see a single continuous log.
- Four parts do the work. The local log, the RemoteLogManager, the storage plugin and the metadata plugin work together, with the leader doing all the uploading.
- Only closed, stable segments move. Local copies are deleted only after the upload is confirmed, which protects against data loss.
- Two clocks control retention. Total retention decides how long data exists at all, and local retention decides how long it stays on brokers.
- Operations get lighter. Because followers copy only the local window, broker replacement and scaling can shrink from a day to about an hour.
- The savings can be large, but so is the responsibility. Long retention gets far cheaper, while the bucket, the catalogue and the plugin become part of your critical path.
- Know the limits. Compacted topics are not supported, old data reads are slower to start, and settings such as segment size and local retention need real testing.