Giriş
Modern olay odaklı mimarilerde Apache Kafka, veri dağıtımı için merkezi sinir sistemi işlevi görür. Ancak, mesaj geçişinin "gönder ve unut" doğası, altta yatan kırılganlığı genellikle gizler. Tüketiciler üreticilere yetişemediğinde veya işleme, hatalar veya geçici arızalar nedeniyle başarısız olduğunda, sistemler çökebilir. Bu yazı, iki kritik dayanıklılık desenini ele alır: bellek tükenmesini önlemek için backpressure yönetimi ve işlenmesi başarısız olan zehirli mesajları izole etmek için Ölü Mektup Kuyruklarının (DLQ) uygulanması.
Kafka'da Backpressure'ı Anlama
Backpressure, bir tüketiciye broker'a aşırı yüklendiğini bildirmesi için kullanılan mekanizmadır. Kafka'da bu, başlıca offset taahhütleri ve getirme boyutları (fetch sizes) üzerinden yönetilir. Bir tüketici, mesajların geldiğinden daha yavaş işliyorsa, broker mesajları konuya (topic) depolamaya devam eder ve bu da etkili bir tampon sağlar. Ancak, uygulamanın dahili belleğini yönetmesi hâlâ gerekir.
Backpressure'ı ele almanın anahtarı, sadece Kafka broker'ları değil, tüketici mantığınızla ilgilidir. Tüketiciniz ağır I/O işlemleri (veritabanına yazma gibi) gerçekleştiriyorsa, bloklanır. Uygun sınırlar olmadan bu, OutOfMemoryError'lara yol açar.
// Örnek: Belleği yönetmek için getirme sınırlarını yapılandırma
Properties props = new Properties();
props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 500);
props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, 5 * 1024 * 1024); // 5MB
props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, 30000);
max.poll.records değerini sınırlayarak, tek bir sorgulama (polling) iterasyonunun belleğe çok fazla veri çekmesini engellersiniz. İşleme,
max.poll.interval.ms süresinden uzun sürerse, tüketici gruptan devredilir ve bir yeniden dengeleme (rebalance) tetiklenir. Bu bir emniyet supabıdır, ancak sık yeniden dengelemeler maliyetlidir. Hedef, bu parametreleri, tüketicinin aşırı yüklenmeden alım hızına yetişebilmesi için ayarlamaktır.
Ölü Mektup Kuyruklarının Rolü
Bir mesajın işlenmesi başarısız olduğunda ne olur? Bir tüketici döngüsünde basit bir
throw new Exception(), tüketiciyi durdurur ve offsetlerin durmasına neden olur. Bu, tüm bölüntüyü (partition) bloklar. Bunu önlemek için DLQ'ler kullanırız.
Bir DLQ, başarısız mesajların yazıldığı ayrı bir konudur (veya kuyruktur). Orijinal tüketici bir sonraki mesajı işlemeye devam ederken, DLQ tüketici (veya manuel operatör) arızayı araştırır.
try {
processMessage(record);
// Başarılıysa offset'i manuel olarak taahhüt et veya otomatik taahhüde güven
} catch (Exception e) {
// Hataları günlüğe kaydet
logger.error("Kayıt işlenemedi: {}", record.value(), e);
// DLQ'ye gönder
dlqProducer.send(dlqTopic, record);
// İlerlemek için orijinal kaydın offset'ini taahhüt et
consumer.commitSync(Map.of(topicPartition, new OffsetAndMetadata(record.offset() + 1)));
}
Not: Üretim ortamında, bu işlem mantığını doğru bir şekilde işlemek ve mesajın ya işlendiğinden ya da DLQ'ye taşındığından, kopyalama veya kayıp olmadan emin olmak için Spring Kafka veya Confluent Cloud'un DLQ işlevselliği gibi sağlam bir çerçeve kullanmalısınız.
Pratik Uygulama Stratejisi
1.
Gecikmeyi İzleyin: Backpressure'ı erken tespit etmek için tüketici grubu gecikmesini (lag) izleyin. Gecikme sürekli artıyorsa, bu bir kapasite sorununa işaret eder.
2.
Güçsüzlük (Idempotency): İşleme mantığınızın güçsüz (idempotent) olduğundan emin olun. Yeniden denemeler ve DLQ yeniden gönderimleri kopyalara neden olabileceğinden, uygulamanız bunları zarif bir şekilde ele almalıdır.
3.
Degradasyon Modları: Aşağı akış (downstream) bir hizmet devre dışıysa, mesajların atılmasına (nadir), yerel olarak tamponlanmasına (riskli) veya daha sonra yeniden oynatılmak üzere DLQ'ye yönlendirilmesine karar verin.
Sonuç
Dayanıklı olay odaklı sistemler inşa etmek, sadece Kafka'yı dağıtmaktan fazlasını gerektirir. Backpressure'ı yönetmek için tüketici davranışının dikkatli ayarlanması ve Ölü Mektup Kuyrukları aracılığıyla arızaları ele almak için sağlam bir strateji gerektirir. Mesajları, herhangi bir aşamada başarısız olabilecek kırılgan veriler olarak ele alarak, yalnızca ölçeklenebilir değil, aynı zamanda kurtarılabilir boru hatları inşa edersiniz. En kritik konularınız için gecikmenizi izlemeye ve temel bir DLQ uygulamasına başlayın.