Skip to content

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

Kafka Cluster Scaling

This document covers the architecture and mechanisms for scaling Apache Kafka clusters. Kafka supports horizontal scaling through broker addition, partition expansion, and dynamic rebalancing.


Kafka scalability dimensions of storage, throughput, and consumer parallelismKafka scalability dimensions of storage, throughput, and consumer parallelismKafka ScalabilityStorage CapacityThroughputConsumer ParallelismAdd brokersAdd disksTiered storageAdd partitionsAdd brokersConsumer scalingAdd partitionsAdd consumersConsumer groups
DimensionScaling MechanismConsiderations
StorageAdd brokers, expand disksRequires partition reassignment
Produce throughputAdd partitionsMay affect ordering guarantees
Consume throughputAdd partitions + consumersMax consumers = partitions
Message rateAdd brokers + partitionsRebalancing overhead

Partition distribution before and after adding a brokerPartition distribution before and after adding a brokerBefore: 3 BrokersAfter: 4 BrokersBroker 1100 partitionsBroker 2100 partitionsBroker 3100 partitionsBroker 175 partitionsBroker 275 partitionsBroker 375 partitionsBroker 475 partitionsPartitions must beexplicitly reassignedto new brokerAdd broker +reassign partitions
OperationAutomaticData MovementImpact
Add brokerRequiredNone until reassignment
Remove brokerRequiredMust drain first
Add partitionsNoneImmediate after admin request
Add consumersNoneTriggers rebalance

Broker Addition

Adding a broker does not automatically rebalance partitions. Explicit partition reassignment is required to distribute load to the new broker.


Adding partitions to an existing topicAdminControllerBroker 1Broker 2Broker 3AdminAdminControllerControllerBroker 1Broker 1Broker 2Broker 2Broker 3Broker 3CreatePartitions(topic, 6)Increase from 3 to 6Compute assignmentsfor new partitionsCreate partition 3Create partition 4Create partition 5OKOKOKSuccessExisting partitions 0-2 unchangedNew partitions 3-5 start empty
ConstraintDescription
Increase onlyPartition count cannot be decreased
Key distributionAdding partitions changes key routing
Empty partitionsNew partitions start with no data
Consumer scalingMore partitions enable more consumers

Key Distribution Impact

Adding partitions changes the key-to-partition mapping. Messages with the same key may route to different partitions after expansion. This affects ordering guarantees for keyed messages.

optimal_partitions = max(
target_throughput / per_partition_throughput,
max_expected_consumers
)
FactorGuideline (Repository Guidance)
Per-partition throughput~10 MB/s typical
Consumer parallelism1 partition per consumer thread
Broker capacity~4000 partitions per broker (depending on hardware)
Cluster limitMonitor total partition count

Broker states from registration to activeBroker states from registration to activeNew BrokerRegisteredFencedUnfencedActiveBroker receives partitionassignments viaLeaderAndIsrRequestStart brokerBrokerRegistrationRequestRegistrationacceptedHeartbeatacceptedPartitionsassigned
  1. Deploy new broker - Configure with unique broker.id
  2. Start broker - Broker registers with controller
  3. Verify registration - Confirm broker appears in cluster
  4. Generate reassignment plan - Compute partition moves
  5. Execute reassignment - Move partitions with throttling
  6. Verify balance - Confirm even distribution
Terminal window
# Step 1: Start new broker (broker.id=4)
kafka-server-start.sh config/server.properties
# Step 2: Verify registration
kafka-broker-api-versions.sh --bootstrap-server kafka:9092
kafka-topics.sh --bootstrap-server kafka:9092 --describe | rg "Replicas:.*\\b4\\b"
# Step 3: Generate reassignment plan
cat > topics.json << 'EOF'
{"topics": [{"topic": "orders"}, {"topic": "events"}], "version": 1}
EOF
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--topics-to-move-json-file topics.json \
--broker-list "1,2,3,4" \
--generate > reassignment.json
# Step 4: Execute with throttle
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--throttle 50000000 \
--execute
# Step 5: Monitor progress
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--verify
Broker removal states from active to unregisteredBroker removal states from active to unregisteredActiveDrainingEmptyShutdownRemovedMust move ALL partitionsbefore stopping brokerInitiate removal(reassign partitions)All partitionsmovedStop brokerUnregister
Terminal window
# Step 1: Generate plan moving all partitions off broker 4
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--topics-to-move-json-file all-topics.json \
--broker-list "1,2,3" \
--generate > removal-plan.json
# Step 2: Execute reassignment
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file removal-plan.json \
--throttle 100000000 \
--execute
# Step 3: Wait for completion
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file removal-plan.json \
--verify
# Step 4: Verify no partitions on broker 4
kafka-topics.sh --bootstrap-server kafka:9092 --describe | rg "Replicas:.*\\b4\\b"
# Step 5: Stop broker
kafka-server-stop.sh

Data Loss Risk

Stopping a broker before completing partition reassignment results in data loss if the broker holds the only replica of any partition.


Capacity utilization thresholds for scaling decisionsCapacity utilization thresholds for scaling decisionsCapacity ThresholdsGreen Zone< 60%Yellow Zone60-80%Red Zone> 80%Trigger scaling planningat 60% utilizationExecute scalingbefore 80%MonitorPlan expansion
MetricThreshold (Repository Guidance)Action
Disk utilization> 70%Add brokers or storage
CPU utilization> 70% sustainedAdd brokers
Network throughput> 70% capacityAdd brokers
Partition count per broker> 4000Add brokers
Consumer lagIncreasingAdd partitions + consumers
Request latency (p99)> SLAScale horizontally
Decision tree for selecting a scaling strategyDecision tree for selecting a scaling strategyIdentify bottleneckyesStorage full?Single topic?yesnoReduce retentionAdd brokers +reassign partitionsyesCPU saturated?Add brokers +reassign partitionsyesConsumer lag growing?Consumers < Partitions?yesnoAdd consumersAdd partitions(impacts key ordering)yesProducer throughput limited?Add partitions +brokers

Rack-aware replica placement across three racksRack-aware replica placement across three racksRack ARack BRack CTopic: orders (RF=3)Broker 1Broker 4Broker 2Broker 5Broker 3Broker 6P0: 1, 2, 3P1: 2, 3, 1P2: 3, 1, 2Each partition has replicasin different racks
# Broker configuration
broker.rack=rack-a
# Topic creation with rack awareness
kafka-topics.sh --bootstrap-server kafka:9092 \
--create \
--topic orders \
--partitions 6 \
--replication-factor 3
# Automatically distributes across racks
ConsiderationRecommendation
New broker placementAdd to least-populated rack
Minimum racksRF racks for full fault tolerance
Balanced racksEqual brokers per rack
ReassignmentMaintain rack diversity

AspectChallenge
Partition reassignmentRequires data movement
Consumer rebalancingTemporary pause
State migrationKafka Streams applications
Connection overheadClient reconnection
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: kafka-cluster
spec:
kafka:
replicas: 3 # Scale by changing this
storage:
type: persistent-claim
size: 100Gi
config:
auto.create.topics.enable: false
default.replication.factor: 3
min.insync.replicas: 2

Kubernetes Scaling

Kubernetes-based Kafka operators (Strimzi, Confluent) automate broker addition but typically require manual partition reassignment for optimal balance.


CheckPurpose
Current partition distributionIdentify imbalance
Under-replicated partitionsEnsure cluster healthy
Active reassignmentsWait for completion
Consumer lagNote current state
Disk space on all brokersEnsure room for data movement
PracticeRationale
Use throttlingPrevent saturation during reassignment
Scale incrementallyAdd one broker at a time
Monitor continuouslyDetect issues early
Test rollbackEnsure recovery path exists
Terminal window
# Verify partition balance
kafka-topics.sh --bootstrap-server kafka:9092 --describe | \
awk '/Leader:/ {leaders[$NF]++} END {for (b in leaders) print b": "leaders[b]}'
# Verify no under-replicated partitions
kafka-topics.sh --bootstrap-server kafka:9092 \
--describe --under-replicated-partitions
# Verify consumer group health
kafka-consumer-groups.sh --bootstrap-server kafka:9092 \
--describe --all-groups