Apache Kafka'ya Giriş: Temel Kavramlar ve Producer

## Apache Kafka'ya Giriş: Temel Kavramlar Kafka, olayları (event) kalıcı bir log yapısında saklayan dağıtık bir akış platformudur. Geleneksel mesaj k...

Apache Kafka'ya Giriş: Temel Kavramlar ve Producer

Apache Kafka'ya Giriş: Temel Kavramlar

Kafka, olayları (event) kalıcı bir log yapısında saklayan dağıtık bir akış platformudur. Geleneksel mesaj kuyruklarından temel farkı, tüketicilerin mesajı okuduktan sonra silinmemesidir; mesajlar yapılandırılabilir bir saklama süresi boyunca diskte kalır. Bu sayede aynı veri birden fazla bağımsız uygulama tarafından, farklı hızlarda okunabilir.

Temel kavramlar:

  • Broker: Kafka sunucusu. Bir küme (cluster) birden fazla broker'dan oluşur.
  • Topic: Mesajların yayımlandığı mantıksal kanal.
  • Partition: Topic'in bölündüğü sıralı, değiştirilemez log parçaları. Sıralama garantisi partition düzeyindedir, topic genelinde değil.
  • Producer: Mesajı bir topic'e yazan uygulama.
  • Consumer: Mesajı okuyan uygulama.
  • Consumer Group: Aynı topic'i paylaşarak okuyan tüketici grubu; her partition gruptaki tek bir tüketiciye atanır.
  • Offset: Bir partition içindeki mesajın konumunu belirten artan sayı.

Ortam ve Sürüm Kapsamı

Aşağıdaki örnekler Kafka 3.x ve 4.x istemci API'leriyle uyumludur; Java istemcisi kullanılır. Yerel deneme için tek düğümlü bir broker yeterlidir. Üretimde en az üç broker ve replication.factor=3 önerilir.

Önkoşullar: JDK 17 veya üzeri, çalışan bir Kafka broker'ı ve bootstrap.servers adresi. Sürüm numarası vermediğim yapılandırma anahtarları Kafka'nın uzun süredir koruduğu isimlerdir; kendi ortamınızda kafka-configs veya resmi belgelerle doğrulayın.

Producer: Mesaj Yazma

import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;

Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.ACKS_CONFIG, "all");
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "true");

try (Producer<String, String> producer = new KafkaProducer<>(props)) {
    ProducerRecord<String, String> record =
        new ProducerRecord<>("siparisler", "siparis-42", "{\"durum\":\"olusturuldu\"}");
    producer.send(record, (metadata, exception) -> {
        if (exception != null) {
            // yeniden deneme veya dead-letter stratejisi
        } else {
            System.out.println(metadata.topic() + "-" + metadata.partition()
                + "@" + metadata.offset());
        }
    });
}

Beklenen davranış: acks=all ile producer, mesajın atanan tüm replikalara yazıldığını onaylayana kadar bekler. enable.idempotence=true ayarı, ağ kaynaklı yeniden denemelerde aynı mesajın partition'a iki kez yazılmasını engeller. Aynı anahtar (siparis-42) her zaman aynı partition'a gider; bu, anahtar bazlı sıralama sağlar.

Yaygın hata: acks=1 veya acks=0 ile üretimde veri kaybı yaşanabilir. Lider broker onayı verip çökerse, replikalara kopyalanmamış mesaj kaybolur. Idempotence'ı açmadan retries değerini yükseltmek de yinelenen mesaj üretir.

Consumer: Mesaj Okuma

import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.*;

Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "siparis-isleyici");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

try (Consumer<String, String> consumer = new KafkaConsumer<>(props)) {
    consumer.subscribe(List.of("siparisler"));
    while (true) {
        ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(500));
        for (ConsumerRecord<String, String> record : records) {
            isle(record.value());
        }
        consumer.commitSync();
    }
}

Beklenen davranış: enable.auto.commit=false ile offset, işleme başarıyla tamamlandıktan sonra elle taahhüt edilir. auto.offset.reset=earliest, grubun daha önce offset taahhüt etmediği durumda partition'ın başından okumaya başlar.

Yaygın hata: Otomatik commit açıkken poll aralığında işleme çökerse, işlenmemiş mesajlar "işlenmiş" sayılır ve kaybolur. Ayrıca max.poll.interval.ms süresini aşan uzun işlemler, tüketicinin gruptan atılmasına ve partition'ın başka bir tüketiciye geçmesine yol açar.

Partition ve Paralellik

Bir topic'in partition sayısı, o topic'te ulaşılabilecek maksimum paralel tüketici sayısını belirler. Gruptaki fazla tüketiciler boşta bekler. Partition sayısı artırılabilir ama azaltılamaz; artırma işlemi anahtar bazlı partition atamasını değiştirdiği için mevcut anahtarların yeni partition'a kaymasına neden olur. Bu nedenle partition sayısını baştan gerçekçi bir üst sınıra göre seçin.

Teslim Garantileri

  • At-most-once: Offset, işleme öncesi taahhüt edilir. Çökme durumunda mesaj kaybolabilir.
  • At-least-once: Offset, işleme sonrası taahhüt edilir. Çökme durumunda mesaj yeniden işlenebilir; işleme tarafı idempotent olmalıdır.
  • Exactly-once: Kafka işlemleri (transaction) ve idempotent producer ile sağlanır. Producer tarafında transactional.id tanımlanır, initTransactions, beginTransaction, commitTransaction çağrıları kullanılır. Tüketici tarafında isolation.level=read_committed ayarlanmalıdır; aksi halde taahhüt edilmemiş mesajlar da okunur.

Güvenlik

Varsayılan Kafka yapılandırması kimlik doğrulama ve şifreleme içermez. Üretimde en az şunlar uygulanmalıdır:

  • TLS: Broker ile istemci arasındaki trafiği şifreler. security.protocol=SSL veya SASL_SSL ile etkinleştirilir.
  • SASL: Kimlik doğrulama. SASL/SCRAM veya SASL/GSSAPI (Kerberos) yaygın seçeneklerdir.
  • ACL: Topic ve grup düzeyinde yetkilendirme. Varsayılan olarak her istemci her topic'e erişebilir; authorizer.class.name ayarlanmadan bu değişmez.
  • Şifre yönetimi: SASL parolalarını kod içine gömmeyin; ortam değişkeni veya bir sır yönetim sisteminden okuyun.

İzleme ve Operasyon

Temel metrikler: partition başına gecikme (consumer lag), üretim/tüketim hızı, ISR (in-sync replica) sayısı, aktif denetleyici (controller) sayısı. Consumer lag sürekli artıyorsa ya tüketici yavaş ya da partition sayısı yetersizdir. ISR sayısının replika faktörünün altına düşmesi, broker arızasına veya disk/ağ gecikmesine işaret eder.

Sonuç

Kafka'yı doğru kullanmanın özü üç karara dayanır: partition sayısını ve anahtar stratejisini baştan doğru seçmek, teslim garantisini iş gereksinimine göre belirleyip tüketici tarafını buna uygun (idempotent veya işlemsel) yazmak, ve güvenlik katmanını üretime çıkmadan önce etkinleştirmek. Bu üç nokta oturduğunda ölçek büyütmek çoğunlukla broker ve partition eklemekten ibarettir.

İLGİLİ İÇERİKLER

Bunları da Okumak İsteyebilirsiniz