Ana sayfa → Teknik
Leader Election: Bu İşi Kim Yapacak?
Streaming-engine'in dört kopyası çalışıyor. Bridge’lerin sağlık kontrolünü (health check) dördü birden yapıyor. Aynı köprüye saniyede dört ping, aynı alarma dört bildirim, aynı yeniden bağlanma dört kez. Ölçekledik ama işi bölmedik.
- Bazı işler tam olarak bir kere yapılmalı. Hepsi yaparsa gürültü, hiçbiri yapmazsa ölü köprü fark edilmez.
- Liderlik süresiz verilmez, kiralanır. Lider yenilemeyi bırakırsa süre dolar, yerine biri geçer.
- İki liderin aynı anda olması engellenemez, sadece zararsız hale getirilir. Cevabı fencing token.
- Çoğu ekip bunu kendi yazmamalı. Kubernetes lease, etcd veya Postgres advisory lock zaten var.
Problem nereden çıkıyor?
Bir servisi yatayda büyütmek genelde bedava gelir: iki kopya iki kat iş yapar. Ama her iş bölünebilir değil. Bazı işler tam olarak bir kere yapılmalı ve kopya sayısı arttıkça bu işler sessizce bozulur.
Trade tarafından tanıdık gelecek örnekler:
| İş | Hepsi yaparsa | Hiçbiri yapmazsa |
|---|---|---|
| Bridge sağlık kontrolü | Köprüye 4 kat ping, 4 kat alarm, gereksiz yük | Ölü köprü fark edilmez, emirler boşluğa gider |
| Gün sonu mutabakat işi | Aynı rapor 4 kez üretilir, 4 kez mail gider | Mutabakat hiç yapılmaz |
| Sembol listesini dış kaynaktan çekme | Sağlayıcının hız sınırına takılırsın | Fiyat listesi eskir |
| Zaman aşımına (timeout) uğramış emirleri temizleme | Aynı emri 4 kopya iptal etmeye çalışır | Emirler askıda kalır |
Sağ sütun ilk bakışta daha korkutucu görünüyor ama sol sütun daha sinsi: hata vermez, sadece pahalıya patlar. Sağlık kontrolünün dört kopyadan gitmesi ilk gün fark edilmez; köprü sağlayıcısı hız sınırı uygulamaya başladığında fark edilir.
Kolay ama yanlış üç çözüm
1. “Sadece bir kopya çalıştıralım”
İşe yarar — o kopya ölene kadar. Kubernetes yeni bir tane açar, arada 20–60 saniye geçer ve o sürede kimse sağlık kontrolü yapmaz. Kabul edilebilir mi? Bazı işler için evet. Bridge health check için hayır.
2. “Ortam değişkeniyle işaretleyelim”
if (os.getenv("IS_LEADER") == "true") {
healthCheckDongusunuBaslat();
}
Basit ve çoğu zaman çalışıyor. Sorun şu: o kopya ölünce liderlik ölür.
Kubernetes yeni pod açar ama yeni pod’un değişkeni false’tur.
Kimse haber vermez; bunu gece 3’te, ölü köprü yüzünden emirler gitmeyince
öğrenirsin.
3. “İlk gelen alsın, Redis’e bayrak koyalım”
Doğru yöne gidiyorsun ama yarısı eksik. SETNX lider 1 ile bayrak koyup
süre vermezsen, süreç çöktüğünde bayrak sonsuza kadar kalır ve
kimse lider olamaz. Bunun tamamı
dağıtık kilit (distributed lock) yazısında anlatılıyor; buradaki
fark, liderliğin bir kilit değil süreli bir kira olması.
Doğru model: lease (liderlik kiralanır)
Lease mantığı şu: liderlik sonsuza kadar verilmez, belirli bir süreliğine kiralanır. Lider bu kirayı düzenli olarak yeniler. Yenileyemezse — çöktüğü, ağdan koptuğu ya da takıldığı için — süre dolar ve başkası devralır.
CREATE TABLE liderlik (
is_adi text PRIMARY KEY,
sahip text NOT NULL,
gecerlilik timestamptz NOT NULL,
donem bigint NOT NULL DEFAULT 0 -- ← fencing token
);
-- Her kopya 5 saniyede bir bunu calistirir:
INSERT INTO liderlik (is_adi, sahip, gecerlilik, donem)
VALUES ('bridge_health', :ben, now() + interval '15 seconds', 1)
ON CONFLICT (is_adi) DO UPDATE
SET sahip = :ben,
gecerlilik = now() + interval '15 seconds',
-- donem SADECE lider degisince artar
donem = liderlik.donem + CASE WHEN liderlik.sahip = :ben THEN 0 ELSE 1 END
WHERE liderlik.sahip = :ben -- ya zaten benim (yenileme)
OR liderlik.gecerlilik < now() -- ya da suresi dolmus (devralma)
RETURNING sahip, donem;
-- Donen sahip ben isem: lider benim, ise devam.
-- Satir donmediyse: baskasi lider, sen bekle.
Otuz satır ve ek bir altyapı yok. Dikkat edilecek üç detay var:
- Kira süresi, yenileme aralığının en az 3 katı olmalı. Yukarıda 5 saniyede bir yenileme, 15 saniyelik kira. İki yenileme kaçarsa hâlâ liderim; üçüncüde düşerim. Bu oran daha dar olursa tek bir ağ gecikmesi liderliği boşuna el değiştirir ve sistem sürekli lider değiştirir.
-
Devralma süre dolmadan yapılamaz.
WHEREsatırındaki iki koşul bunu garanti ediyor. -
donemalanı boşuna değil. Bir sonraki bölümün konusu.
Split-brain: iki lider aynı anda
Şimdi kötü haber. Yukarıdaki kod doğru ama iki kopyanın aynı anda kendini lider sanmasını engellemiyor. Ve hiçbir kod engelleyemez. Sebep:
| Zaman | Kopya A | Kopya B | Gerçek durum |
|---|---|---|---|
| 00:00 | lider oldu, dönem 7 | bekliyor | lider A |
| 00:05 | yeniledi | bekliyor | lider A |
| 00:07 | GC duraklaması başladı | bekliyor | lider A (ama uyuyor) |
| 00:20 | hâlâ duraklamada | süre doldu, lider oldu, dönem 8 | lider B |
| 00:22 | uyandı, “ben liderim” sanıyor | çalışıyor | iki lider! |
A yanlış bir şey yapmadı; sadece uyudu ve uyandığında dünyanın değiştiğini bilmiyor. Bu duruma split-brain deniyor ve dağıtık sistemlerde kaçınılmaz.
Çözüm: fencing token (dönem numarası)
Her liderlik devrinde artan bir numara üret ve korunan kaynağa bu numarayı yazdır. Kaynak, gördüğünden daha küçük numaralı isteği reddetsin:
-- A (donem 7) uyanip bridge durumunu guncellemeye calisiyor:
UPDATE bridge_durum
SET saglik = 'DOWN', son_kontrol = now(), donem = 7
WHERE bridge_id = 'LP-3'
AND donem <= 7; -- ← tabloda 8 yaziyor, kosul tutmaz
-- 0 satir etkilendi. A yazamadi.
-- Uygulama bunu gorup "artik lider degilim" diyip donguyu durduruyor.
Buradaki incelik: A’nın kendi liderliğini sorgulamasına gerek yok. Yazmaya kalkıyor, reddediliyor, anlıyor. Doğruluk zamana değil sıraya bağlanmış oluyor — dağıtık kilitteki fikrin aynısı.
Yan etkisi olmayan işlerde gerek yok
Her iş için fencing gerekmiyor. Ayrım şu: iş dışarıya bir etki bırakıyor mu?
- Salt okuma sağlık kontrolü (ping atıp loglamak)
- Önbellek ısıtma
- Metrik toplama
İki kopya yaparsa sadece israf olur.
- Emir iptal etme, pozisyon kapatma
- Bildirim/e-posta gönderme
- Mutabakat kaydı yazma
- Dış sisteme durum bildirme
İki kopya yaparsa para veya güven kaybı.
Bunu kendin yazma (çoğu zaman)
Yukarıdaki Postgres yöntemi öğretici ama gerçekte muhtemelen zaten elinde hazır bir araç var:
| Nerede çalışıyorsun | Kullan | Not |
|---|---|---|
| Kubernetes | coordination.k8s.io/Lease |
Kütüphaneler hazır; süre yönetimini kendi yapıyor |
| Postgres var | pg_try_advisory_lock ya da yukarıdaki tablo |
Bağlantı kopunca kilit kendiliğinden düşer |
| etcd / Consul / ZooKeeper | Yerleşik lider seçimi | En sağlamı; ama sırf bunun için kurulmaz |
| Sadece Redis var | SET ... NX PX + yenileme |
Çalışır, ama fencing token’ı sen eklemelisin |
Kendi Raft uygulamanı yazmak neredeyse hiçbir zaman doğru cevap değil. O kod doğru görünür, testlerden geçer ve altı ay sonra bir ağ bölünmesinde seni yalnız bırakır.
Sahadan: health check’e ne yaptık
Baştaki probleme dönelim. Dört streaming-engine, hepsi köprüleri yokluyor. Yaptığımız üç adım:
- Liderlik lease’e bağlandı. 5 saniye yenileme, 15 saniye kira. Ping trafiği dörtte bire indi.
- Durum yazımına dönem numarası eklendi. Bir kopya duraklamadan çıkıp “LP-3 çalışmıyor” yazmaya kalkarsa reddediliyor. Bu değişiklikten önce, uykudan uyanan bir kopyanın sağlıklı bir köprüyü ölü işaretleyip trafiği kesmesi yaşandı — en pahalı ders buydu.
- Liderlik metriğe döküldü. Her kopya “lider miyim” bilgisini metrik olarak yayıyor. Grafikte toplamın sürekli 1 olması gerekiyor. 0’a düşerse kimse yapmıyor, 2 olursa split-brain var. Tek bir grafik, iki farklı arızayı da gösteriyor.
Liderliği bırakırken haber ver. Kopya düzgün kapanıyorsa (deploy sırasında) kira kaydını silsin. Yoksa yeni lider 15 saniye boşuna bekler. Tek satırlık bir iş ve deploy sırasındaki boşluğu sıfırlıyor:
DELETE FROM liderlik WHERE is_adi = 'bridge_health' AND sahip = :ben;
Kaç lider olmalı? Bir tane, ama hangi konuda?
Sık yapılan bir tasarım hatası: tek bir global lider seçip bütün özel işleri ona yükleme. Sonuç, yatayda büyüyen bir sistemin içinde tek bir dar boğaz oluşması.
Daha iyisi liderliği iş bazında vermek: sağlık kontrolünün lideri ayrı, mutabakatın lideri ayrı, sembol senkronunun lideri ayrı. Böylece yük dağılır ve bir işin liderinin takılması diğerlerini etkilemez.
Bunu bir adım öteye götürmek istersen zaten sharding konusuna girmiş olursun: liderlik “tek kopya yapsın” demek, sharding “her kopya kendi payını yapsın” demek. İkisi birbirinin rakibi değil; hangi işin bölünebildiğine göre seçiyorsun.
Kontrol listesi AI agent görev listesi
- Bu iş gerçekten tek kopya mı istiyor, yoksa bölünebilir mi?
- Liderlik süreli mi (lease), yoksa süresiz bir bayrak mı?
- Kira süresi, yenileme aralığının en az 3 katı mı?
- Lider çökerse kaç saniye içinde yerine geçiliyor? Bu süre kabul edilebilir mi?
- İş dışarıya etki bırakıyorsa fencing token var mı?
- Düzgün kapanışta liderlik bırakılıyor mu?
- “Kaç lider var” metriği var mı? (Sürekli 1 olmalı.)
- Liderlik iş bazında mı, yoksa tek global lider mi?
Sonuç
Leader election kulağa akademik geliyor ama pratik karşılığı çok basit bir soruya dayanıyor: bu işi kim yapacak? Cevabı “hepsi” olursa gürültü, “hiçbiri” olursa sessiz bir arıza çıkıyor.
Ve akılda kalacak tek şey şu olsun: liderlik bir mülk değil, bir kiradır. Süresi dolar, el değiştirir ve eski sahibi bunu bilmeyebilir. Sistemin sağlamlığı, eski sahibin geç uyandığında ne yapabildiğiyle ölçülür.