Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka Tiered Storage Configuration

Tiered storage (KIP-405) enables Kafka to offload log segments to remote storage systems, enabling cost-effective long-term retention while maintaining local storage for recent data.

Version Requirement

Tiered storage is an early access feature in Apache Kafka 3.6+. Production readiness varies by release.


Kafka BrokerLocal Storage(Hot Data)Remote Storage(Cold Data)Remote Storage ManagerActive SegmentRecent SegmentsOld SegmentsArchived Segmentslocal.retention.mslocal.retention.bytesretention.msretention.bytessegment rollafter local.retentionuploadfetch on read
TierStorageRetentionAccess Pattern
Local (Hot)Broker disklocal.retention.msFrequent reads
Remote (Cold)Object storageretention.msInfrequent reads

server.properties
# Enable tiered storage
remote.log.storage.system.enable=true
# Remote storage manager plugin (implementation-specific)
remote.log.storage.manager.class.name=com.example.kafka.remote.RemoteStorageManager
remote.log.storage.manager.class.path=/opt/kafka/plugins/tiered-storage
# Remote log metadata manager
remote.log.metadata.manager.class.name=org.apache.kafka.server.log.remote.metadata.storage.TopicBasedRemoteLogMetadataManager
# Metadata topic configuration
remote.log.metadata.topic.num.partitions=50
remote.log.metadata.topic.replication.factor=3
# Reader and copier threads
remote.log.reader.threads=10
remote.log.copier.threads=10
Terminal window
# Enable tiered storage for topic
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type topics \
--entity-name events \
--alter \
--add-config remote.storage.enable=true
# Configure local retention (hot tier)
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type topics \
--entity-name events \
--alter \
--add-config local.retention.ms=86400000 # 1 day local
# Configure total retention (including remote)
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type topics \
--entity-name events \
--alter \
--add-config retention.ms=2592000000 # 30 days total

Plugin required

Apache Kafka does not ship an object store implementation. You must install a remote storage manager plugin and use its class name and config keys.

# S3 Remote Storage Manager configuration
remote.log.storage.manager.class.name=io.confluent.kafka.tiered.storage.s3.S3RemoteStorageManager
# S3 bucket
remote.log.storage.s3.bucket.name=my-kafka-tiered-storage
remote.log.storage.s3.region=us-east-1
# Authentication (use IAM roles when possible)
remote.log.storage.s3.credentials.provider.class=com.amazonaws.auth.DefaultAWSCredentialsProviderChain
# Or explicit credentials (not recommended)
# remote.log.storage.s3.access.key=AKIAXXXXXXXX
# remote.log.storage.s3.secret.key=XXXXXXXX
# S3 settings
remote.log.storage.s3.endpoint.override= # For S3-compatible storage
remote.log.storage.s3.path.style.access.enabled=false

Google Cloud Storage (Vendor Plugin Example)

Section titled “Google Cloud Storage (Vendor Plugin Example)”
# GCS Remote Storage Manager configuration
remote.log.storage.manager.class.name=io.confluent.kafka.tiered.storage.gcs.GCSRemoteStorageManager
# GCS bucket
remote.log.storage.gcs.bucket.name=my-kafka-tiered-storage
remote.log.storage.gcs.project.id=my-project
# Authentication
remote.log.storage.gcs.credentials.path=/etc/kafka/gcs-credentials.json

Azure Blob Storage (Vendor Plugin Example)

Section titled “Azure Blob Storage (Vendor Plugin Example)”
# Azure Blob Remote Storage Manager configuration
remote.log.storage.manager.class.name=io.confluent.kafka.tiered.storage.azure.AzureBlobRemoteStorageManager
# Azure container
remote.log.storage.azure.container.name=kafka-tiered-storage
remote.log.storage.azure.account.name=mystorageaccount
# Authentication
remote.log.storage.azure.account.key=XXXXX
# Or use managed identity
remote.log.storage.azure.use.managed.identity=true

SettingDescription
remote.storage.enableEnable tiered storage for topic
local.retention.msTime to retain locally before tiering
local.retention.bytesSize to retain locally per partition
retention.msTotal retention (local + remote)
retention.bytesTotal size retention per partition

High-Volume Event Stream:

Terminal window
# 6 hours local, 90 days total
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type topics \
--entity-name events \
--alter \
--add-config remote.storage.enable=true,\
local.retention.ms=21600000,\
retention.ms=7776000000

Audit Log (Long Retention):

Terminal window
# 1 day local, 7 years total
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type topics \
--entity-name audit-log \
--alter \
--add-config remote.storage.enable=true,\
local.retention.ms=86400000,\
retention.ms=220752000000

Size-Based Tiering:

Terminal window
# 10GB local, 1TB total per partition
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type topics \
--entity-name large-events \
--alter \
--add-config remote.storage.enable=true,\
local.retention.bytes=10737418240,\
retention.bytes=1099511627776

Tiered storage maintains metadata about remote segments in an internal Kafka topic.

# Metadata topic settings
remote.log.metadata.topic.num.partitions=50
remote.log.metadata.topic.replication.factor=3
remote.log.metadata.topic.retention.ms=-1
# Metadata manager settings
remote.log.metadata.manager.listener.name=INTERNAL
remote.log.metadata.custom.metadata.max.bytes=1024
# Metadata initialization timeout
remote.log.metadata.manager.impl.prefix=rlmm.config.
rlmm.config.remote.log.metadata.topic.replication.factor=3
# Metadata consumption settings
remote.log.metadata.consume.wait.ms=120000

# Segment upload threads (per broker)
remote.log.copier.threads=10
# Segment download threads (for consumer reads)
remote.log.reader.threads=10
# Expiration threads (deleting expired remote segments)
remote.log.manager.expiration.threads=10
# Task queue size
remote.log.manager.task.queue.max.size=100
# Retry settings
remote.log.manager.task.retry.backoff.ms=100
remote.log.manager.task.retry.max.attempts=5
# Minimum segment age before upload
remote.log.copy.segment.age.threshold.ms=30000
# Interval between upload checks
remote.log.manager.copier.task.interval.ms=30000
# Upload batch size
remote.log.segment.copy.max.batch.size=100
# Prefetch for remote reads
remote.log.reader.fetch.max.bytes=52428800
# Cache for remote segments (optional, implementation-specific)
remote.log.storage.cache.size.bytes=1073741824
remote.log.storage.cache.dir=/var/kafka/remote-cache

MetricDescription
RemoteLogManager.RemoteCopyLagBytesBytes pending upload
RemoteLogManager.RemoteCopyLagSegmentsSegments pending upload
RemoteLogManager.RemoteReadRequestsPerSecRemote read rate
RemoteLogManager.RemoteReadBytesPerSecRemote read throughput
RemoteLogManager.RemoteCopyBytesPerSecUpload throughput
RemoteLogManager.RemoteDeleteLagBytesBytes pending deletion
kafka.log.remote:type=RemoteLogManager,name=*
kafka.log.remote:type=RemoteStorageManager,name=*
kafka.log.remote:type=RemoteLogMetadataManager,name=*
MetricWarningCritical
RemoteCopyLagBytes> 1GB> 10GB
RemoteCopyLagSegments> 10> 100
RemoteReadRequestsPerSecBaseline +50%Baseline +100%

Storage TypeCost FactorAccess Cost
Local SSDHigh $/GBNone
S3 StandardLow $/GBPer request
S3 Infrequent AccessLower $/GBHigher per request
S3 GlacierLowest $/GBHigh + retrieval time
  1. Enable on new topics first - Test with non-critical workloads
  2. Gradual rollout - Enable per topic, monitor impact
  3. Adjust local retention - Start conservative, reduce gradually
  4. Monitor consumer latency - Remote reads add latency
LimitationDescription
Compacted topicsNot supported with tiered storage
Consumer lagRemote reads increase fetch latency
TransactionsTransactional data must complete before tiering
Partition reassignmentRemote segments must be considered

IssueCauseSolution
High copy lagSlow uploadsIncrease copier threads
Failed uploadsNetwork/permission issuesCheck remote storage connectivity
Slow remote readsHigh consumer lagAdd read threads, consider caching
Metadata issuesMetadata topic problemsCheck replication, monitor topic
Terminal window
# Check remote log manager status
kafka-log-dirs.sh --bootstrap-server kafka:9092 \
--describe \
--topic-list events
# List remote segments (implementation-specific)
# Check remote storage directly for segment inventory
Terminal window
# Check for tiered storage errors
grep -i "remote" /var/log/kafka/server.log | grep -i "error"
# Check upload progress
grep -i "RemoteLogManager" /var/log/kafka/server.log