Skip to content

Instantly share code, notes, and snippets.

@zmstone
Last active December 11, 2019 14:08
Show Gist options
  • Save zmstone/686504d57addbdb8e0a9c7a3c4b78422 to your computer and use it in GitHub Desktop.
Save zmstone/686504d57addbdb8e0a9c7a3c4b78422 to your computer and use it in GitHub Desktop.
Help script to demote kafka leader node
#!/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