Last active
December 11, 2019 14:08
-
-
Save zmstone/686504d57addbdb8e0a9c7a3c4b78422 to your computer and use it in GitHub Desktop.
Help script to demote kafka leader node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -e | |
# Demoting leader is a necessary step before moving replicas off that node otherwise follower fetchers may crash due to a kafka bug. | |
# This script makes use of replica-reassign.sh script to demote a node from preferred leader in the given topic-partition's replicas list | |
# It then forces a preferred leader election for this topic-partition. | |
usage() { | |
echo "Usage: $0 -t <topic-name> -p <partition-number> -n <node-id> [-z <zookeeper-host>]" | |
echo "For example, if topic 'foo' partition 0 has replicas list [0,1,2]" | |
echo "Running command '$0 -t foo -p 0 -n 0' will change the order to [1,2,0]" | |
echo "Then kafka-preferred-replica-election.sh should force kafka to re-elect the preferred node as leader" | |
exit "$1" | |
} | |
while [[ $# -gt 0 ]]; do | |
opt="$1" | |
case $opt in | |
-t|--topic) | |
TOPIC="$2" | |
shift 2 | |
;; | |
-p|--partition) | |
PARTITION="$2" | |
shift 2 | |
;; | |
-n|--node) | |
NODE_TO_DEMOTE="$2" | |
shift 2 | |
;; | |
-z|--zookeeper) | |
ZOOKEEPER="$2" | |
shift 2 | |
;; | |
-h|--help) | |
usage 0 | |
;; | |
*) | |
echo "Unknown option $opt" | |
exit 1 | |
;; | |
esac | |
done | |
[ -z "$TOPIC" ] && echo "-t|--topic is missing" && usage 1 | |
[ -z "$PARTITION" ] && echo "-p|--partition is missing" && usage 1 | |
[ -z "$NODE_TO_DEMOTE" ] && echo "-n|--node is missing" && usage 1 | |
[ -z "$ZOOKEEPER" ] && echo "ZOOKEEPER is not defined and -z|--zookeeper is missing" && usage 1 | |
THIS_DIR="$(cd "$(dirname "$0")" && pwd)" | |
REASSIGN="$THIS_DIR/replica-reassign.sh" | |
DESCRIBE="$THIS_DIR/kafka-topics.sh" | |
ELECT_PREFERRED_LEADER="$THIS_DIR/kafka-preferred-replica-election.sh" | |
if [ ! -f "$REASSIGN" ]; then echo "Can not find $REASSIGN"; exit 1; fi | |
if [ ! -f "$DESCRIBE" ]; then echo "Can not find $DESCRIBE"; exit 1; fi | |
if [ ! -f "$ELECT_PREFERRED_LEADER" ]; then echo "Can not find $ELECT_PREFERRED_LEADER"; exit 1; fi | |
describe_line="" | |
replicas_csv="" | |
current_leader_node="" | |
describe() { | |
describe_line="$($DESCRIBE --zookeeper "$ZOOKEEPER" --topic "$TOPIC" --describe | grep -E "Partition:\s$PARTITION\s")" | |
replicas_csv="$(echo "$describe_line" | sed -e 's#^.*Replicas:\(.*\)Isr.*#\1#' | tr -d ' \t')" | |
current_leader_node="$(echo "$describe_line" | sed -e 's#^.*Leader:\(.*\)Replicas.*#\1#' | tr -d ' \t')" | |
} | |
describe | |
IFS=',' read -r -a replicas_array <<< "$replicas_csv" | |
replicas_count="${#replicas_array[@]}" | |
if [ ! "$replicas_count" -gt 1 ]; then | |
echo "Not enough replicas" | |
echo "$describe_line" | |
exit 1 | |
fi | |
found="no" | |
for node in "${replicas_array[@]}"; do | |
if [ "$node" -eq "$NODE_TO_DEMOTE" ]; then | |
found="yes" | |
break | |
fi | |
done | |
if [ "no" = "$found" ]; then | |
echo "Node $NODE_TO_DEMOTE is not in replicas list for $TOPIC-$PARTITION: $replicas_csv. Skipped demoting!" | |
exit 0 | |
fi | |
# first element in the array is the preferred leader | |
current_preferred_leader="${replicas_array[0]}" | |
if [ "$current_preferred_leader" != "$NODE_TO_DEMOTE" ]; then | |
echo "Node $NODE_TO_DEMOTE is not preferred leader for $TOPIC-$PARTITION: $replicas_csv. Skipped replica reordering!" | |
else | |
# reorder replicas list | |
# only reordering, no need for --throttle and --reoder-replicas | |
reordered_replicas_csv="" | |
for i in $(seq 1 $((replicas_count - 1))); do | |
reordered_replicas_csv+="${replicas_array[$i]}," | |
done | |
reordered_replicas_csv+="$current_preferred_leader" | |
$REASSIGN --zookeeper "$ZOOKEEPER" --topic "$TOPIC" --partition "$PARTITION" --replicas "$reordered_replicas_csv" | |
fi | |
if [ "$current_leader_node" != "$NODE_TO_DEMOTE" ]; then | |
exit 0 | |
fi | |
echo "Forcing preferred leader election for $TOPIC-$PARTITION" | |
JSON="/tmp/$TOPIC-$PARTITION-elect-preferred-leader.json" | |
cat <<EOF > "$JSON" | |
{"partitions":[{"topic": "$TOPIC","partition": $PARTITION}]} | |
EOF | |
$ELECT_PREFERRED_LEADER --zookeeper "$ZOOKEEPER" --path-to-json-file "$JSON" | |
sleep 2 | |
# now check status | |
describe | |
if [ "$current_leader_node" = "$NODE_TO_DEMOTE" ]; then | |
echo "Failed to demote leader node $NODE_TO_DEMOTE for $TOPIC-$PARTITION" | |
exit 1 | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment