@Scheduled ve ShedLock — Cron İşi Kaç Pod'da Çalışıyor?
Önce şunu oku: Oturum Yönetimi ve Stateless Ölçekleme
30 saniyede özet
@Scheduled her sunucuda ayrı çalışır: üç kopya çalıştırırsan iş de üç kez çalışır. ShedLock veritabanına bir satır yazarak işi tek sunucuya indirir; kilidin süresini de işin süresine göre seçmek gerekir.
Servis bir replikadan üçe çıkarıldı. Ertesi sabah müşteri hizmetlerinin telefonu durmadı: herkes aynı faturayı üç kez almıştı.
Adım adım oku
- Saat 02:00'de uygulamanın üç kopyasındaki @Scheduled zamanlayıcısı aynı anda çalar.
- Birbirlerinden haberleri olmadığı için üçü de fatura işini çalıştırır: herkes faturayı üç kez alır.
- ShedLock ile işe başlayan ilk kopya ortak bir deftere, yani veritabanındaki bir satıra adını yazar.
- Öteki kopyalar satırı görür ve o turu atlar. Fatura bir kez gönderilir.
-
Bayt: Ertesi sabah müşteri hizmetlerinin telefonu susmadı!
-
Sen: Ne oldu?
-
Bayt: Herkes aynı faturayı üç kez almış. Kod değişmedi, sadece üç kopya çalıştırdık.
-
Bayt: Üç vardiya amirinin telefonunda aynı alarm varsa, kapıyı kaç kişi kilitler?
@Scheduled sadece kendi sunucusunu tanır
@EnableScheduling açıkken Spring, @Scheduled metotları kendi zamanlayıcısıyla çalıştırır. Boot’un zamanlayıcısı varsayılan olarak tek thread’lidir; uzun bir iş, diğer zamanlanmış işleri de bekletir.
Zamanlayıcı yalnızca kendi JVM’ini bilir. Üç pod varsa üç zamanlayıcı vardır ve dakikası gelince üçü de işi başlatır.
Kafam karıştı, daha basit anlat
Üç sunucunun her birinin kendi çalar saati var. Saat sekizi gösterince üçü de aynı işi başlatır, çünkü birbirlerinden haberleri yoktur.
Gece 02:00'de fatura gönderen bir @Scheduled işi olan servis 1 replikadan 3 replikaya çıkarıldı. Ertesi sabah ne görürsün?
Bir serviste iki @Scheduled iş var: her dakika çalışan hızlı bir sağlık kontrolü ve bazen 10 dakika süren bir rapor. Rapor çalışırken sağlık kontrolü de duruyor. Neden?
@Scheduled(fixedRate = 60_000) ile @Scheduled(fixedDelay = 60_000) arasındaki fark nedir?
ShedLock: defterdeki satır
ShedLock, pod’lar arasında paylaşılan bir distributed lockBirden çok süreç arasında paylaşılan kilit; genellikle bir veritabanı satırı ya da Redis anahtarı. Aynı işin aynı anda yalnızca bir yerde çalışmasını sağlar.Sözlükte gör → kurar: veritabanında iş adına bir satır. Dakikası gelen pod satırı almaya çalışır; alamayan o çalıştırmayı atlar.
Kilit alındı, lockAtMostFor 1 dakika. İş bu sefer 3 dakika sürüyor. 02:01'de ne olur? Cevabı göster
Başka bir pod işi yeniden başlatır. Kilit 1 dakika sonra düşer, iş ise hâlâ sürüyor. Aynı iş artık iki pod’da çalışıyor.
lockAtMostForShedLock'ta kilidin, sahibi ölse bile en geç ne zaman düşeceği. En uzun normal çalıştırmadan uzun olmalı; kısa olursa iş iki yerde çalışır.Sözlükte gör →, kilidin sahibi ölse bile en geç ne zaman düşeceğidir. En uzun normal çalıştırmadan uzun olmalı. Bedeli: kilidi tutan pod çökerse, o süre boyunca kimse işi çalıştıramaz.
Kafam karıştı, daha basit anlat
ShedLock ortak bir deftere “bu işi ben yapıyorum” diye yazmaktır. Satırı ilk yazan işi yapar, ötekiler o turu atlar.
Rapor her gece iki kez gönderiliyor, ama yalnızca 02:00'daki çalıştırma 10 dakikadan uzun sürdüğünde. ShedLock kurulu. Hatalı satır hangisi?
ShedLock kullanan bir işte kilidi tutan pod çalıştırmanın ortasında çöktü. lockAtMostFor 30 dakika. Ne olur?
Kendin gör
Cron işi kaç pod'da çalışıyor?
Tohum 26760Pod A
boşta
Pod B
boşta
Pod C
boşta
Oynat ya da adımla.
Şu an ne oldu?
3 pod, kilit yok
Her pod kendi zamanlayıcısını çalıştırır ve dakikası gelince işi başlatır. Pod'ları birbirinden haberdar eden tek şey kilittir.
Görevler0/3
Aynı işi üç pod'da birden çalıştıraçık
İpucu
Kilit olmadan ölçekle.
Kilit varken yine de çift çalıştıraçık
İpucu
lockAtMostFor'a bak.
Üç pod, sıfır çift çalıştırma, sıfır boş dakikaaçık
İpucu
Doğru kilit süresi, çökme yok.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Üç pod, kilit yok: her dakika üç çalıştırma.
- Kilidi “ShedLock” yap. Her dakika tek çalıştırma.
- lockAtMostFor’u “1 dk” yap. 02:01’de ikinci pod da başladı.
- “10 dk”ya dön ve çökmeyi aç. Dört dakika boyunca hatırlatma yok.
- Çökme açıkken “1 dk” seç. B hemen devraldı; ama çökme olmasaydı 3. adımdaki gibi iş iki kez çalışırdı.
Her işi, 3 replikalı bir serviste en uygun çalıştırma biçimine göre ayır.
Tuzaklar
Kilide tek başına güvenmek. Kilit düşebilir, saatler farklı olabilir. İşin kendisini idempotent yap: zaten gönderilmiş faturayı atla.
Sessiz başarısızlık. Tekrarlayan bir işin exception’ı yalnızca log’a yazılır ve iş bir sonraki tetiklemede yine denenir. Son başarılı çalıştırma zamanını metrik olarak yayınla ve alarm kur.
Saat dilimi. cron ifadesi sunucunun saat dilimiyle yorumlanır. zone = "Europe/Istanbul" gibi açıkça yaz.
Uzun iş web pod’unda. Bir saat süren dışa aktarma, deploy ve ölçeklemeyle kesilir. Onu bir Kubernetes CronJob’a taşımak çoğu zaman daha basittir.
Kafam karıştı, daha basit anlat
Kilit düşebilir. İşi, iki kez çalışsa da zarar vermeyecek şekilde yaz: gönderilmiş faturayı yeniden gönderme.
ShedLock'lu, her dakika çalışan ve 200 ms süren bir iş var. Pod saatleri birkaç saniye farklı. Bazen aynı dakikada iki çalıştırma görülüyor. Hangi ayar bunu önler?
Aşağıdaki örnek bir bankanın kredi servisinden: vadesi yaklaşan taksitler için SMS gönderen iş üç pod’da güvenle çalışıyor. Kilit, idempotent iş, izlenebilir son başarı ve açık saat dilimi bir arada.
Derinleş · Kredi taksidi hatırlatma işi: uçtan uca 5 dosya · ~75 satır · ilk okumada atlayabilirsin
Kendini sına
@Scheduled bir iş, uygulamanın çalışan her kopyasında ayrı ayrı çalışır.
@Scheduled bir metot her çalıştırmada exception fırlatıyor. Ne olur?
Aklında kalacak üç şey
- 1 @Scheduled sunucular arasında haberleşmez. Kopya sayısı arttıkça kilitsiz her zamanlanmış iş de çoğalır.
- 2 lockAtMostFor, en uzun normal çalıştırmadan uzun olmalıdır. Bedeli: kilidi tutan sunucu çökerse iş o süre boyunca bekler.
- 3 Kilit de şaşabilir; bu yüzden iş iki kez çalışsa bile zarar vermemeli ve son başarılı çalışma zamanı izlenmelidir.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.