Spring Kafka Poison Pills -Zehirli Kayıtlar

İbrahim Yanık
turkcell
Published in
4 min readOct 6, 2022

Son zamanlarda modern uygulamalarda Event-driven architecture yapısı kullanılarak küçük componentlerin birbirleri ile iletişim kurmaları sağlanmaktadır.

Event-driven architecture da 3 temel bileşen vardır. Bunlar; event producers, event broker, event consumers.

Buradaki temel kavram produce edilen mesajların consume edilmesidir. Produce ettiğimiz mesajlardan herhangi bir tanesinde oluşacak bir hatadan dolayı consume edilememesi durumunda sistemimizin tamamen durmasına neden olabilir. Bu duruma poison pill (zehirlenme) denir.

Bu yazımda poison pills tam olarak ne olduğunu, nasıl oluştuğunu, etkilerini ve bunlarla nasıl başa çıkılacağını ele alıyor olacağız.

Serialization ve Deserialization

Poison pill’i tam anlamak için serialization ve deserialization kavramlarını tam olarak anlamakta fayda vardır.

Serialization, bir nesne durumunu depolanabilen veya iletilebilen ve daha sonra farklı bir ortamda yeniden oluşturulabilen bir formata (byte dizisi) dönüştürme işlemidir. Bir byte dizisini nesne durumuna dönüşümünün sağlandığı işleme ise deserialization denir.

Yukarıda bahsettiğim gibi poison pill bozuk kayıt olma durumunda oluşur. Bozuk kayıtların birçok sebebi olması nedeniyle bu yazıda sadece deserialization durumunda oluşan hataları odaklanacağız.

Producer ve consumer da uyumlu serializer ve deserializer kullanılıyorsa her şey beklendiği gibi çalışır. Bu durumda poison pill den kaçınılmış olunur. Fakat producer ve consumer uyumsuz serializer ve deserializer’a sahip olduklarında deserialization hatası meydana gelir. Aşağıdaki örnekte, producer bir StringSerializer kullanırken, consumer uyumsuz deserializer (FloatDeserializer) kullanıyor.

Kafka da serialization, bir Java objesinin produce edilirken key-value ikilisinin byte dizisine dönüştürülmesi deserialization ise consume edilen mesajın byte dizisinin açılmasını ve key-value değerlerinin alınması sağlanır.

Poison Pills nedir?

Poison Pill Kafka topiclerin de üretilen bir mesajın kaç defa denenirse denensin bir türlü consume edilememesine yol açan kayıttır. Bu durumun olası nedeni bozuk kayıtların olması, kaydın deserialization durumunda bir hata oluşması veya schema uyuşmazlığı olabilir. Schema uyuşmaz ise consume edilirken bir hata döndürülür. Bu soruna en çok yol açan durum schema uyuşmazlığıdır.

Bu durumda, her deserializer hatası olduğunda log dosyasına bu yazılır ve log dosyası bir anda çok büyük bir boyuta ulaşır. Bir çok sistemde bu log dosyaları merkezi bir yerdedir ve bu durum oldukça maliyetli bir hal alır. Ayrıca log içerisinde Kafka dışında başka bir akışın loglarını bulmakta ikansız hale gelebilir. Depolama alanına bağlı olarak log doyaları Kafka hataları ile doldurulur ve makinenin çalışması etkilenebilir. Yani poison pill in oldukça ciddi bir etkisi vardır.

Nasıl Çözülür?

Poison pill’i çözmek için 4 seçenek vardır. Fakat bunlardan sadece bir tanesi tavsiye edilir.

İlk seçenek, oluşturulan topic in retention süresi kadar beklemek ve hatalı kaydın retention süresi sonunda silinmesi. Retention süresi default olarak 7 gündür ve değiştirilebilir. Tabi burada consumer tarafının bunun için 7 gün beklemesi idealden uzak bir yöntemdir.

İkinci seçenek, offset değerini zehirleme oluşturan kayıttan sonraki bir offset değerine manuel olarak güncellemektir. Bu yöntemde Kafka için çok fazla kontrole sahip olmanız bir avantajdır. Fakat bu yöntem basit bir yöntem olmayabilir. Offseti sıfırlamak için aşağıdaki komutu kullanabilirsiniz. Sıfırlama işlemini yapmadan önce consumer durdurulmalıdır.

kafka-consumer-groups — bootstrap-server $BOOTSTRAP_SERVER — group $CONSUMER_GROUP — reset-offsets — to-offset $OFFSET — topic $TOPIC — execute

Üçüncü seçenek, consumer grubunu değiştirmek ve en son offset ten consume etmeye başlamaktır. Bu çözümün dezavantajı zehirli olan kayıt ile son produce edilen kayıt arasındaki mesajların consume edilememesi ve kaybolmasıdır.

Son ve önerilen seçenek, ErrorHandlingDeserializer kullanılmasıdır.

ErrorHandlingDeserializer kullanmak içi consumer konfigürasyonunu key-value deserializer konfigürasyonlarını ErrorHandlingDeserializer olarak vermeliyiz.

ErrorHandlingDeserializer bu class key ve value değerlerini deserialize etmeye çalışacaktır. Eğer DeserializationException oluşmaz ise kayıt consume tarafına iletilir ve normal şekilde çalışır. Fakat DeserializationException oluşursa kayıt artık consume tarafına iletilmez. Bunun yerine ErrorHandler başarısız olan kaydı çağırır ve hatalı kaydı işleyerek offset değerini ileri taşımış olur. Bu sayede ErrorHandler zehirlenmeye sebep olan kaydı yutmuş oldu. Sonuç olarak Consume tarafı bu durumdan etkilenmeden devam eder.

Birden fazla consumer olması durumunda, ErrorHandlingDeserializer bu duruma özel yapılandırmak mümkündür. Aşağıda, LoggingErrorHandler ile bir JsonDeserializer’ın nasıl yapılandırılacağını görebilirsiniz.

Bu kısımda LoggingErrorHandler’ın zehirli kaydın byte sırasını gösterir, burada SeekToCurrentErrorHandler kullanarak başarısız olan kayıt hakkında bazı ek bilgileri alabilirsiniz.

--

--