How-To Guides

Olay Akışlarını Ustalıkla Yönetme: Apache Kafka Kullanımı Kapsamlı Rehber

Mikroservisler ve dağıtık sistemlerin modern manzarasında, gerçek zamanlı veri akışlarını verimli bir şekilde işleme yeteneği bir lüks değil, bir zorunluluktur. Apache Kafka, yüksek işleme kapasitesi, hata toleransı ve ölçeklenebilirlik sunarak olay odaklı mimariler kurmak için varsayılan standart haline gelmiştir. Ancak, geleneksel veritabanı odaklı modellerden akış işleme modellerine geçiş yapan geliştiriciler için öğrenme eğrisi oldukça dik olabilir. Bu rehber, Kafka'nın temel kavramlarını size adım adım anlatacak ve yaygın olarak kullanılan Confluent Kafka Java istemcisi kullanarak üreticiler (producer) ve tüketiciler (consumer) nasıl uygulanacağını gösterecektir.

Temel Soyutlamaları Anlamak

Koda dalmadan önce, Kafka'nın temel yapı taşlarını anlamak kritik öneme sahiptir. Geleneksel bir kuyruk, mesajların tüketilip atıldığı bir yapı iken, Kafka mesajları yapılandırılabilir bir süre boyunca saklar; bu sayede birden fazla hizmet, kendi hızında aynı veriyi okuyabilir. Birincil soyutlamalar şunları içerir:
  • Topic (Konu): Kayıtların yayınlandığı bir kategori veya besleme adı.
  • Partition (Bölüm): Paralellik ve ölçeklenebilirlik sağlamak için konular bölümlere ayrılır. Her bölüm, sıralı ve değiştirilemez bir kayıt dizisidir.
  • Producer (Üretici): Kafka konularına kayıt yayınlayan (yazan) bir uygulama.
  • Consumer (Tüketici): Konulara abone olan (okuyan) ve kayıtları işleyen bir uygulama.
  • Consumer Group (Tüketici Grubu): Bir konunun tüm bölümlerini kolektif olarak okuyan bir tüketici grubu; bu, yük dengelemeyi ve paralel işlemeyi sağlar.

Ortamın Hazırlanması

Bu yazıdaki pratik örnekleri takip etmek için çalışan bir Kafka broker'ına ve Confluent Kafka istemci kütüphanesine ihtiyacınız olacaktır. Java 11 veya daha yüksek bir sürümün yüklü olduğundan emin olun. Maven kullanıyorsanız, pom.xml dosyanıza aşağıdaki bağımlılığı ekleyin:
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>3.4.0</version>
</dependency>

Bir Üretici (Producer) Oluşturma

Üretici, verileri Kafka'ya göndermekten sorumludur. Anahtarları (keys) ve değerleri (values) baytlara serileştirir ve hangi bölüme yazılacağını belirler. Aşağıda, test-topic adlı bir konuya basit bir metin mesajı gönderen minimal bir Kafka üretici örneği bulunmaktadır.
import org.apache.kafka.clients.producer.*;
import java.util.Properties;

public class KafkaProducerExample {
    public static void main(String[] args) throws Exception {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        try (Producer<String, String> producer = new KafkaProducer<>(props)) {
            ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key1", "Hello Kafka!");
            producer.send(record, (metadata, exception) -> {
                if (exception != null) {
                    System.out.println("Mesaj gönderme hatası: " + exception.getMessage());
                } else {
                    System.out.println("Bölüme gönderildi: " + metadata.partition() + 
                                       ", ofset: " + metadata.offset());
                }
            });
            producer.flush();
        }
    }
}
Uygulama kapanmadan önce tamponlanmış tüm mesajların gönderildiğinden emin olmak için flush() kullanımına dikkat edin. Üretim ortamında, asenkron geri aramaları daha sağlam bir şekilde yönetmeniz ve üretici yaşam döngüsünü bir singleton olarak yönetmeniz genellikle beklenir.

Bir Tüketici (Consumer) Oluşturma

Tüketiciler, ofsetleri yönetmeleri ve potansiyel mesaj işleme hatalarını ele almaları nedeniyle biraz daha karmaşıktır. Tüketici bir konuya abone olur ve döngü içinde yeni mesajlar için sorgulama (poll) yapar.
import org.apache.kafka.clients.consumer.*;
import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("group.id", "test-group");
        props.put("enable.auto.commit", "true");
        props.put("auto.commit.interval.ms", "1000");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        try (Consumer<String, String> consumer = new KafkaConsumer<>(props)) {
            consumer.subscribe(Collections.singletonList("test-topic"));
            
            while (true) {
                ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
                for (ConsumerRecord<String, String> record : records) {
                    System.out.printf("Tüketilen kayıt: key=%s, value=%s, partition=%d%n",
                                      record.key(), record.value(), record.partition());
                }
            }
        }
    }
}

Üretim İçin En İyi Uygulamalar

Yukarıdaki örnekler işlevsel olsa da, üretim sistemleri ek hususlar gerektirir. Mesajların tüm eşitlenmiş replikalara kalıcı olarak yazıldığından emin olmak için üretici yapılandırmanızda her zaman acks=all kullanın; bu da dayanıklılığı garanti eder. Tüketiciler için, tam olarak bir kez (exactly-once) semantiği elde etmek veya çökmeler sırasında veri kaybını önlemek amacıyla otomatik commit'i devre dışı bırakmayı ve ofsetleri yalnızca başarılı mesaj işlemeden sonra manuel olarak commit etmeyi düşünün. Ayrıca, geçici ağ hatalarını zarif bir şekilde yönetmek için her zaman yeniden deneme mantığını ve devre kesici (circuit breaker) desenlerini uygulayın.

Sonuç

Apache Kafka, doğru şekilde anlaşıldığında uygulamalarınızın verileri nasıl işlediğini dönüştürebilen güçlü bir araçtır. Üretici-tüketici desenini ustalaşarak ve bölütleme stratejilerini anlayarak, dayanıklı, ölçeklenebilir ve gevşek bağlı sistemler inşa edebilirsiniz. İleriye doğru ilerlerken, gerçek zamanlı analiz için Kafka Streams ve veri sözleşmelerini yönetmek için Schema Registry gibi gelişmiş özellikleri keşfederek olay odaklı mimarinizi daha da güçlendirin.
Share: