Skip to content

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

Kafka Partition Reassignment

Partition reassignment moves partition replicas between brokers to balance load, accommodate scaling, or replace failed hardware. This document covers the reassignment protocol, throttling mechanisms, and operational procedures.


ScenarioGoal
Broker additionDistribute load to new brokers
Broker removalEvacuate partitions before decommissioning
Load balancingEven distribution across brokers
Rack migrationMove partitions between racks
Storage balancingBalance disk usage across brokers
Partition reassignment request flow from admin client to brokersAdmin ClientControllerSource BrokerTarget BrokerAdmin ClientAdmin ClientControllerControllerSource BrokerSource BrokerTarget BrokerTarget BrokerAlterPartitionReassignments(reassignment plan)Validate planAdd target to replicasLeaderAndIsrRequest(add as follower)loop[Data copy]FetchRequestFetchResponse (data)Update ISRafter target catches upRemove sourcefrom replicasStopReplicaRequestReassignment complete

Replica set state transitions during a reassignmentReplica set state transitions during a reassignmentOriginalReplicas: [1,2,3]ReassigningReplicas: [1,2,3,4,5,6]Adding: [4,5,6]Removing: [1,2,3]FinalReplicas: [4,5,6]During reassignment:- All replicas exist- Target catches up- RF temporarily doubledStart reassignmentData copied,ISR converged
  1. Plan validation - Controller validates broker IDs and partition existence
  2. Add target replicas - New replicas added to replica set (non-ISR)
  3. Data replication - New replicas fetch from leader
  4. ISR join - New replicas join ISR when caught up
  5. Leader election - If leader changing, elect new leader
  6. Remove old replicas - Old replicas removed from replica set
  7. Delete data - Old brokers delete partition data
Replica set, ISR, and leader changes through a reassignmentReplica SetISRLeaderReplica SetReplica SetISRISRLeaderLeader[1,2,3][1,2,3]Broker 1Add Target Replicas[1,2,3,4,5,6][1,2,3]Broker 1Targets Catching Up[1,2,3,4,5,6][1,2,3,4]Broker 1All Targets in ISR[1,2,3,4,5,6][1,2,3,4,5,6]Broker 1Remove Old Replicas[4,5,6][4,5,6]Broker 4

Terminal window
# Create topics file
cat > topics-to-move.json << 'EOF'
{
"topics": [
{"topic": "orders"},
{"topic": "events"},
{"topic": "logs"}
],
"version": 1
}
EOF
# Generate plan for target brokers
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--topics-to-move-json-file topics-to-move.json \
--broker-list "1,2,3,4,5,6" \
--generate
# Output: Current and proposed assignment
{
"version": 1,
"partitions": [
{
"topic": "orders",
"partition": 0,
"replicas": [4, 5, 6],
"log_dirs": ["any", "any", "any"]
},
{
"topic": "orders",
"partition": 1,
"replicas": [5, 6, 4],
"log_dirs": ["any", "any", "any"]
},
{
"topic": "orders",
"partition": 2,
"replicas": [6, 4, 5],
"log_dirs": ["any", "any", "any"]
}
]
}
Terminal window
# Execute with throttling (recommended)
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--throttle 50000000 \
--execute
# Execute without throttling (fast but impacts cluster)
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--execute
Terminal window
# Check reassignment status
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--verify
# List ongoing reassignments
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--list
# Cancel reassignment
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--cancel

Leader and follower replication throttles during reassignmentLeader and follower replication throttles during reassignmentSource BrokerTarget BrokerLeader ReplicaThrottle:leader.replication.throttled.rateFollower ReplicaThrottle:follower.replication.throttled.rateThrottle applies to partitionslisted in throttled replicasReplication trafficLimit outboundLimit inbound
ConfigurationScopeDescription
leader.replication.throttled.rateBrokerMax bytes/sec for leader replicas
follower.replication.throttled.rateBrokerMax bytes/sec for follower replicas
leader.replication.throttled.replicasTopicPartitions with throttled leaders
follower.replication.throttled.replicasTopicPartitions with throttled followers
Terminal window
# Set throttle rate (50 MB/s)
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--throttle 50000000 \
--execute
# Increase throttle during reassignment
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--throttle 100000000 \
--execute
# Remove throttle (after completion)
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type brokers \
--entity-default \
--alter \
--delete-config leader.replication.throttled.rate,follower.replication.throttled.rate
kafka-configs.sh --bootstrap-server kafka:9092 \
--entity-type topics \
--entity-name orders \
--alter \
--delete-config leader.replication.throttled.replicas,follower.replication.throttled.replicas
time_estimate = total_data_to_move / throttle_rate
# Example:
# 500 GB to move at 50 MB/s = ~2.8 hours
# 500 GB to move at 100 MB/s = ~1.4 hours
Throttle RateUse Case
10-30 MB/sProduction with high sensitivity
50-100 MB/sNormal production
100-200 MB/sOff-peak hours
UnlimitedMaintenance window only

Throttle Removal

The --verify command automatically removes throttle settings when reassignment completes. If reassignment is cancelled, manually remove throttles using kafka-configs.sh.


AlterPartitionReassignmentsRequest =>
timeout_ms: INT32
topics: [Topic]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
replicas: [INT32] // null to cancel
ListPartitionReassignmentsRequest =>
timeout_ms: INT32
topics: [Topic]
ListPartitionReassignmentsResponse =>
topics: [Topic]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
replicas: [INT32] // Current replica set
adding_replicas: [INT32] // Being added
removing_replicas: [INT32] // Being removed

Intra-broker partition move between log directoriesIntra-broker partition move between log directoriesBroker 1/data1/data2/data3orders-0Intra-broker movementNo network trafficMove partitionto different disk
Terminal window
# Describe current log dirs
kafka-log-dirs.sh --bootstrap-server kafka:9092 \
--describe --topic-list orders
# Create log dir reassignment plan
cat > log-dir-reassignment.json << 'EOF'
{
"version": 1,
"partitions": [
{
"topic": "orders",
"partition": 0,
"replicas": [1, 2, 3],
"log_dirs": ["/data2", "any", "any"]
}
]
}
EOF
# Execute
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file log-dir-reassignment.json \
--execute

MetricDescriptionAlert
kafka.server:type=BrokerTopicMetrics,name=ReassignmentBytesInPerSecBytes/sec being copied-
kafka.server:type=BrokerTopicMetrics,name=ReassignmentBytesOutPerSecBytes/sec being sent-
kafka.server:UnderReplicatedPartitionsPartitions below RF> 0 extended
kafka.server:IsrShrinksPerSecISR shrink rateElevated during reassignment
kafka.server:IsrExpandsPerSecISR expand rateIndicates progress
Terminal window
# Watch reassignment progress
watch -n 10 'kafka-reassign-partitions.sh \
--bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--verify'
# Check under-replicated partitions
kafka-topics.sh --bootstrap-server kafka:9092 \
--describe --under-replicated-partitions
# Monitor replication lag
# Use broker metrics: ReassignmentBytesInPerSec/OutPerSec

FailureImpactRecovery
Source broker crashReassignment stallsWait for recovery or cancel
Target broker crashNew replica lostRestart broker, retry
Controller failoverContinues after electionAutomatic
Network partitionReassignment stallsResolve network, resume
Terminal window
# Cancel specific reassignment
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--cancel
# Verify cancellation
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--list
Terminal window
# Check current state
kafka-topics.sh --bootstrap-server kafka:9092 \
--describe --topic orders
# If stuck with extra replicas, cancel and restart
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--cancel
# Retry with fresh plan
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file reassignment.json \
--throttle 50000000 \
--execute

PracticeRationale
Assess data volumeCalculate reassignment duration
Schedule during low trafficMinimize production impact
Start with small topicsValidate process
Document original stateEnable rollback
PracticeRationale
Always use throttlingPrevent cluster saturation
Monitor continuouslyDetect issues early
Reassign incrementallyReduce blast radius
Keep original planRequired for verify/cancel
PracticeRationale
Verify completionEnsure all moves finished
Check partition balanceConfirm even distribution
Monitor cluster healthDetect delayed issues
Remove throttle configsClean up configuration

Terminal window
# 1. New broker joins (broker.id=4)
# 2. Generate balanced plan
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--topics-to-move-json-file all-topics.json \
--broker-list "1,2,3,4" \
--generate > add-broker-4.json
# 3. Execute with throttle
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file add-broker-4.json \
--throttle 100000000 \
--execute
Terminal window
# 1. Generate plan excluding broker 4
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--topics-to-move-json-file all-topics.json \
--broker-list "1,2,3" \
--generate > remove-broker-4.json
# 2. Execute
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file remove-broker-4.json \
--throttle 100000000 \
--execute
# 3. Wait for completion
kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \
--reassignment-json-file remove-broker-4.json \
--verify
# 4. Stop broker 4
kafka-server-stop.sh
Terminal window
# Create rack-aware reassignment
# Ensure replicas distributed across racks
cat > rack-balance.json << 'EOF'
{
"version": 1,
"partitions": [
{
"topic": "orders",
"partition": 0,
"replicas": [1, 3, 5]
}
]
}
EOF
# Broker 1 = rack-a, Broker 3 = rack-b, Broker 5 = rack-c