Kafka Broker ve ZooKeeper Arıza Yönetimi: Failover Senaryoları ve Kurtarma Prosedürleri

Prodüksiyonda Kafka cluster’ınız aniden çöktüğünde sakin kalabilmek, önceden hazırlanmış prosedürlere sahip olmakla doğrudan ilişkilidir. Yıllar içinde onlarca Kafka arızasıyla boğuşurken öğrendim ki, panik değil prosedür kurtarır. Bu yazıda gerçek dünya senaryolarından yola çıkarak Kafka broker ve ZooKeeper arızalarını nasıl yöneteceğinizi, failover mekanizmalarını ve adım adım kurtarma prosedürlerini ele alacağım.

Kafka Failover Mekanizmasını Anlamak

Kafka’nın dayanıklılığı, partition replikasyon mimarisine dayanır. Her partition’ın bir leader ve bir ya da birden fazla follower‘ı vardır. Leader tüm okuma/yazma işlemlerini üstlenirken, follower’lar sürekli leader’ı takip eder. Bir broker düştüğünde, o broker üzerindeki leader partition’lar için yeni bir leader seçimi başlar. İşte bu süreç, failover’ın temelidir.

ZooKeeper ise (ya da KRaft modunda metadata log) broker koordinasyonunu, leader seçimini ve cluster metadata’sını yönetir. ZooKeeper olmadan geleneksel Kafka cluster’ı ayağa kalkamaz. Bu iki katmanın arızalarını ayrı ayrı ele almak gerekir.

ISR (In-Sync Replicas) listesi burada kritik öneme sahiptir. Sadece ISR listesindeki replikalar leader olabilir. Bir replica, leader’dan çok geride kaldığında ISR’dan düşer ve leader seçimine katılamaz. Bu davranışı anlamak, veri kaybı riskini minimize etmek açısından hayatidir.

Arıza Tespiti: Neler Oluyor?

Herhangi bir kurtarma prosedürüne girmeden önce ne tür bir arıza yaşadığınızı anlamanız şart. Aşağıdaki komutlarla hızlı durum tespiti yapabilirsiniz.

# Cluster genelinde broker durumunu kontrol et
kafka-broker-api-versions.sh --bootstrap-server kafka1:9092,kafka2:9092,kafka3:9092

# Tüm topic'lerdeki under-replicated partition'ları listele
kafka-topics.sh --bootstrap-server kafka1:9092 
  --describe 
  --under-replicated-partitions

# Leader olmayan partition'ları bul
kafka-topics.sh --bootstrap-server kafka1:9092 
  --describe 
  --unavailable-partitions

# ZooKeeper bağlantı durumu
echo "stat" | nc zookeeper1 2181 | grep -E "Mode|Connections|Latency"

Bu komutların çıktılarını yorumlamayı bilin. Under-replicated partitions sayısı aniden yükseldiyse, bir broker ISR’dan düşüyor demektir. Unavailable partitions görüyorsanız, artık producer ve consumer’lar etkileniyor.

# ZooKeeper ensemble sağlık kontrolü
for host in zk1 zk2 zk3; do
  echo "=== $host ==="
  echo "ruok" | nc $host 2181
  echo "mntr" | nc $host 2181 | grep -E "zk_state|zk_followers|zk_avg_latency"
done

ZooKeeper’da imok yerine bağlantı hatası alıyorsanız, o node sorunlu demektir. Follower sayısı beklenenden azsa ensemble çoğunluğunu kaybetme riskiyle karşı karşıyasınız demektir.

Senaryo 1: Tek Broker Arızası

En yaygın ve görece en kolay yönetilen senaryodur. Üç broker’lı bir cluster’da tek broker düştüğünde, Kafka otomatik olarak leader seçimini gerçekleştirir. Ancak bu otomatik süreç bazen beklediğiniz kadar hızlı olmayabilir.

# Hangi broker'ın down olduğunu tespit et
kafka-topics.sh --bootstrap-server kafka1:9092 
  --describe 
  --under-replicated-partitions | 
  awk '{print $4}' | sort -u

# Controller broker'ı bul (cluster koordinasyonunu kim yapıyor)
kafka-metadata-quorum.sh --bootstrap-server kafka1:9092 describe
# Eski yöntem (ZooKeeper tabanlı)
zookeeper-shell.sh zk1:2181 get /controller

Broker tekrar ayağa kalktığında, önce ISR’a geri dönmesi beklenir. Bu süre, replica.lag.time.max.ms parametresine ve mevcut veri miktarına göre değişir. Eğer broker uzun süre kapalı kaldıysa, follower’ların leader’ı yakalaması zaman alacaktır.

# Broker yeniden başlatıldıktan sonra ISR durumunu takip et
watch -n 5 "kafka-topics.sh --bootstrap-server kafka1:9092 
  --describe 
  --under-replicated-partitions | wc -l"

# Preferred replica election başlat (partition'ları tercihli broker'lara geri taşı)
kafka-leader-election.sh --bootstrap-server kafka1:9092 
  --election-type PREFERRED 
  --all-topic-partitions

Preferred replica election önemlidir. Kafka, partition leader’larını başlangıçta dengeli dağıtır. Bir broker kısa süre kapalı kalıp geri döndüğünde, leader’lık diğer broker’larda kalmaya devam edebilir. Bu seçimi çalıştırarak dengeyi yeniden sağlarsınız.

Senaryo 2: Çoklu Broker Arızası ve Veri Kaybı Riski

İki veya daha fazla broker aynı anda düştüğünde, özellikle replication factor 3 olan bir cluster’da, ISR listesi kritik boyuta düşebilir. Bu noktada unclean.leader.election.enable parametresi devreye girer.

Bu parametre varsayılan olarak false durumundadır ve bu doğru bir tercihtir. true yaparsanız, ISR dışındaki bir replica leader seçilebilir ve bu veri kaybına yol açar. Prodüksiyonda bu tradeoff’u bilinçli yapmalısınız.

# Hangi topic'lerde unclean election riski var?
kafka-topics.sh --bootstrap-server kafka1:9092 
  --describe | 
  grep "Isr:" | 
  awk -F'Isr:' '{print $2}' | 
  tr ',' 'n' | 
  sort | 
  uniq -c | 
  sort -rn

# Kritik durum: Bazı partition'lar için unclean election'a izin ver
# (son çare olarak kullanın!)
kafka-configs.sh --bootstrap-server kafka1:9092 
  --entity-type topics 
  --entity-name kritik-topic 
  --alter 
  --add-config unclean.leader.election.enable=true

Gerçek dünya hikayesi: Bir e-ticaret platformunda iki broker aynı rack’te bulunuyordu ve güç arızası nedeniyle ikisi birden düştü. Replication factor 3 olmasına rağmen, üçüncü broker’daki replica geride kalmıştı ve ISR dışındaydı. Bu durumda ya veri kaybını kabul ederek unclean election’a izin verdik, ya da servis kesintisini uzatarak diğer broker’ların recovery’sini bekledik. İkinci seçeneği tercih ettik ve doğru karar oldu.

Senaryo 3: ZooKeeper Ensemble Arızası

ZooKeeper’ın çoğunluğu kaybetmesi, tüm Kafka cluster’ını durdurur. Üç node’lu bir ensemble’da iki node düştüğünde sistem çalışmaz hale gelir. Beş node’lu ensemble’da ise üç node düşmesi aynı sonucu verir.

# ZooKeeper leader'ı bul
for host in zk1 zk2 zk3; do
  mode=$(echo "stat" | nc $host 2181 | grep Mode)
  echo "$host: $mode"
done

# ZooKeeper node'larının sağlık durumunu detaylı incele
echo "mntr" | nc zk1 2181 | grep -E 
  "zk_num_alive_connections|zk_outstanding_requests|zk_avg_latency|zk_max_latency"

# ZooKeeper veri dizinini kontrol et
ls -lh /var/lib/zookeeper/data/
ls -lh /var/lib/zookeeper/data/version-2/

ZooKeeper arızasında dikkat etmeniz gereken kritik nokta: Kafka broker’ları ZooKeeper bağlantısını kaybedince zookeeper.session.timeout.ms süresi dolana kadar bekler. Bu süre içinde ZooKeeper tekrar erişilebilir olursa, broker’lar kaldığı yerden devam eder. Süre dolarsa, broker kendini cluster’dan kopar.

# ZooKeeper node'unu temiz başlatma prosedürü
# 1. Önce mevcut veriyi yedekle
tar -czf /backup/zk-snapshot-$(date +%Y%m%d-%H%M%S).tar.gz 
  /var/lib/zookeeper/data/

# 2. ZooKeeper servisini yeniden başlat
systemctl stop zookeeper
systemctl start zookeeper

# 3. Log dosyalarını kontrol et
journalctl -u zookeeper -n 100 --no-pager | 
  grep -E "ERROR|WARN|Exception|elected"

Senaryo 4: Split-Brain ve Network Partition

Network partition, Kafka yönetiminin en sinsi sorunlarından biridir. Broker’lar birbirini göremez hale geldiğinde, bazıları eski controller’ı takip ederken bazıları yeni controller seçmeye çalışır.

# Network connectivity kontrolü
for broker in kafka1 kafka2 kafka3; do
  echo "=== Broker: $broker ==="
  for target in kafka1 kafka2 kafka3 zk1 zk2 zk3; do
    result=$(nc -zv -w 2 $target 9092 2>&1 | tail -1)
    echo "  -> $target: $result"
  done
done

# Controller epoch'unu kontrol et (eski ZooKeeper tabanlı)
zookeeper-shell.sh zk1:2181 get /controller_epoch

# KRaft modunda metadata durumu
kafka-metadata-quorum.sh --bootstrap-server kafka1:9092 describe --replication

Network partition sonrası iyileşme aşamasında, bazı consumer group offset’lerinde tutarsızlık görebilirsiniz. Bu durumu şöyle ele alabilirsiniz:

# Consumer group offset durumunu kontrol et
kafka-consumer-groups.sh --bootstrap-server kafka1:9092 
  --describe 
  --group uygulama-consumer-group

# LAG değerlerini izle
kafka-consumer-groups.sh --bootstrap-server kafka1:9092 
  --describe 
  --group uygulama-consumer-group | 
  awk 'NR>1 {lag=$6; if (lag > 1000) print "YUKSEK LAG:", $0}'

Partition Reassignment ile Yük Dengeleme

Bir broker uzun süre kapalı kaldıktan sonra geri döndüğünde, o broker’daki partition’ların replica’larını yeniden oluşturmanız gerekebilir. Bu işlem, cluster üzerine ciddi I/O yükü bindirdiği için dikkatli yapılmalıdır.

# Reassignment için JSON dosyası oluştur
kafka-reassign-partitions.sh --bootstrap-server kafka1:9092 
  --broker-list "1,2,3" 
  --topics-to-move-json-file topics-to-move.json 
  --generate

# topics-to-move.json örneği
cat > topics-to-move.json << 'EOF'
{
  "topics": [
    {"topic": "siparisler"},
    {"topic": "kullanici-olaylari"}
  ],
  "version": 1
}
EOF

# Reassignment'ı başlat (throttle ile - üretimi etkilememek için)
kafka-reassign-partitions.sh --bootstrap-server kafka1:9092 
  --reassignment-json-file reassignment-plan.json 
  --throttle 50000000 
  --execute

# İlerlemeyi takip et
kafka-reassign-partitions.sh --bootstrap-server kafka1:9092 
  --reassignment-json-file reassignment-plan.json 
  --verify

–throttle parametresi megabayt/saniye cinsinden replika trafik limitini belirler. 50MB/s ile başlayın, cluster’ınıza bağlı olarak artırabilirsiniz. Bu limiti ayarlamazsanız, reassignment sırasında producer/consumer latency’niz tavan yapar.

Log Temizleme ve Disk Sorunları

Disk dolması Kafka arızalarının sıkça karşılaşılan nedenlerinden biridir. Broker disk dolduğunda log yazmayı durdurur ve ISR’dan düşer.

# Disk kullanımını topic bazında analiz et
du -sh /var/kafka/logs/*/

# Hangi topic en çok yer kaplıyor?
du -s /var/kafka/logs/* | sort -rn | head -20

# Topic retention ayarlarını kontrol et
kafka-configs.sh --bootstrap-server kafka1:9092 
  --entity-type topics 
  --entity-name buyuk-topic 
  --describe

# Acil durum: Retention süresini geçici olarak kısalt
kafka-configs.sh --bootstrap-server kafka1:9092 
  --entity-type topics 
  --entity-name buyuk-topic 
  --alter 
  --add-config retention.ms=3600000

# Log segment'lerini manuel temizleme (son çare!)
# Önce topic'i offline'a alma gerekebilir
# Bu işlemi ürün ortamında çok dikkatli yapın
ls -lt /var/kafka/logs/buyuk-topic-0/ | head -20
# Broker log dizini boyutunu monitor eden basit script
#!/bin/bash
THRESHOLD=85
LOG_DIR="/var/kafka/logs"
USAGE=$(df $LOG_DIR | awk 'NR==2 {print $5}' | tr -d '%')

if [ $USAGE -gt $THRESHOLD ]; then
  echo "KRITIK: Kafka log dizini %$USAGE dolu!"
  echo "En büyük topic'ler:"
  du -s $LOG_DIR/*/ | sort -rn | head -5
  # Buraya alerting mekanizmanızı ekleyin
fi

KRaft Modunda Failover (ZooKeeper’sız)

Kafka 3.x ile birlikte KRaft modu artık üretim için önerilir hale geldi. Bu modda ZooKeeper ortadan kalkar, metadata controller’lar tarafından Kafka’nın kendi log mekanizmasıyla yönetilir.

# KRaft cluster durumunu kontrol et
kafka-metadata-quorum.sh --bootstrap-server kafka1:9092 describe

# KRaft controller'larının sağlık durumu
kafka-metadata-quorum.sh --bootstrap-server kafka1:9092 
  describe --replication

# KRaft snapshot durumu
ls -lh /var/kafka/kraft-combined-logs/__cluster_metadata-0/

KRaft modunda controller failover, ZooKeeper tabanlı sistemden çok daha hızlıdır. Controller seçimi saniyeler içinde gerçekleşir çünkü harici bir sisteme bağımlılık yoktur. Ancak controller quorum’unu kaybederseniz (örneğin beş controller’dan üçü düşerse), cluster yazma işlemlerini durdurur.

# KRaft modunda quorum sağlık kontrolü
kafka-metadata-quorum.sh --bootstrap-server kafka1:9092 describe | 
  grep -E "LeaderId|VoterCount|CurrentVoters"

# KRaft controller log'larını incele
tail -f /var/kafka/logs/controller.log | 
  grep -E "ERROR|WARN|Resignation|Election|became active"

Monitoring ve Proaktif Uyarılar

Arızaları reaktif yönetmek yerine proaktif tespit etmek için doğru metrikleri izlemeniz gerekir.

# JMX üzerinden kritik metrikleri çek
# UnderReplicatedPartitions - 0 olmalı
# ActiveControllerCount - tüm cluster'da toplam 1 olmalı
# OfflinePartitionsCount - 0 olmalı

kafka-run-class.sh kafka.tools.JmxTool 
  --object-name "kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions" 
  --jmx-url service:jmx:rmi:///jndi/rmi://kafka1:9999/jmxrmi 
  --reporting-interval 5000

# Consumer lag monitoring
kafka-consumer-groups.sh --bootstrap-server kafka1:9092 
  --list | 
  xargs -I{} kafka-consumer-groups.sh 
    --bootstrap-server kafka1:9092 
    --describe 
    --group {} 2>/dev/null | 
  awk 'NR>1 && $6 > 10000 {print "YUKSEK LAG - Group:", $1, "Topic:", $2, "Partition:", $3, "Lag:", $6}'

Prometheus ve Grafana kullanıyorsanız, JMX Exporter ile aşağıdaki metrikleri mutlaka dashboard’unuza ekleyin:

  • kafka_server_ReplicaManager_UnderReplicatedPartitions: 0’dan büyükse alarm
  • kafka_controller_KafkaController_ActiveControllerCount: Cluster genelinde 1 olmalı
  • kafka_server_ReplicaManager_OfflineReplicaCount: 0 olmalı
  • kafka_network_RequestMetrics_RequestsPerSec: Anormal düşüş broker sorununa işaret eder
  • kafka_log_Log_LogEndOffset: Consumer lag hesaplaması için gerekli

Kurtarma Sonrası Doğrulama Checklist

Herhangi bir arıza sonrasında sistemi tekrar üretime almadan önce şu kontrolleri yapın:

#!/bin/bash
# kafka-health-check.sh
echo "=== Kafka Cluster Saglik Kontrolu ==="

BOOTSTRAP="kafka1:9092,kafka2:9092,kafka3:9092"

echo "[1] Under-replicated partitions:"
URP=$(kafka-topics.sh --bootstrap-server $BOOTSTRAP 
  --describe --under-replicated-partitions 2>/dev/null | wc -l)
echo "    Sayi: $URP (0 olmalı)"

echo "[2] Offline partitions:"
OFP=$(kafka-topics.sh --bootstrap-server $BOOTSTRAP 
  --describe --unavailable-partitions 2>/dev/null | wc -l)
echo "    Sayi: $OFP (0 olmalı)"

echo "[3] Consumer group durumu:"
kafka-consumer-groups.sh --bootstrap-server $BOOTSTRAP 
  --list 2>/dev/null | while read group; do
  state=$(kafka-consumer-groups.sh --bootstrap-server $BOOTSTRAP 
    --describe --group $group 2>/dev/null | 
    grep -i "state:" | awk '{print $2}')
  echo "    $group: $state"
done

echo "[4] Broker listesi:"
kafka-broker-api-versions.sh --bootstrap-server $BOOTSTRAP 2>/dev/null | 
  grep "id:"

echo "=== Kontrol tamamlandi ==="

Sonuç

Kafka arıza yönetiminde başarının sırrı, sorun olmadan önce hazır olmaktır. ISR mekanizmasını anlayın, ZooKeeper ensemble boyutunu doğru seçin (üç veya beş node, asla çift sayı değil), replication factor’ünüzü en az üç tutun ve partition reassignment prosedürlerini önceden deneyin.

Her senaryo için bu yazıda verdiğim komutları gerçek bir test ortamında çalıştırarak öğrenin. Prodüksiyonda ilk kez görmemeniz gereken bir komut yoktur. Disaster recovery tatbikatlarını takvime koyun, altı ayda bir cluster’ın bir broker’ını kasıtlı olarak kapatarak ekibinizin tepkisini ve prosedürlerinizin geçerliliğini test edin.

KRaft moduna geçiş için uygun ortamı hazırlıyorsanız, ZooKeeper bağımlılığından kurtulmak uzun vadede operasyonel yükünüzü ciddi ölçüde azaltacaktır. Ancak geçiş sırasında her iki mimarinin failover davranışını iyi anlamanız gerekir. Sorularınızı yorum kısmına bırakabilirsiniz, gerçek senaryolarınızı tartışmaya her zaman açığım.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir