Asenkron İş Kuyruklarında RabbitMQ Yerine Kafka Ne Zaman Seçilmeli: Mimari Değerlendirme Çerçevesi
Blog'a Dön

Asenkron İş Kuyruklarında RabbitMQ Yerine Kafka Ne Zaman Seçilmeli: Mimari Değerlendirme Çerçevesi

Buğra Şıkel

Asenkron İş Kuyruklarında RabbitMQ Yerine Kafka Ne Zaman Seçilmeli: Mimari Değerlendirme Çerçevesi

Giriş

Dağıtık sistem mimarilerinde asenkron iş işleme altyapısı kurarken, genellikle iki ana teknoloji etrafında dönen bir karar süreci yaşanır: AMQP tabanlı mesaj aracıları (RabbitMQ) ve dağıtık log platformları (Apache Kafka). 2010’ların başından beri 1.000 mesaj/saniye ölçeğinden 500.000 mesaj/saniye ölçeğine kadar uzanan geniş bir yelpazede bu iki aracı canlı üretim (production) ortamlarında bizzat yönettim. Sektörde sıklıkla düşülen en kritik hata, bu iki teknolojinin birbirinin doğrudan drop-in alternatifi olarak konumlandırılmasıdır.

Sisteminiz saniyede 15.000 sipariş eventi üretmeye başladığında ve Erlang VM tabanlı RabbitMQ kümeniz bellek (RAM) sınırlarına dayanıp %40 p99 gecikme artışı (20ms’den 180ms’ye) sergilediğinde, basit bir kuyruk yapısından çıkıp append-only (sadece ekleme yapılabilen) dağıtık bir log yapısına geçme ihtiyacını hissedersiniz. RabbitMQ, mesajın tüketiciye iletilmesi ve işlendikten sonra silinmesi üzerine kurulu “Smart Broker / Dumb Consumer” (Zeki Aracı / Aptal Tüketici) modelini benimser. Kafka ise mesajları diske yazıp belirli bir süre (retention period) saklayan, okuma pozisyonunun (offset) tüketici tarafından yönetildiği “Dumb Broker / Smart Consumer” modeline dayanır.

İçindekiler

  • Temel Mimari Farklar: Kuyruk ve Dağıtık Log Yaklaşımları
  • Karar Matrisi ve Değerlendirme Kriterleri
  • “Eğer X ise -> Y” Kural Seti
  • Üretim Ortamı Vakası: Günde 50 Milyon İşlem Taşıyan Sistemin Migrasyonu
  • Konfigürasyon ve Kod Örnekleri
  • Pratik Öneriler / Production Notları
  • Sık Sorulan Sorular
  • Sonuç

Temel Mimari Farklar: Kuyruk ve Dağıtık Log Yaklaşımları

RabbitMQ: Zeki Yönlendirme ve Durum Yönetimi

RabbitMQ, AMQP 0-9-1 protokolünü uygulayan geleneksel bir mesaj aracısıdır. Exchange (Değişim) yapıları (Direct, Topic, Fanout, Headers) sayesinde üretici (producer) mesajı bir kuyruğa değil, bir Exchange’e gönderir. Routing key ve binding kurallarına göre mesaj bir veya birden fazla kuyruğa kopyalanır. Mesajın durumu (state) doğrudan broker üzerinde tutulur. Bir tüketici mesajı alır (pull veya push modeliyle) ve işlemi bitirdiğinde ACK (acknowledgement) gönderir. Broker bu ACK mesajını aldığında veriyi bellekten/diskten siler.

Bu mimari, karmaşık yönlendirme kurallarının uygulandığı ve tekil mesaj işleme sürelerinin (örneğin bir video işleme veya PDF oluşturma görevi) 30 saniye ile 15 dakika arasında değiştiği senaryolarda hayat kurtarır.

Apache Kafka: Sıralı Disk G/Ç ve Olay Kaynaklaması (Event Sourcing)

Kafka ise temelinde TCP üzerinden kendi özel protokolüyle haberleşen bir dağıtık commit log sistemidir. Veri, Topic’ler altında Partition’lara (Bölümlere) ayrılır. Her mesaj partition’ın sonuna eklenir ve ardışık bir sayı olan Offset değerini alır. Kafka mesajları silmez; yapılandırılmış bir retention.ms (saklama süresi) veya retention.bytes (saklama boyutu) limitine ulaşılana kadar diskte tutar.

Kafka’nın asıl yeteneği, Zero-Copy I/O (Sıfır Kopya G/Ç) mimarisi sayesinde mesajları RAM’e almadan doğrudan OS Page Cache üzerinden ağ soketine aktarabilmesidir. Bu özellik, 100.000 mesaj/saniye hacminde bile CPU kullanım oranını %15 seviyelerinde tutmasını sağlar.

Karar Matrisi ve Değerlendirme Kriterleri

Mimari kararlar soyut kavramlar üzerinden değil, ölçülebilir sınırlar üzerinden alınmalıdır. Aşağıdaki matris, tipik bir mikroservis ekosistemindeki karar eşiklerini göstermektedir.

Kriter RabbitMQ (Quorum Queues) Apache Kafka (KRaft Mode)
Mesaj Hacmi (Throughput) ~30.000 – 50.000 msg/sec (Node başına) 1.000.000+ msg/sec (Node başına)
Tüketici Gecikmesi (Latency) p99 < 2ms (Boş kuyrukta) p99 ~ 10-15ms (Batch işlemeler dahil)
Yönlendirme (Routing) Esnekliği Çok yüksek (Exchange, Binding, Header) Düşük (Sadece Topic ve Partition Key)
Geçmişi Tekrar Oynatma (Replay) Desteklenmez (Mesaj ACK sonrası silinir) Doğal destek (Offset sıfırlama ile)
İşlem Süresi Tahmini (Task Duration) Değişken (Milisaniyeden saatlere kadar) Kısa (Tipik olarak < 30-60 saniye)
Tüketici Ölçekleme Limiti Sınırsız (Worker sayısı anında artırılabilir) Partition sayısıyla sınırlıdır (Max parallelism = Partitions)

“Eğer X ise -> Y” Kural Seti

  • Eğer tüketici uygulamanızın bir mesajı işlemesi rastgele süreler (örneğin 2 saniye ile 45 dakika arası) alıyorsa -> RabbitMQ kullanın. Kafka’da uzun süren işlemler max.poll.interval.ms aşımına neden olup sürekli Consumer Group Rebalance (Yeniden Dengeleme) tetikler.
  • Eğer sisteme yeni eklenen bir mikroservisin, geçmişteki son 30 günlük olayları (events) baştan okuması gerekiyorsa (Event Sourcing) -> Kafka kullanın.
  • Eğer yükünüz saniyede 5.000 mesajın altındaysa ve mesajları payload içeriğine (JSON içindeki bir field) göre 15 farklı servise yönlendirmeniz gerekiyorsa -> RabbitMQ kullanın.
  • Eğer log toplama, metrik işleme veya IoT telemetri verisi gibi saniyede yüz binlerce veri noktası alıyor ve bunları batch (toplu) işlemek istiyorsanız -> Kafka kullanın.
  • Eğer mesajların işlenme sırası (Global Ordering) kesinlikle korunmalıysa -> Kafka kullanın. (İlgili varlık ID’sini partition key olarak vererek aynı ID’li mesajların aynı partition’a düşmesini garantilersiniz).

Üretim Ortamı Vakası: Günde 50 Milyon İşlem Taşıyan Sistemin Migrasyonu

2021 yılında uluslararası bir ödeme geçidinde (payment gateway) yaşadığımız darboğaz, bu iki sistem arasındaki geçişin klasik bir örneğidir. Sistem başlangıçta RabbitMQ üzerinde inşa edilmişti. Günlük işlem hacmi 5 milyondan 50 milyona fırladığında, özellikle Black Friday döneminde saniyede 12.000 event barajını aştık.

RabbitMQ kümesi, biriken kuyrukları RAM’den diske yazmaya başladığında (paging), Erlang Garbage Collection süreçleri p99 gecikmelerini 18ms’den 800ms’ye çıkardı. Ödeme onay (webhook) servislerimiz timeout yemeye başladı. Sorunu geçici olarak RabbitMQ node’larına RAM ekleyerek (128GB) çözsek de, kalıcı çözüm mimariyi değiştirmekti.

Log benzeri, geriye dönük sorgulanabilir yapı gerektiren transaction_events, fraud_analysis_streams ve audit_logs topic’lerini Kafka 3.2.0 (KRaft modunda) üzerine taşıdık. Sadece anlık asenkron e-posta gönderimi ve PDF fatura oluşturma işlerini RabbitMQ’da bıraktık. Sonuç:

  • Kafka kümesindeki CPU kullanımı %18 seviyelerinde sabitlendi.
  • Tüketici servislerdeki p99 gecikmesi 800ms’den 12ms’ye kalıcı olarak düştü.
  • RabbitMQ’da kalan iş kuyrukları, IOPS baskısı azaldığı için tekrar 5ms altı yanıt sürelerine döndü.

Konfigürasyon ve Kod Örnekleri

Kafka İçin At-Least-Once (En Az Bir Kere) İşleme Konfigürasyonu

Kafka kullanırken veri kaybını önlemek için otomatik offset commit özelliğini kapatıp, işlem başarılı olduğunda manuel commit yapmalısınız. Aşağıdaki Java (Spring Kafka) örneği, production ortamları için stabil bir konfigürasyondur:

# application.yml (Kafka Consumer Yapılandırması)
spring:
  kafka:
    consumer:
      bootstrap-servers: kafka-broker1:9092,kafka-broker2:9092
      group-id: payment-fraud-validators
      enable-auto-commit: false
      auto-offset-reset: earliest
      max-poll-records: 500
      properties:
        session.timeout.ms: 45000
        max.poll.interval.ms: 300000 # İşlemlerin 5 dakikayı aşmasına izin ver
        isolation.level: read_committed
    listener:
      ack-mode: manual_immediate
// Java Consumer Implementasyonu
@KafkaListener(topics = "transaction_events", groupId = "payment-fraud-validators")
public void processTransaction(ConsumerRecord<String, String> record, Acknowledgment ack) {
    try {
        String transactionId = record.key();
        String payload = record.value();
        
        fraudDetectionService.analyze(transactionId, payload);
        
        // İşlem başarılı, offset'i commit et
        ack.acknowledge();
    } catch (Exception e) {
        // Hata durumunda offset commit edilmez. 
        // Mesaj DLQ'ya atılabilir veya Retry mekanizması tetiklenebilir.
        handleFailure(record, e);
    }
}

RabbitMQ İçin Prefetch Tuning (Performans Optimizasyonu)

RabbitMQ’da tüketici performansını belirleyen en kritik metrik Prefetch Count değeridir. Tüketicinin RAM’ine aynı anda kaç mesaj alınacağını belirler. İşlem süresi 100ms civarındaysa prefetch 50-100 arasında tutulmalıdır. Aşağıdaki Node.js (amqplib) örneği bu ayarı gösterir:

const amqp = require('amqplib');

async function startWorker() {
    const connection = await amqp.connect('amqp://user:pass@rabbitmq-node:5672');
    const channel = await connection.createChannel();
    
    const queue = 'invoice_generation_queue';
    await channel.assertQueue(queue, { durable: true });
    
    // Tüketiciye aynı anda en fazla 20 mesaj gönder (Prefetch Limit)
    await channel.prefetch(20);
    
    channel.consume(queue, async (msg) => {
        if (msg !== null) {
            try {
                await generatePdfInvoice(msg.content.toString());
                // Başarılı işlem sonrası ACK
                channel.ack(msg);
            } catch (error) {
                // Başarısız işlem sonrası NACK, requeue = false ile mesajı DLQ'ya düşür
                channel.nack(msg, false, false);
            }
        }
    });
}

Pratik Öneriler / Production Notları

  • Dead Letter Queue (DLQ) Yönetimi: RabbitMQ’da mesajları x-dead-letter-exchange parametresiyle otomatik DLQ’ya yönlendirmek yerleşik ve kolay bir işlemdir. Kafka’da ise DLQ mantığını uygulama katmanında kurmanız veya Kafka Connect (ya da Spring Kafka’nın SeekToCurrentErrorHandler yapısı) üzerinden manuel ele almanız gerekir.
  • Monitoring (İzleme) Odak Noktaları: RabbitMQ için izlenmesi gereken ana metrikler Memory Paging (Erlang process memory) ve Queue Size olmalıdır. Kafka için ise UnderReplicatedPartitions, ConsumerLag ve disk G/Ç süresi (Disk IO Wait) hayati önem taşır. JMX veya Prometheus Exporter ile bu metrikleri mutlaka Grafana dashboard’larınıza yansıtın.
  • Ağ Bölünmeleri (Network Partitions): RabbitMQ klasik mirroring modunda (Classic Mirrored Queues) split-brain senaryolarına karşı kırılgandır. RabbitMQ 3.8+ kullanıyorsanız kesinlikle Raft konsensüs algoritmasını kullanan Quorum Queues mimarisine geçin. Kafka ise doğası gereği ZooKeeper/KRaft üzerinden cluster state’ini koruduğu için ağ bölünmelerine karşı çok daha dirençlidir.

Sık Sorulan Sorular

RabbitMQ Streams, Kafka’nın yerini tutar mı?

RabbitMQ 3.9 ile gelen Streams özelliği, Kafka’nın append-only log yapısını taklit eder ve 1M+ msg/sec oranlarına ulaşabilir. Ancak Kafka’nın ekosistemi (Kafka Connect, ksqlDB, Schema Registry) ve yıllardır kanıtlanmış disk optimizasyon olgunluğu göz önüne alındığında, sıfırdan stream processing yapılacaksa Kafka hala sektör standardıdır. Mevcut altyapınız sadece RabbitMQ ise ve ek bir teknoloji sokmak istemiyorsanız Streams iyi bir alternatif olabilir.

Kafka’yı basit asenkron işler (Örn: E-posta gönderme) için kullanmak anti-pattern midir?

Eğer Kafka halihazırda altyapınızda kurulu ve bakımını yapan bir ekibiniz varsa, e-posta kuyruğu için Kafka kullanmak anti-pattern değildir. Ancak projeye sırf e-posta kuyruğu için Kafka kümesi dahil etmek, getireceği bakım maliyeti (infrastructure overhead) düşünüldüğünde ciddi bir mühendislik hatasıdır. Bu durumda RabbitMQ veya Redis tabanlı daha hafif çözümler (BullMQ vb.) tercih edilmelidir.

Kafka’da tüketici (consumer) sayısını nasıl ölçeklerim?

RabbitMQ’da istediğiniz an 100 yeni pod ayağa kaldırıp kuyruğu hızlıca eritebilirsiniz. Kafka’da ise maksimum paralel tüketici sayısı, ilgili topic’in partition sayısı kadardır. Topic 12 partition’a sahipse, 13. tüketici boşa (idle) çıkar. Bu nedenle Kafka topic’leri oluşturulurken gelecekteki ölçeklenme ihtiyacı düşünülerek partition sayısı (örn: 24 veya 50) baştan yüksek tutulmalıdır (Over-partitioning).

Sonuç

RabbitMQ ve Kafka arasındaki seçim, birinin diğerinden mutlak üstün olmasıyla değil, sisteminizin I/O profili, veri saklama gereksinimleri ve mesaj işleme alışkanlıklarıyla ilgilidir. Saniye bazında on binlerce kısa ömürlü olay kaydını analiz edip depolamanız gerekiyorsa Kafka’nın disk odaklı ardışık yazma kapasitesine ihtiyacınız vardır. Aksine, karmaşık yönlendirme kuralları içeren, her biri belirsiz sürelerde tamamlanan ve işlem sonrası silinmesi gereken arka plan işlerini yönetiyorsanız RabbitMQ’nun AMQP standartları işinizi çok daha kolaylaştıracaktır.

Aksiyon Adımı: Geçiş veya teknoloji seçimi yapmadan önce mevcut/hedeflenen yükünüzün bir haftalık metriklerini (Mesaj boyutu, P99 işleme süresi, Tüketici sayısındaki dalgalanma) çıkarın. İşleme süresi varyansı %500’ün üzerindeyse RabbitMQ Quorum Queues, throughput (hacim) saniyede 15.000 sınırını zorluyorsa Kafka KRaft mimarisi üzerinde Proof of Concept (PoC) çalışmalarına başlayın.

Bunları da beğenebilirsiniz

ONNX Runtime 1.17 CUDA Provider VRAM Parçalanması ve BFC Arena Optimizasyonu
23 Mayıs 2026

ONNX Runtime 1.17 CUDA Provider VRAM Parçalanması ve BFC Arena Optimizasyonu

Yapay zeka inference altyapılarında karşılaşılan CUDA OOM hatalarının temel nedeni VRAM parçalanmasıdır. ORT 1.17 BFC Arena konfigürasyonu ve trade-off analizi.

Devamını Oku
Dağıtık Sistemlerde Cardinality Explosion: Prometheus ve Mimir ile Maliyet Yönetimi
5 Nisan 2026

Dağıtık Sistemlerde Cardinality Explosion: Prometheus ve Mimir ile Maliyet Yönetimi

Dağıtık sistemlerde metrik maliyetlerini artıran yüksek kardinalite sorununu çözmek ve Prometheus ile Grafana Mimir üzerinden depolama optimizasyonu sağlamak için teknik stratejileri keşfedin.

Devamını Oku
Autoencoder Modelleri için PyTorch mu TensorFlow mu? 2026 Yılı İçin En İyi Seçim
16 Ocak 2026

Autoencoder Modelleri için PyTorch mu TensorFlow mu? 2026 Yılı İçin En İyi Seçim

Derin öğrenme alanında Autoencoder’lar, veri sıkıştırma, anomali tespiti ve özellik öğrenimi gibi birçok kritik görevde kilit rol oynamaktadır. Bu güçlü modelleri eğitirken karşılaşılan temel sorulardan…

Devamını Oku
AI Asistan