Eğitim Portalı/Spring Boot/Spring Boot ile Apache Kafka
Spring Boot03-spring-boot/32-apache-kafka

Spring Boot ile Apache Kafka

> ⚠️ Bu konuda çalıştırılabilir örnek yoktur. Kafka, çalışan bir Kafka broker'ı + ek bağımlılık > gerektirir; portalda çalışmaz. Kod tanıtım amaçlıdır.

Spring Boot ile Apache Kafka

⚠️ Bu konuda çalıştırılabilir örnek yoktur. Kafka, çalışan bir Kafka broker'ı + ek bağımlılık gerektirir; portalda çalışmaz. Kod tanıtım amaçlıdır.

Mikroservisler birbirine iki şekilde bağlanır: senkron (REST çağrısı, topic 16) ve asenkron (mesajlaşma). Asenkron mesajlaşma, servisleri gevşek bağlı kılar: gönderen, alıcının o anda çalışıyor olmasını beklemez; mesajı bir kuyruğa/akışa bırakır, alıcı hazır olunca işler. Apache Kafka, yüksek hacimli olay akışları (event streaming) için en yaygın platformdur; Spring, Spring for Apache Kafka ile bunu kolaylaştırır. (Saga choreography'de — topic 08 — bu mantığı simüle etmiştik.)

Kafka kavramları

  • Topic: Mesajların yayınlandığı isimli kanal (örn. siparis-olaylari).
  • Producer: Topic'e mesaj yayınlayan (publish).
  • Consumer: Topic'ten mesaj okuyan (subscribe).
  • Partition: Topic, paralellik ve ölçek için bölümlere ayrılır.
  • Consumer group: Aynı gruptaki consumer'lar partition'ları paylaşır (yük dengeleme).
  • Offset: Bir consumer'ın bir partition'da nereye kadar okuduğu (kalıcı; tekrar okunabilir).

Kafka'nın farkı: mesajlar kalıcıdır (bir log gibi saklanır), birden çok tüketici aynı veriyi bağımsız okuyabilir, çok yüksek hacme ölçeklenir.

Kurulum

implementation 'org.springframework.kafka:spring-kafka'
spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: siparis-grubu
      auto-offset-reset: earliest

Producer (mesaj yayınlama)

@Service
class SiparisYayinci {
    private final KafkaTemplate<String, String> kafka;
    SiparisYayinci(KafkaTemplate<String, String> kafka) { this.kafka = kafka; }

    void siparisOlustu(String siparisId) {
        kafka.send("siparis-olaylari", siparisId, "OLUSTURULDU");  // topic, key, value
    }
}

Consumer (mesaj dinleme)

@Component
class StokDinleyici {
    @KafkaListener(topics = "siparis-olaylari", groupId = "stok-grubu")
    void dinle(String mesaj) {
        // sipariş olayını işle: stok düş
        System.out.println("Stok servisi olay aldı: " + mesaj);
    }
}

Aynı topic'i birden çok servis (farklı groupId) bağımsız dinleyebilir: stok düşer, fatura kesilir, bildirim gönderilir — gönderen hiçbirini bilmez (gevşek bağ).

Ne zaman Kafka (asenkron) vs REST (senkron)?

Senkron (REST)Asenkron (Kafka)
BağSıkı (alıcı ayakta olmalı)Gevşek (mesaj beklerde durur)
YanıtAnında gerekirGerekmez ("ateşle ve unut")
KullanımSorgu, anlık ihtiyaçOlay yayını, iş kuyruğu, log/metrik akışı
DayanıklılıkAlıcı çökerse istek kaybolurMesaj saklanır, sonra işlenir

Önemli desenler

  • Event-driven mimari: Servisler olaylarla haberleşir (Saga choreography — topic 08).
  • Outbox pattern: "DB'ye yaz + olay yayınla" atomikliğini sağlamak için (topic 08).
  • Idempotency: Kafka mesajı tekrar teslim edilebilir; tüketici aynı mesajı iki kez işlese de sonuç değişmemeli.
  • Dead Letter Topic: İşlenemeyen mesajları ayrı bir topic'e gönderip sonra incele.

Alternatifler

  • RabbitMQ (Spring AMQP): Geleneksel mesaj kuyruğu; yönlendirme esnek, hacim Kafka'dan düşük.
  • Kafka: Yüksek hacimli olay akışı, log/stream işleme, olay kaynağı (event sourcing).

Özet

Asenkron mesajlaşmanın servisleri gevşek bağladığını; Kafka kavramlarını (topic/producer/consumer/ partition/consumer group/offset), Spring Kafka ile producer (KafkaTemplate) ve consumer (@KafkaListener) kurulumunu, senkron-asenkron seçimini ve desenleri (event-driven, outbox, idempotency, DLT) öğrendik; RabbitMQ alternatifine değindik. Sırada, gerçek zamanlı çift yönlü iletişim: WebSocket.