Node.js İle Rabbitmq Kullanarak Asenkron Mesaj Kuyruğu Nasıl Yapılır?

Node.js İle Rabbitmq Kullanarak Asenkron Mesaj Kuyruğu Nasıl Yapılır?
Node.js İle Rabbitmq Kullanarak Asenkron Mesaj Kuyruğu Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Çalışmaya başlamadan önce sisteminizde Node.js (LTS sürümü önerilir) ve RabbitMQ sunucusunun kurulu olması gerekir. RabbitMQ, mesajların geçici olarak tutulduğu bir broker görevi görür.

  • Node.js (v20 veya üzeri önerilir).
  • RabbitMQ Sunucusu (Docker üzerinde rabbitmq:3-management imajı ile kolayca ayağa kaldırılabilir).
  • amqplib kütüphanesi: Node.js ile RabbitMQ arasındaki iletişimi sağlayan standart kütüphane.

Projenizi başlatmak için terminalinizde şu komutları çalıştırın:

mkdir rabbitmq-node-app
cd rabbitmq-node-app
npm init -y
npm install amqplib

Bu komutlar, projenizin temel yapılandırmasını oluşturacak ve RabbitMQ ile iletişim kurmamızı sağlayacak amqplib paketini projenize dahil edecektir.

RabbitMQ Temel Kavramları ve Çalışma Mantığı

RabbitMQ'yu verimli kullanmak için temel terimlere hakim olmalısınız. Mesaj kuyruğu yapısı, mesajı gönderen (Producer) ve mesajı işleyen (Consumer) birimlerden oluşur.

Terim Açıklama
Producer Mesajı oluşturan ve kuyruğa gönderen uygulama.
Queue Mesajların saklandığı FIFO (ilk giren ilk çıkar) yapısındaki bellek alanı.
Consumer Kuyruktaki mesajı dinleyen ve işleyen uygulama.
Exchange Mesajların hangi kuyruğa gideceğine karar veren yönlendirici.

Adım Adım Mesaj Gönderici (Producer) Oluşturma

Producer, veriyi RabbitMQ'ya ileten kısımdır. İlk olarak bir bağlantı kurmalı, bir kanal (channel) açmalı ve mesajı ilgili kuyruğa göndermeliyiz.

const amqp = require('amqplib');

async function sendMessage() {
    const connection = await amqp.connect('amqp://localhost');
    const channel = await connection.createChannel();
    const queue = 'task_queue';
    const msg = 'Merhaba, bu bir asenkron mesajdır!';

    await channel.assertQueue(queue, { durable: true });
    channel.sendToQueue(queue, Buffer.from(msg), { persistent: true });

    console.log("Mesaj gönderildi:", msg);
    setTimeout(() => { connection.close(); }, 500);
}

sendMessage();

Burada durable: true parametresi, RabbitMQ sunucusu yeniden başlatılsa bile kuyruğun silinmemesini sağlar. persistent: true ise mesajın diskte saklanmasını garanti altına alır.

Adım Adım Mesaj İşleyici (Consumer) Oluşturma

Consumer, kuyruğu sürekli dinleyerek yeni bir mesaj geldiğinde onu işler. Mesaj başarıyla işlendikten sonra RabbitMQ'ya "mesajı aldım ve işledim" bilgisini (ack) göndermeliyiz.

const amqp = require('amqplib');

async function consumeMessages() {
    const connection = await amqp.connect('amqp://localhost');
    const channel = await connection.createChannel();
    const queue = 'task_queue';

    await channel.assertQueue(queue, { durable: true });
    channel.prefetch(1); // Aynı anda sadece 1 mesaj işle

    console.log("Mesajlar bekleniyor...");

    channel.consume(queue, (msg) => {
        console.log("Alınan mesaj:", msg.content.toString());
        setTimeout(() => {
            channel.ack(msg); // İşlemin bittiğini onayla
        }, 1000);
    }, { noAck: false });
}

consumeMessages();

channel.prefetch(1) kullanımı, bir consumer mesajı tam olarak işleyip onay (ack) gönderene kadar ona yeni mesaj verilmemesini sağlar. Bu, yük dengelemesi için hayati önem taşır.

Hata Yönetimi ve Güvenlik

Mesaj kuyruklarında en büyük risk, işlenemeyen mesajların kaybolması veya sistemin kilitlenmesidir. "Dead Letter Exchange" (DLX) yapısı kullanarak hatalı mesajları ayrı bir kuyruğa yönlendirebilirsiniz.

Kritik Uyarı: Üretim ortamında (production) RabbitMQ bağlantı bilgilerinizi (kullanıcı adı ve şifre) asla kod içerisinde açık metin olarak bulundurmayın. Ortam değişkenlerini (dotenv paketi ile) kullanın ve bağlantı hatalarını try-catch blokları ile yöneterek uygulamanın çökmesini engelleyin.

Aşağıdaki kod örneğinde bağlantı kopmaları için temel bir hata yönetimi gösterilmiştir:

try {
    const connection = await amqp.connect('amqp://user:password@localhost');
} catch (error) {
    console.error("RabbitMQ bağlantı hatası:", error.message);
    process.exit(1);
}

Sıkça Sorulan Sorular

RabbitMQ ile Redis Pub/Sub arasındaki fark nedir?

Redis Pub/Sub mesajları geçici olarak iletir ve alıcı çevrimdışıysa mesaj kaybolur. RabbitMQ ise mesajları kuyrukta tutar, alıcı müsait olduğunda iletir; bu da onu görev kuyrukları için daha güvenilir kılar.

Mesajlar neden işlenmiyor?

Genellikle channel.ack(msg) unutulmuştur. Eğer onay göndermezseniz, RabbitMQ mesajın işlenmediğini düşünür ve mesaj kuyrukta "unacked" durumunda takılı kalır.

Birden fazla Consumer çalıştırabilir miyim?

Evet, aynı kuyruğu dinleyen birden fazla Node.js süreci çalıştırarak iş yükünü dağıtabilirsiniz. RabbitMQ mesajları Round-Robin yöntemiyle consumer'lar arasında paylaştırır.

Mesajlar diskte mi tutulur?

Kuyruğu durable olarak tanımlarsanız ve mesajı persistent olarak gönderirseniz, RabbitMQ mesajları diske yazar.

Node.js uygulamasında performans kaybı yaşanır mı?

Asenkron yapısı sayesinde RabbitMQ, Node.js'in event-loop mekanizmasıyla mükemmel uyum sağlar. Ancak çok yoğun mesaj trafiğinde bağlantı havuzlarını (connection pooling) yönetmeniz gerekebilir.

RabbitMQ ile İleri Seviye Mesaj Yönlendirme: Exchange Tipleri

Temel kuyruk yapısının ötesine geçmek istediğinizde, RabbitMQ'nun sunduğu Exchange (Değiştirici) mekanizmalarını anlamak kritiktir. Mesajların doğrudan kuyruğa gitmesi yerine, bir Exchange üzerinden belirli kurallara göre dağıtılması, mikroservis mimarilerinde esneklik sağlar.

Direct, Fanout ve Topic Exchange Kullanımı

Exchange tipleri, mesajın hangi kuyruğa iletileceğini belirleyen "routing key" mantığını yönetir:

  • Direct: Mesaj, routing key ile kuyruk ismi tam eşleşirse iletilir.
  • Fanout: Mesaj, kendisine bağlı tüm kuyruklara kopyalanır. Yayın/Abone (Pub/Sub) modeli için idealdir.
  • Topic: Routing key üzerinde joker karakterler (wildcard) kullanarak mesajları filtrelemenize olanak tanır.

Aşağıdaki örnekte, bir topic exchange kullanarak mesajları kategorize etmeyi görebilirsiniz:

// Mesaj gönderici (Producer) - Topic Exchange
const exchange = 'logs_topic';
const args = process.argv.slice(2);
const key = (args.length > 0) ? args[0] : 'anonymous.info';
const msg = args.slice(1).join(' ') || 'Merhaba Dünya!';

await channel.assertExchange(exchange, 'topic', { durable: false });
channel.publish(exchange, key, Buffer.from(msg));
console.log(" [x] Gönderildi: '%s':'%s'", key, msg);

RabbitMQ Mesaj İşleme Performansını Optimize Etme

Node.js uygulamalarında yüksek trafik altında RabbitMQ kullanırken, darboğazları önlemek için bazı optimizasyon tekniklerini uygulamanız gerekir. Özellikle mesaj işleme hızını artırmak için Prefetch Count ayarı hayati önem taşır.

Prefetch Count (QoS) Ayarının Önemi

Varsayılan olarak RabbitMQ, tüm mesajları aynı anda tüm consumer'lara dağıtmaya çalışır. Ancak, bir consumer'ın aynı anda kaç mesajı işleyebileceğini sınırlamak, sistemin çökmesini engeller. prefetch(1) ayarı, bir mesaj işlenip onaylanmadan (ack) consumer'a yeni mesaj gönderilmemesini sağlar.

// Consumer tarafında performans optimizasyonu
channel.prefetch(1); // Aynı anda sadece 1 mesajı işle

channel.consume(queue, (msg) => {
  const secs = msg.content.toString().split('.').length - 1;
  
  setTimeout(() => {
    console.log(" [x] İşlem tamamlandı");
    channel.ack(msg); // İşlem bittiğinde onay gönder
  }, secs * 1000);
}, { noAck: false });

Performans İçin İpuçları

Teknik Fayda
Persistent Mesajlar Sunucu yeniden başlatıldığında mesaj kaybını önler.
Bağlantı Havuzu Her istek için yeni bağlantı açmak yerine mevcut bağlantıyı yeniden kullanın.
Batching Küçük mesajları tek bir büyük paket halinde göndererek ağ trafiğini azaltın.

Unutmayın, RabbitMQ üzerinde çok fazla kuyruk oluşturmak bellek kullanımını artırabilir. İhtiyaç duymadığınız kuyrukları auto-delete özelliği ile otomatik olarak temizlenmesini sağlayarak sistem kaynaklarını verimli kullanabilirsiniz.

Sonuç

Node.js ile RabbitMQ kullanarak asenkron mesaj kuyruğu mimarisini kurmak, uygulamanızın ölçeklenebilirliğini doğrudan artırır. Bu rehberde, temel bağlantı kurma, mesaj gönderme ve işleme süreçlerini öğrendiniz. Bir sonraki adım olarak, "Exchange" tiplerini (Fanout, Direct, Topic) araştırarak mesajlarınızın daha karmaşık kurallarla yönlendirilmesini sağlayabilirsiniz. Yazılım geliştirme süreçlerinizde her zaman hata toleransını ön planda tutmayı unutmayın.

Yasal Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Ticari projelerinizde kullanmadan önce güvenlik denetimlerini yapmalı, bağlantı şifrelerini güvenli bir şekilde yönetmeli ve sisteminizin ihtiyaçlarına göre yapılandırmalısınız.

Bu yazıya tepkinizi paylaşın:
Mert Demir

Hobi projeleri, küçük tamirat işleri ve bahçe bakımı konusunda deneyimli bir editörüm. Adım adım rehberlerimle okuyucularımın özgüvenli bir şekilde yeni beceriler kazanmasını amaçlıyorum.

Yorumlar (17)

17
okuyucu bu yazı hakkında yorum yaptı. Siz de deneyiminizi paylaşarak diğer okuyuculara yardımcı olabilirsiniz.
Caner Yılmaz
Caner Yılmaz 31 Temmuz 2026

Eline sağlık Mert, tam da aradığım konuydu. Özellikle producer-consumer mantığını çok sade anlatmışsın.

Mert Demir
Mert Demir 02 Ağustos 2026

Teşekkür ederim Caner, faydalı olmasına sevindim.

Selin Kaya
Selin Kaya 02 Ağustos 2026

Ya ben kodları denedim ama bağlantı hatası alıyorum. Docker üzerinde ayağa kaldırdım halbuki, bir bilgin var mı?

Burak Özdemir
Burak Özdemir 02 Ağustos 2026

Docker'da portları dışarı açtığından emin misin? Genelde 5672 portunda sorun oluyo.

Mehmet Arı
Mehmet Arı 02 Ağustos 2026

RabbitMQ yerine Redis kullansak daha iyi olmaz mı? Çok daha hafif bir çözüm değil mi sizce?

Mert Demir
Mert Demir 03 Ağustos 2026

Redis Pub/Sub için harikadır ama kalıcılık ve karmaşık routing kuralları gerekiyorsa RabbitMQ hala çok daha güvenli bir tercih.

Zeynep Doğan
Zeynep Doğan 03 Ağustos 2026

Anlatım gayet güzel olmuş. Okurken hiç sıkılmadım, sade ve net. Başarılar.

Hakan Şahin
Hakan Şahin 04 Ağustos 2026

Asenkron mimaride en büyük sorun mesajın kaybolması. Onu nasıl handle ediyoruz, bir sonraki yazıda bahseder misin?

Mert Demir
Mert Demir 06 Ağustos 2026

Haklısın, ACK (Acknowledgement) mekanizmasını bir sonraki yazıda detaylıca ele alacağım.

Emre Can
Emre Can 05 Ağustos 2026

Kodları kopyaladım ama çalışmadı ya, eksik bişey mi var acaba? bide node versiyonu farkeder mi?

Mert Demir
Mert Demir 05 Ağustos 2026

Node sürümü çok fark etmez ama amqp kütüphanesinin güncel olduğundan emin ol, bir de bağlantı string'ini kontrol et.

Ahmet Çelik
Ahmet Çelik 05 Ağustos 2026

abi süpersin valla, saatlerdir bunu arıyodum. kafamdaki çoğu soru işareti gitti şu an.

Gökhan Tan
Gökhan Tan 07 Ağustos 2026

aynen, harika bi anlatım olmuş, eline sağlık.

Deniz Yıldız
Deniz Yıldız 05 Ağustos 2026

Çok açıklayıcı bir yazı, teşekkürler. Özellikle exchange türlerine de değinmen süper olmuş.

Kaan Yıldırım
Kaan Yıldırım 06 Ağustos 2026

Yazı güzel ama keşke bir de örnek repo linki bıraksaydın hocam, github'da görmemiz daha iyi olurdu.

Mert Demir
Mert Demir 07 Ağustos 2026

Haklısın Kaan, kodları GitHub hesabıma yükledim, yazının sonuna linki ekliyorum.

Elifnur B.
Elifnur B. 06 Ağustos 2026

Bu yapı ölçeklenebilir mi? Yani trafik çok artarsa ne yapmamız lazım?

Yorum Yaz