Skip to content

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

Kafka Broker Configuration

Broker configuration controls the behavior of Kafka broker nodes. Configuration is defined in server.properties and through dynamic configuration updates.


CategoryDescriptionDynamic
Node IdentityBroker and controller identifiers
ListenersNetwork endpoints and protocols
StorageLog directories and retentionPartial
ReplicationReplica fetching and ISR managementPartial
NetworkThreading and buffer sizes
SecurityTLS, SASL, and authorization

# Unique node identifier (required)
node.id=1
# Node roles: broker, controller, or both
process.roles=broker,controller
# Controller quorum voters (id@host:port)
controller.quorum.voters=1@controller1:9093,2@controller2:9093,3@controller3:9093
# Controller listener name
controller.listener.names=CONTROLLER
SettingDescriptionRequired
node.idUnique identifier for this node
process.rolesComma-separated roles: broker, controller, or both
controller.quorum.votersList of controller voters
controller.listener.namesListener name for controller communication
# Broker ID (must be unique in cluster)
broker.id=1
# ZooKeeper connection
zookeeper.connect=zk1:2181,zk2:2181,zk3:2181/kafka
zookeeper.connection.timeout.ms=18000
zookeeper.session.timeout.ms=18000

ZooKeeper Deprecation

ZooKeeper mode is deprecated as of Kafka 3.5 and will be removed in Kafka 4.0. New deployments should use KRaft mode.


Listeners define network endpoints where brokers accept client connections.

# Define listeners (protocol://host:port)
listeners=PLAINTEXT://0.0.0.0:9092,SSL://0.0.0.0:9093,SASL_SSL://0.0.0.0:9094
# Advertised listeners (what clients see)
advertised.listeners=PLAINTEXT://broker1.example.com:9092,SSL://broker1.example.com:9093
# Map listener names to security protocols
listener.security.protocol.map=PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_SSL:SASL_SSL,CONTROLLER:PLAINTEXT
# Inter-broker communication listener
inter.broker.listener.name=PLAINTEXT
# Controller listener (KRaft only)
controller.listener.names=CONTROLLER
ProtocolEncryptionAuthenticationUse Case
PLAINTEXTDevelopment, internal networks
SSLOptional (mTLS)Encrypted communication
SASL_PLAINTEXTAuthentication without encryption
SASL_SSLProduction recommended
# Separate internal and external listeners
listeners=INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9093
# Different advertised addresses per listener
advertised.listeners=INTERNAL://broker1.internal:9092,EXTERNAL://broker1.public.example.com:9093
# Security protocol mapping
listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:SASL_SSL
# Use internal listener for inter-broker communication
inter.broker.listener.name=INTERNAL

# Log directory (single)
log.dir=/var/kafka-logs
# Multiple log directories (comma-separated)
log.dirs=/data1/kafka-logs,/data2/kafka-logs,/data3/kafka-logs

Multiple Log Directories

Using multiple log directories across different disks improves I/O throughput. Kafka distributes partitions across directories.

# Segment file size (default: 1GB)
log.segment.bytes=1073741824
# Time before segment is rolled (default: 7 days)
log.roll.hours=168
log.roll.ms=604800000
# Index file size
log.index.size.max.bytes=10485760
# Index interval (bytes between index entries)
log.index.interval.bytes=4096
# Time-based retention (default: 7 days)
log.retention.hours=168
log.retention.minutes=10080
log.retention.ms=604800000
# Size-based retention per partition (default: unlimited)
log.retention.bytes=-1
# Check interval for retention policy
log.retention.check.interval.ms=300000
# Delete or compact
log.cleanup.policy=delete
SettingDefaultDynamicDescription
log.retention.ms604800000Retention time in ms
log.retention.bytes-1Max bytes per partition
log.segment.bytes1073741824Segment file size
log.cleanup.policydeletedelete or compact
# Enable compaction for specific topics via topic config
# Broker-level compaction settings:
# Compaction threads
log.cleaner.threads=1
# Compaction buffer size
log.cleaner.dedupe.buffer.size=134217728
# I/O buffer size per cleaner thread
log.cleaner.io.buffer.size=524288
# I/O throughput limit (bytes/sec, -1 = unlimited)
log.cleaner.io.max.bytes.per.second=-1
# Minimum ratio of dirty log to total log to trigger compaction
log.cleaner.min.cleanable.ratio=0.5
# Minimum time message remains uncompacted
log.cleaner.min.compaction.lag.ms=0
# Maximum time message remains uncompacted
log.cleaner.max.compaction.lag.ms=9223372036854775807
# Delete retention for tombstones
log.cleaner.delete.retention.ms=86400000

# Default replication factor for auto-created topics
default.replication.factor=3
# Minimum ISR for writes when acks=all
min.insync.replicas=2
# Replica fetcher threads
num.replica.fetchers=1
# Replica fetch settings
replica.fetch.max.bytes=1048576
replica.fetch.min.bytes=1
replica.fetch.wait.max.ms=500
# Replica lag
replica.lag.time.max.ms=30000
# Allow unclean leader election
unclean.leader.election.enable=false
SettingDefaultRecommendedDescription
default.replication.factor13RF for auto-created topics
min.insync.replicas12Minimum ISR for acks=all
unclean.leader.election.enablefalsefalseAllow out-of-sync replica as leader
replica.lag.time.max.ms3000030000Max lag before removing from ISR

Unclean Leader Election

Setting unclean.leader.election.enable=true may result in data loss. An out-of-sync replica becoming leader means committed messages on the previous leader may be lost.


# Network threads (handle connections)
num.network.threads=3
# I/O threads (handle requests)
num.io.threads=8
# Background threads
background.threads=10
# Request handler threads
num.recovery.threads.per.data.dir=1

Sizing Guidelines:

SettingFormulaNotes
num.network.threads2-3 per listenerHandles connection I/O
num.io.threads2x CPU coresHandles request processing
num.recovery.threads.per.data.dir1-2 per diskParallel log recovery on startup
# Socket buffers
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
# Maximum request size
socket.request.max.bytes=104857600
# Request queue
queued.max.requests=500
# Request timeout
request.timeout.ms=30000
# Maximum time request can wait in queue
queued.max.request.bytes=104857600
# Connections per IP
max.connections.per.ip=100
max.connections.per.ip.overrides=10.0.0.1:200

These settings apply to topics when not overridden at the topic level.

# Default partition count
num.partitions=3
# Auto-create topics
auto.create.topics.enable=false
# Delete topics
delete.topic.enable=true
# Compression
compression.type=producer
# Maximum message size
message.max.bytes=1048588
# Replication settings
default.replication.factor=3
min.insync.replicas=2

Auto-Create Topics

In production, auto.create.topics.enable should be false. Auto-created topics use default settings and bypass governance controls.


Certain broker settings can be modified without restart.

When a config is defined at multiple levels, precedence order:

  1. Dynamic per-broker config stored in metadata log
  2. Dynamic cluster-wide default config stored in metadata log
  3. Static broker config from server.properties
  4. Kafka default value
ModeDescriptionScope
read-onlyRequires broker restartStatic only
per-brokerUpdated dynamically per brokerIndividual broker
cluster-wideUpdated as cluster-wide defaultAll brokers
Terminal window
# Per-broker configuration
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type brokers \
--entity-name 1 \
--alter \
--add-config num.io.threads=16
# Cluster-wide default
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type brokers \
--entity-default \
--alter \
--add-config log.retention.ms=86400000
# View configuration
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type brokers \
--entity-name 1 \
--describe
# Delete dynamic config (revert to static/default)
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type brokers \
--entity-name 1 \
--alter \
--delete-config num.io.threads
# Update log level dynamically
kafka-configs.sh --bootstrap-server kafka:9092 \
--broker-logger 1 \
--alter \
--add-config org.apache.kafka.server.quota=DEBUG

Thread pool sizes can only be updated within a restricted range to ensure graceful handling:

  • Minimum: currentSize / 2
  • Maximum: currentSize × 2

This applies to: num.network.threads, num.io.threads, num.replica.fetchers, num.recovery.threads.per.data.dir, log.cleaner.threads, background.threads

SettingScopeDescription
log.cleaner.threadsBrokerCompaction threads
log.cleaner.io.buffer.sizeBrokerCleaner buffer
log.cleaner.io.max.bytes.per.secondBrokerCleaner I/O limit
log.retention.msBroker/ClusterRetention time
log.retention.bytesBroker/ClusterRetention size
message.max.bytesBroker/ClusterMax message size
num.io.threadsBrokerI/O thread count
num.network.threadsBrokerNetwork thread count
num.replica.fetchersBrokerReplica fetcher count
ssl.keystore.locationBrokerSSL keystore path
ssl.keystore.passwordBrokerSSL keystore password

SSL keystores can be updated without restart for certificate rotation:

Terminal window
# Update keystore for specific listener
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type brokers \
--entity-name 1 \
--alter \
--add-config 'listener.name.sasl_ssl.ssl.keystore.location=/path/to/new.keystore.jks,listener.name.sasl_ssl.ssl.keystore.password=newpassword'

Requirements:

  • New certificate must be signed by the same CA as the old certificate
  • For inter-broker listener, new keystore must be trusted by existing truststore
  • Config name must be prefixed with listener.name.{listenerName}.

Listeners can be added or removed without restart:

Terminal window
# Add new listener
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type brokers \
--entity-name 1 \
--alter \
--add-config 'listeners=PLAINTEXT://0.0.0.0:9092,EXTERNAL://0.0.0.0:9094,advertised.listeners=PLAINTEXT://broker1:9092,EXTERNAL://external.example.com:9094'

Inter-Broker Listener

The inter-broker listener cannot be changed dynamically. Changing inter.broker.listener.name requires a rolling restart.


Terminal window
# jvm.options or KAFKA_HEAP_OPTS
# Heap size (typically 6-8GB max)
-Xms6g
-Xmx6g
# GC settings (G1GC recommended)
-XX:+UseG1GC
-XX:MaxGCPauseMillis=20
-XX:InitiatingHeapOccupancyPercent=35
# GC logging
-Xlog:gc*:file=/var/log/kafka/gc.log:time,level,tags:filecount=10,filesize=100M
Terminal window
# File descriptors (per process)
ulimit -n 100000
# sysctl settings
vm.swappiness=1
vm.dirty_background_ratio=5
vm.dirty_ratio=60
net.core.wmem_default=131072
net.core.rmem_default=131072
net.ipv4.tcp_wmem=4096 65536 2048000
net.ipv4.tcp_rmem=4096 65536 2048000

CategorySettingRecommended Value
Reliabilitymin.insync.replicas2 (with RF=3)
unclean.leader.election.enablefalse
default.replication.factor3
Securityauto.create.topics.enablefalse
allow.everyone.if.no.acl.foundfalse
Performancenum.io.threads2× CPU cores
num.network.threads2-3 per listener
Monitoringmetric.reportersJMX or Prometheus