Docker & DevOps

    RabbitMQ Kurulumu ve Kuyruk Yönetimi

    RabbitMQ kurulumu, exchange-kuyruk mantığı ve üretimde dayanıklı kuyruk yönetimi.

    11 dk okuma Güncellendi: 25 Ağustos 2026

    Kullanıcı sipariş verdiğinde fatura PDF'i üretilecek, e-posta gidecek, muhasebe sistemine kayıt düşecek. Bunların üçünü de HTTP isteğinin içinde yaparsan kullanıcı sekiz saniye bekler, e-posta sağlayıcısı yavaşladığında sipariş ekranı donar ve bir adım patlarsa diğerlerinin ne olduğunu kimse bilmez. RabbitMQ kurulumu tam olarak bu problemi çözmek için yapılır: işi kabul et, kuyruğa at, kullanıcıya hemen cevap ver, ağır işi arka planda bir işçi (worker) yapsın.

    Bu rehberde RabbitMQ'yu Ubuntu üzerine ve Docker ile kuracağız, exchange–kuyruk–binding üçlüsünün gerçekte nasıl çalıştığını örneklerle çözeceğiz, mesajların kaybolmamasını sağlayan onay (ack) ve dayanıklılık ayarlarını yapacağız, ölü mektup kuyruğuyla başarısız işleri güvenli bir yere alacağız. En sonda da üretimde en çok can yakan tuzakları — sınırsız büyüyen kuyruklar, prefetch hatası ve sonsuz yeniden deneme döngüsü — tek tek konuşacağız.

    RabbitMQ Ne Zaman Doğru Araçtır#

    RabbitMQ bir mesaj brokeridir; yani üretici (producer) ile tüketici (consumer) arasında duran, mesajları güvenle saklayıp doğru alıcıya teslim eden bir aracı. Güçlü olduğu senaryo, her mesajın tek bir işçi tarafından bir kez işlenmesi gereken görev dağıtımıdır: e-posta gönderme, görsel küçültme, rapor üretme, dış API'ye senkron kuyruğu. Bir mesaj alındığında işlenir, onaylanır ve silinir. Bu davranışa "iş kuyruğu" (work queue) denir.

    Kafka gibi log tabanlı sistemlerle karıştırılır ama tasarım hedefleri farklıdır. Kafka mesajı bir kayıt defterine yazar ve birden çok tüketici grubu aynı kaydı bağımsız olarak okur; RabbitMQ ise mesajı teslim edip siler. Aradaki farkı ve hangi durumda hangisini seçmen gerektiğini Apache Kafka nedir yazısında ayrıntılı karşılaştırıyorum. Kabaca kural şudur: görev dağıtıyorsan RabbitMQ, olay akışı biriktiriyorsan Kafka. Zamanlanmış işlerle kuyruk arasındaki seçim ise ayrı bir konudur ve cron mu job queue mu yazısında ele aldım.

    RabbitMQ'nun sana verdiği asıl şey esneklikten çok geri basınç (backpressure) yönetimidir. E-posta servisin dakikada 100 mesaj kaldırabiliyorsa, ani bir kampanyada gelen 50.000 istek uygulamayı çökertmez; kuyrukta birikir ve işçiler kendi hızlarında tüketir. Kullanıcı bunu hiç hissetmez.

    Ubuntu Üzerine RabbitMQ Kurulumu#

    RabbitMQ Erlang üzerinde çalışır, bu yüzden dağıtımın deposundaki sürüm çoğu zaman geridedir. Üretimde resmi depoyu kullanmak daha sağlıklıdır ama hızlı başlangıç için dağıtım paketi de iş görür.

    # Depoları güncelle ve RabbitMQ sunucusunu kur
    sudo apt update
    sudo apt install -y rabbitmq-server
    
    # Servisi başlat ve açılışta otomatik başlamasını sağla
    sudo systemctl enable --now rabbitmq-server
    sudo systemctl status rabbitmq-server --no-pager
    
    # Web yönetim arayüzü eklentisini aç (15672 portunda çalışır)
    sudo rabbitmq-plugins enable rabbitmq_management
    

    Kurulumdan sonraki ilk iş varsayılan guest kullanıcısını devre dışı bırakmaktır. guest yalnızca localhost'tan bağlanabilir ama yönetim arayüzünü dışa açtığın anda bu bir zafiyete dönüşür. Kendi yönetici kullanıcını oluştur:

    # Yönetici kullanıcı oluştur (parolayı kendi ürettiğinle değiştir)
    sudo rabbitmqctl add_user uygulama 'GucluBirParola123!'
    sudo rabbitmqctl set_user_tags uygulama administrator
    
    # Uygulamaya özel bir sanal host aç ve tam yetki ver
    sudo rabbitmqctl add_vhost /uretim
    sudo rabbitmqctl set_permissions -p /uretim uygulama ".*" ".*" ".*"
    
    # Varsayılan guest kullanıcısını sil
    sudo rabbitmqctl delete_user guest
    
    # Kullanıcıları ve vhost'ları doğrula
    sudo rabbitmqctl list_users
    sudo rabbitmqctl list_vhosts
    

    Parolayı elle uydurma; şifre üretici aracıyla uzun ve rastgele bir değer üret. Yönetim arayüzü http://sunucu-ip:15672 adresinde açılır ama bu portu asla doğrudan internete açma. Ya SSH tüneli üzerinden eriş ya da bir ters proxy arkasına alıp kimlik doğrulaması ekle.

    PortNe içinDışa açılmalı mı
    5672AMQP istemci bağlantısı (şifresiz)Hayır, yalnızca iç ağ
    5671AMQP over TLSGerekiyorsa evet
    15672Yönetim arayüzü ve HTTP APIHayır, tünel veya proxy
    25672Küme (cluster) düğüm iletişimiKesinlikle hayır
    4369epmd, düğüm keşfiKesinlikle hayır

    Docker ile Hızlı Kurulum ve Kalıcı Veri#

    Geliştirme ortamında ya da konteyner tabanlı bir mimaride RabbitMQ'yu Docker ile ayağa kaldırmak çok daha pratiktir. Kritik nokta veriyi kalıcı hale getirmektir; aksi halde konteyner yeniden oluşturulduğunda kuyruklarınla birlikte bekleyen mesajlar da gider.

    services:
      rabbitmq:
        image: rabbitmq:3-management
        hostname: rabbit-1          # ÖNEMLİ: veri dizini hostname'e göre isimlenir
        restart: unless-stopped
        environment:
          RABBITMQ_DEFAULT_USER: uygulama
          RABBITMQ_DEFAULT_PASS: GucluBirParola123!
          RABBITMQ_DEFAULT_VHOST: /uretim
        ports:
          - "127.0.0.1:5672:5672"    # yalnızca localhost'a bağla
          - "127.0.0.1:15672:15672"
        volumes:
          - rabbit_veri:/var/lib/rabbitmq
        healthcheck:
          test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
          interval: 20s
          timeout: 10s
          retries: 5
    
    volumes:
      rabbit_veri:
    

    hostname satırını atlamak, bu kurulumdaki en sinsi hatadır. RabbitMQ veri dizinini düğüm adına göre (/var/lib/rabbitmq/mnesia/rabbit@<hostname>) oluşturur; Docker her yeniden oluşturmada rastgele bir hostname verirse, birim (volume) yerinde durduğu halde RabbitMQ boş bir düğüm gibi açılır ve eski kuyrukların "kaybolur". Sabit bir hostname verdiğinde bu sorun ortadan kalkar. Birim yönetiminin ayrıntıları için Docker volume veri yönetimi yazısına, çok servisli kurulumun geneli için Docker Compose kullanımı rehberine bakabilirsin.

    Exchange, Kuyruk ve Binding Mantığı#

    RabbitMQ'da üretici mesajı kuyruğa göndermez, bir exchange'e gönderir. Exchange, kendisine bağlı kuyruklara mesajı hangi kurala göre dağıtacağına karar verir. Bu dolaylılık ilk bakışta gereksiz görünür ama tüm esnekliğin kaynağıdır: tüketici tarafını hiç değiştirmeden yeni bir dinleyici eklemeni sağlar.

    Exchange tipiDağıtım kuralıTipik kullanım
    directrouting key birebir eşleşirİş kuyruğu, öncelik ayrımı
    topicsiparis.*.iptal gibi desen eşleşmesiOlay yayını, esnek abonelik
    fanoutrouting key yok sayılır, herkese giderÖnbellek temizleme yayını
    headersbaşlık değerlerine göre eşleşirNadir, karmaşık yönlendirme

    Pratik bir örnek kuralım: siparişle ilgili olaylar siparis adında bir topic exchange'e gidiyor. Fatura servisi yalnızca siparis.olusturuldu, bildirim servisi ise tüm sipariş olaylarını dinliyor.

    # Exchange oluştur (kalıcı, yeniden başlatmada silinmez)
    sudo rabbitmqadmin -V /uretim declare exchange name=siparis type=topic durable=true
    
    # İki ayrı kuyruk oluştur
    sudo rabbitmqadmin -V /uretim declare queue name=fatura_isleri durable=true
    sudo rabbitmqadmin -V /uretim declare queue name=bildirim_isleri durable=true
    
    # Kuyrukları exchange'e bağla (binding)
    sudo rabbitmqadmin -V /uretim declare binding source=siparis \
      destination=fatura_isleri routing_key=siparis.olusturuldu
    sudo rabbitmqadmin -V /uretim declare binding source=siparis \
      destination=bildirim_isleri routing_key="siparis.#"
    
    # Sonucu doğrula
    sudo rabbitmqctl list_queues -p /uretim name messages consumers
    sudo rabbitmqctl list_bindings -p /uretim
    

    siparis.# deseninde # sıfır veya daha fazla kelimeyi, * ise tam olarak bir kelimeyi karşılar. Yani siparis.olusturuldu ve siparis.kargo.cikti her ikisi de bildirim kuyruğuna düşer, fatura kuyruğuna yalnızca ilki gider. Yarın "sipariş iptal edildiğinde SMS at" ihtiyacı çıktığında yeni bir kuyruk açıp siparis.iptal ile bağlarsın; üretici kodunda tek satır değişmez.

    Mesaj Onayı, Prefetch ve Dayanıklılık#

    Varsayılan ayarlarla RabbitMQ mesajları belleğe alır ve teslim eder etmez unutur. Üretimde bu kabul edilemez; üç ayarı birlikte açman gerekir.

    1. Kalıcı kuyruk ve kalıcı mesaj. Kuyruğu durable=true ile oluşturmak yalnızca kuyruğun tanımını kalıcı yapar. Mesajların da diske yazılması için üreticinin her mesajı delivery_mode=2 (persistent) ile göndermesi gerekir. İkisi birlikte olmazsa broker yeniden başladığında kuyruk durur ama içi boşalır.

    2. Manuel onay (manual ack). Tüketici mesajı aldığı anda değil, işi bitirdiğinde onay göndermelidir. Otomatik onay modunda işçi mesajı alır almaz RabbitMQ onu siler; işçi bir saniye sonra çökerse iş kaybolur. Manuel onayda ise bağlantı koparsa mesaj kuyruğa geri döner ve başka bir işçiye verilir.

    3. Prefetch (QoS) sınırı. Bu, en çok yanlış yapılan ayardır. Varsayılanda RabbitMQ bir işçiye kuyruktaki tüm mesajları peş peşe iter. Üç işçin varsa ve ilki 1000 mesajı üzerine alırsa, diğer ikisi boş boş bekler; ilk işçi çökerse 1000 mesaj aynı anda yeniden dağıtılır.

    # Python (pika) tarafında doğru tüketici kurgusu — kavramsal örnek
    # kanal.basic_qos(prefetch_count=10)      -> aynı anda en fazla 10 iş
    # kanal.basic_consume(kuyruk, auto_ack=False)
    # iş bitince: kanal.basic_ack(delivery_tag=...)
    # iş kalıcı olarak başarısızsa: kanal.basic_nack(requeue=False)  -> DLQ'ya düşer
    

    Prefetch değeri için pratik kural: işler kısa ve tek tipse 10–50 arası iyi bir başlangıçtır; işler uzun sürüyorsa (birkaç saniye ve üzeri) 1 yap. 1 değeri işçiler arasında adil dağıtım sağlar ve bir işçinin diğerlerini aç bırakmasını engeller. Ölçemediğin bir değeri büyütme; kuyruk boşalmıyorsa sorun genelde prefetch değil, işçi sayısıdır.

    Ölü Mektup Kuyruğu ve Yeniden Deneme Stratejisi#

    Bir mesaj işlenemiyorsa ne olacak? Doğal refleks "tekrar dene"dir ama bunu kontrolsüz yaparsan sonsuz döngü kurarsın: mesaj başarısız olur, kuyruğa döner, yine başarısız olur ve CPU'yu yiyip bitirir. Doğru yapı ölü mektup kuyruğu (dead letter queue, DLQ) kurmaktır.

    # Önce ölü mektupların toplanacağı kuyruk
    sudo rabbitmqadmin -V /uretim declare queue name=fatura_isleri_dlq durable=true
    
    # Ana kuyruğu, reddedilen mesajları DLQ'ya atacak şekilde tanımla
    sudo rabbitmqadmin -V /uretim declare queue name=fatura_isleri durable=true \
      'arguments={"x-dead-letter-exchange":"", 
                  "x-dead-letter-routing-key":"fatura_isleri_dlq",
                  "x-message-ttl":600000,
                  "x-max-length":100000}'
    

    Buradaki dört argümanın her biri ayrı bir kazadan koruyor. x-dead-letter-* ikilisi, basic_nack(requeue=False) ile reddedilen ya da süresi dolan mesajları sessizce kaybetmek yerine DLQ'ya taşıyor. x-message-ttl bir mesajın kuyrukta en fazla 10 dakika bekleyebileceğini söylüyor — sonrasında DLQ'ya düşüyor. x-max-length ise kuyruğun sınırsız büyümesini engelliyor; bu sınır olmadan bir tüketici arızası diski doldurup broker'ı tamamen durdurabilir.

    Yeniden deneme için önerdiğim düzen şudur: tüketici işi 3 kez dener, aralarında artan bir bekleme koyar (1 sn, 5 sn, 30 sn), üçüncüde de olmazsa requeue=False ile reddeder ve mesaj DLQ'ya gider. DLQ'yu günlük olarak kontrol edersin; oradaki mesajlar bir hata raporu gibidir. Düzelttikten sonra rabbitmqadmin ya da yönetim arayüzündeki "Move messages" özelliğiyle mesajları ana kuyruğa geri gönderebilirsin.

    Üretimde İzleme, Sık Hatalar ve Tuzaklar#

    Kuyruk uzunluğunu izlemiyorsun. İzlemen gereken tek metrik varsa o da messages_ready sayısıdır. Bu sayı sürekli artıyorsa tüketiciler üretim hızına yetişemiyordur ve er ya da geç disk dolar. Basit bir kontrol komutu:

    # Kuyruk derinliği, bekleyen onaysız mesaj ve tüketici sayısı
    sudo rabbitmqctl list_queues -p /uretim name messages_ready messages_unacknowledged consumers
    
    # Düğüm sağlığı, bellek ve disk alarmı durumu
    sudo rabbitmq-diagnostics status
    sudo rabbitmq-diagnostics check_running
    sudo rabbitmq-diagnostics alarms
    

    Bellek ve disk alarmlarını bilmiyorsun. RabbitMQ bellek kullanımı eşiği (varsayılan olarak RAM'in %40'ı) aştığında ya da boş disk alanı disk_free_limit altına düştüğünde üreticileri bloklar. Uygulaman aniden "mesaj gönderemiyorum" der ve broker loglarında memory resource limit alarm set satırını görürsün. Bu bir arıza değil, koruma mekanizmasıdır; çözüm kuyruğu boşaltmak ya da kaynağı artırmaktır.

    Bağlantıyı her mesajda açıp kapatıyorsun. AMQP bağlantısı kurmak pahalıdır (TCP + TLS + kimlik doğrulama). Doğru desen, uygulama başlarken bir bağlantı açmak ve içinde işçi başına birer kanal (channel) kullanmaktır. Kanal ucuzdur, bağlantı değildir. Her HTTP isteğinde yeni bağlantı açan bir uygulama, orta yükte broker'daki dosya tanıtıcılarını tüketir.

    Tek düğüm çalıştırıp yüksek erişilebilirlik sanıyorsun. Tek RabbitMQ düğümü düşerse kuyruk durur. Gerçek dayanıklılık için en az üç düğümlü bir küme ve quorum kuyrukları gerekir. Üç düğüm gerekmeyecek kadar küçük bir sistemin varsa en azından düzenli yedek al ve düğümü izle; sağlık kontrolüyle otomatik yeniden başlatma kurmayı uygulama sağlık kontrolü yazısında anlattım.

    Mesajın içine büyük veri koyuyorsun. 20 MB'lık PDF'i mesaj gövdesine koymak brokeri belleğinden eder. Doğru desen, dosyayı bir depolama alanına yazıp mesaja yalnızca yolunu (referansını) koymaktır. Mesaj gövdesi birkaç kilobaytı geçmemelidir.

    Sıkça Sorulan Sorular#

    RabbitMQ ücretsiz mi#

    Evet, RabbitMQ açık kaynaklıdır ve Mozilla Public License altında ücretsiz kullanılabilir; üretimde de dahil olmak üzere lisans ücreti ödemezsin. Ücretli olan kısım, üreticisinin sunduğu ticari destek ve kurumsal eklenti paketleridir. Kendi sunucunda kurup çalıştırmak için hiçbir ödeme yapman gerekmez.

    RabbitMQ mı Kafka mı kullanmalıyım#

    İşi tek bir işçiye dağıtıp bitince silmek istiyorsan RabbitMQ, aynı olay akışını birden çok bağımsız tüketicinin farklı hızlarda okuması ve geçmişe dönebilmesi gerekiyorsa Kafka daha uygundur. RabbitMQ'nun kurulumu ve işletmesi belirgin biçimde daha basittir, bu yüzden ihtiyacın netleşmediyse RabbitMQ ile başlamak makul bir tercihtir. Kafka'ya asıl geçiş sebebi genelde yüksek hacimli olay akışı ve yeniden oynatma (replay) ihtiyacıdır.

    Kuyruktaki mesajlar sunucu yeniden başlarsa kaybolur mu#

    Üç koşulu birden sağlarsan kaybolmaz: kuyruk durable=true olmalı, mesaj persistent (delivery_mode=2) gönderilmeli ve tüketici manuel onay kullanmalı. Bu üçünden biri eksikse mesaj yeniden başlatmada ya da işçi çöküşünde kaybolabilir. En sık yapılan hata kuyruğu kalıcı yapıp mesajı kalıcı göndermeyi unutmaktır.

    Kuyruğum sürekli büyüyor, ne yapmalıyım#

    Önce sorunun tüketici tarafında mı üretici tarafında mı olduğunu ayır: list_queues çıktısında consumers sayısı sıfırsa işçilerin bağlanamıyor demektir, messages_unacknowledged yüksekse işçiler alıyor ama bitiremiyor demektir. İkinci durumda ya işçi sayısını artırman ya da işin kendisini hızlandırman gerekir. Kalıcı çözüm gelene kadar kuyruğa x-max-length sınırı koymak, diskin dolup brokerin tamamen durmasını engeller.

    RabbitMQ yönetim arayüzüne nasıl güvenli erişirim#

    15672 portunu güvenlik duvarında dışa kapalı tut ve erişimi SSH tüneli üzerinden yap: ssh -L 15672:127.0.0.1:15672 kullanici@sunucu komutundan sonra tarayıcıdan http://localhost:15672 adresini açarsın. Sürekli erişim gerekiyorsa arayüzü bir ters proxy arkasına alıp TLS ve ek kimlik doğrulama ekle. Her durumda ilk iş varsayılan guest kullanıcısını silmektir.

    Kaç tane işçi çalıştırmalıyım#

    Bunu formülle değil ölçümle bulursun: bir işin ortalama süresini ve hedeflediğin saniyelik iş sayısını çarp. Örneğin bir iş ortalama 2 saniye sürüyor ve saniyede 10 iş bitirmen gerekiyorsa yaklaşık 20 eşzamanlı işçi gerekir. İşler ağırlıklı olarak dış servis beklemesiyse (I/O) işçi sayısını CPU çekirdek sayısının çok üstüne çıkarabilirsin; CPU yoğun işlerde ise çekirdek sayısını aşmak fayda sağlamaz.

    Aynı mesajın iki kez işlenmesi mümkün mü#

    Evet ve buna hazırlıklı olmalısın. İşçi işi bitirip onay göndermeden hemen önce çökerse, RabbitMQ mesajı başka bir işçiye yeniden teslim eder; bu "en az bir kez teslim" (at-least-once) garantisinin doğal sonucudur. Çözüm, işlemleri idempotent yazmaktır: her mesaja benzersiz bir kimlik ver ve işlem öncesi bu kimliğin daha önce işlenip işlenmediğini veritabanından kontrol et.

    Kapanış#

    RabbitMQ'yu kurmak on dakika, doğru kurmak ise birkaç ayarlık bir disiplin işidir. Aklında kalması gereken dört alışkanlık şudur: guest kullanıcısını daha ilk gün sil ve 15672'yi dışa açma, kalıcı kuyruk–kalıcı mesaj–manuel onay üçlüsünü birlikte aç, her kuyruğa mutlaka bir ölü mektup kuyruğu ve x-max-length sınırı tanımla, işçileri prefetch değeriyle dengele. Bir de kuyruk derinliğini izlemeye al — bu tek metrik, sistemdeki her tıkanmayı sana önceden haber verir.

    Broker ve işçileri kendi altyapında çalıştıracaksan tam root erişimli VDS ya da kaynağı esnek bulut sunucu paketlerimiz RabbitMQ ve arkasındaki işçi havuzunu aynı iç ağda barındırmak için yeterlidir. Kuyruğun tuttuğu verinin düzenli kopyasını almak istersen yedekleme hizmetimizi, kurulum ve izleme kısmını hiç üstlenmek istemiyorsan sunucu yönetimi ekibimizi devreye alabilirsin.

    RabbitMQMesaj KuyruğuAMQP

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.