RabbitMQ Cluster Kurulumu ve Yüksek Erişilebilirlik
Üretim ortamında tek bir RabbitMQ node’uyla çalışmak, gece 2’de telefon beklemek demektir. Bunu bir kez yaşayan sysadmin, bir daha asla tek node’la production’a çıkmaz. Bu yazıda sıfırdan bir RabbitMQ cluster kurulumunu, Quorum Queue yapılandırmasını ve gerçek anlamda yüksek erişilebilirlik sağlamak için yapmanız gerekenleri adım adım ele alacağız.
Ortam Hazırlığı ve Gereksinimler
Üç node’dan oluşan bir cluster kuracağız. Bunun altında mantıksal bir neden var: RabbitMQ, Raft konsensüs algoritması kullandığı için tek sayıda node’a ihtiyaç duyar. İki node’lu bir cluster, split-brain durumunda karar veremez ve kendini durdurur. Minimum üç node, production için makul bir başlangıç noktasıdır.
Node’larımız şunlar olsun:
- rabbitmq-01: 192.168.10.11
- rabbitmq-02: 192.168.10.12
- rabbitmq-03: 192.168.10.13
İşletim sistemi olarak Ubuntu 22.04 LTS kullanacağız. Her node için önerilen minimum kaynak:
- CPU: 4 vCPU
- RAM: 8 GB (RabbitMQ bellek limitini toplam RAM’in %40’ı olarak ayarlar)
- Disk: 50 GB SSD (Durable queue’lar için disk I/O kritik)
- Network: Node’lar arası düşük latency, tercihen aynı availability zone
Her üç node’da da /etc/hosts dosyasını düzenleyerek hostname çözümlemesini sağlayın. DNS üzerinden de yapabilirsiniz ama /etc/hosts daha öngörülebilir davranır:
cat >> /etc/hosts << 'EOF'
192.168.10.11 rabbitmq-01
192.168.10.12 rabbitmq-02
192.168.10.13 rabbitmq-03
EOF
Hostname’lerin doğru set edildiğini kontrol edin:
hostnamectl set-hostname rabbitmq-01 # Her node'da kendi adını set edin
hostname -f # FQDN kontrolü
RabbitMQ Kurulumu
Her üç node’da aynı kurulum adımlarını uygulayacaksınız. RabbitMQ’nun resmi paket deposunu kullanmak, dağıtımın kendi reposunu kullanmaktan çok daha mantıklı. Ubuntu’nun standart reposundaki sürüm genellikle birkaç major version geride kalır.
# Erlang ve RabbitMQ için gerekli bağımlılıklar
apt-get update
apt-get install -y curl gnupg apt-transport-https
# Erlang reposunu ekle (TeamRabbitMQ'nun Erlang paketi önerilir)
curl -1sLf 'https://dl.cloudsmith.io/public/rabbitmq/rabbitmq-erlang/setup.deb.sh' | bash
# RabbitMQ reposunu ekle
curl -1sLf 'https://dl.cloudsmith.io/public/rabbitmq/rabbitmq-server/setup.deb.sh' | bash
# Kurulum
apt-get update
apt-get install -y erlang-base
erlang-asn1
erlang-crypto
erlang-eldap
erlang-ftp
erlang-inets
erlang-mnesia
erlang-os-mon
erlang-parsetools
erlang-public-key
erlang-runtime-tools
erlang-snmp
erlang-ssl
erlang-syntax-tools
erlang-tftp
erlang-tools
erlang-xmerl
apt-get install -y rabbitmq-server
Kurulum sonrası servisi başlatıp enable edin:
systemctl enable rabbitmq-server
systemctl start rabbitmq-server
systemctl status rabbitmq-server
Erlang Cookie Senkronizasyonu
Cluster kurulumunun en kritik ve en çok hata yapılan adımı budur. RabbitMQ node’ları birbirleriyle Erlang distributed protocol üzerinden konuşur ve bunun için tüm node’larda aynı Erlang cookie değerinin olması zorunludur. Cookie uyuşmazlığı, node’ların birbirine bağlanamamasına neden olur ve hata mesajları bazen yanıltıcı olabilir.
İlk node’da cookie’yi okuyun:
# rabbitmq-01 üzerinde
cat /var/lib/rabbitmq/.erlang.cookie
# Örnek çıktı: ABCDEFGHIJKLMNOP
Bu değeri diğer node’lara kopyalayın:
# rabbitmq-02 ve rabbitmq-03 üzerinde
systemctl stop rabbitmq-server
# Cookie dosyasını yazın (rabbitmq-01'den kopyaladığınız değeri kullanın)
echo -n "ABCDEFGHIJKLMNOP" > /var/lib/rabbitmq/.erlang.cookie
chmod 400 /var/lib/rabbitmq/.erlang.cookie
chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie
systemctl start rabbitmq-server
Cookie senkronizasyonu yaparken echo -n kullanmak önemli. -n olmadan satır sonu karakteri eklendiği için cookie değeri farklı olur ve node’lar bağlanamaz. Bu hatayı defalarca gördüm, mutlaka dikkat edin.
Cluster’ı Oluşturma
Cookie senkronizasyonundan sonra node’ları cluster’a ekleyebilirsiniz. Bu işlemi rabbitmq-02 ve rabbitmq-03 üzerinde yapacaksınız. rabbitmq-01 referans node olarak kalacak.
rabbitmq-02 üzerinde:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbitmq-01
rabbitmqctl start_app
rabbitmq-03 üzerinde:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbitmq-01
rabbitmqctl start_app
Cluster durumunu kontrol edin:
rabbitmqctl cluster_status
Çıktıda üç node’u da görmeli ve hepsinin running nodes listesinde yer almalısınız. Eğer bir node disc yerine ram olarak görünüyorsa ve bu sizin istediğiniz bir şey değilse, --disc parametresiyle join_cluster komutunu tekrar çalıştırabilirsiniz. Genel tavsiyem: production’da tüm node’ları disc node olarak kullanın.
Management Plugin ve İzleme
Management UI olmadan RabbitMQ yönetmek gereksiz yere zorlaştırır. Her node’da plugin’i aktifleştirin:
rabbitmq-plugins enable rabbitmq_management
rabbitmq-plugins enable rabbitmq_management_agent
Varsayılan guest kullanıcısı yalnızca localhost’tan bağlanabilir. Production için ayrı bir admin kullanıcısı oluşturun:
# Admin kullanıcısı oluştur
rabbitmqctl add_user admin 'G3rc3ktenGucluBirSifre!'
rabbitmqctl set_user_tags admin administrator
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
# Guest kullanıcısını silin (güvenlik için)
rabbitmqctl delete_user guest
Management UI’ya http://rabbitmq-01:15672 adresinden erişebilirsiniz. Cluster view’da tüm node’ları göreceksiniz.
Quorum Queue Yapılandırması
Eski klasik mirrored queue yapısı RabbitMQ 3.9’dan itibaren deprecated oldu ve 3.12 itibarıyla kaldırıldı. Quorum Queue, modern ve doğru yaklaşım. Raft tabanlı çalışır, lider seçimi yapar ve veri tutarlılığı konusunda çok daha güvenilirdir.
Quorum Queue oluştururken dikkat etmeniz gereken parametreler:
- x-queue-type:
quorumolarak set edilmeli - x-quorum-initial-group-size: Varsayılan cluster boyutunu kullanır, genellikle dokunmayın
- x-delivery-limit: Mesajın kaç kez yeniden deneneceği, zehirli mesajları önlemek için önemli
# rabbitmqadmin ile quorum queue oluşturma
rabbitmqadmin declare queue
name=siparis-kuyrugu
durable=true
arguments='{"x-queue-type": "quorum", "x-delivery-limit": 5}'
Python istemcisi üzerinden exchange ve queue bind örneği:
import pika
credentials = pika.PlainCredentials('admin', 'G3rc3ktenGucluBirSifre!')
parameters = pika.ConnectionParameters(
host='rabbitmq-01',
port=5672,
credentials=credentials
)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()
# Exchange tanımla
channel.exchange_declare(
exchange='siparis-exchange',
exchange_type='direct',
durable=True
)
# Quorum Queue tanımla
channel.queue_declare(
queue='siparis-kuyrugu',
durable=True,
arguments={
'x-queue-type': 'quorum',
'x-delivery-limit': 5
}
)
# Bind et
channel.queue_bind(
exchange='siparis-exchange',
queue='siparis-kuyrugu',
routing_key='yeni-siparis'
)
connection.close()
print("Queue ve exchange başarıyla oluşturuldu.")
Load Balancer Entegrasyonu
Uygulama katmanından doğrudan node IP’sine bağlanmak, yüksek erişilebilirliğin önündeki en büyük engeldir. Bir node düştüğünde uygulamanız haberdar olmaz ve bağlantı hatası alır. Önlerine bir HAProxy koyarak bu problemi çözeceğiz.
HAProxy kurulumu:
apt-get install -y haproxy
/etc/haproxy/haproxy.cfg konfigürasyonu:
global
log /dev/log local0
maxconn 50000
user haproxy
group haproxy
daemon
defaults
log global
mode tcp
option tcplog
option dontlognull
timeout connect 5s
timeout client 60s
timeout server 60s
# AMQP load balancing
frontend rabbitmq_frontend
bind *:5672
default_backend rabbitmq_backend
backend rabbitmq_backend
balance roundrobin
option tcp-check
server rabbitmq-01 192.168.10.11:5672 check inter 5s rise 2 fall 3
server rabbitmq-02 192.168.10.12:5672 check inter 5s rise 2 fall 3
server rabbitmq-03 192.168.10.13:5672 check inter 5s rise 2 fall 3
# Management UI load balancing
frontend rabbitmq_management_frontend
bind *:15672
default_backend rabbitmq_management_backend
backend rabbitmq_management_backend
balance roundrobin
option httpchk GET /api/health/checks/aliveness
http-check expect status 200
server rabbitmq-01 192.168.10.11:15672 check inter 10s rise 2 fall 3
server rabbitmq-02 192.168.10.12:15672 check inter 10s rise 2 fall 3
server rabbitmq-03 192.168.10.13:15672 check inter 10s rise 2 fall 3
# HAProxy stats
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 10s
HAProxy’nin health check için kullandığı /api/health/checks/aliveness endpoint’i, node’un gerçekten sağlıklı olup olmadığını kontrol eder. Basit bir TCP check’ten çok daha güvenilirdir.
Bellek ve Disk Alarmları
RabbitMQ, bellek veya disk eşiği aşıldığında flow control mekanizmasını devreye alır ve publisher’ları bloklar. Bu davranışı anlamak ve doğru eşikleri ayarlamak, production’da sürprizleri önler.
/etc/rabbitmq/rabbitmq.conf dosyasını oluşturun veya düzenleyin:
cat > /etc/rabbitmq/rabbitmq.conf << 'EOF'
# Cluster adı
cluster_name = production-rabbitmq
# Bellek eşiği - toplam RAM'in %40'ı (varsayılan)
vm_memory_high_watermark.relative = 0.4
# Disk eşiği - en az 2GB boş alan
disk_free_limit.absolute = 2GB
# Heartbeat - bağlantı kopuklarını hızlı tespit
heartbeat = 60
# Network partition handling
cluster_partition_handling = pause_minority
# Bağlantı başına maksimum kanal sayısı
channel_max = 2047
# Log seviyesi
log.console.level = info
log.file.level = info
log.file = /var/log/rabbitmq/rabbit.log
EOF
cluster_partition_handling = pause_minority ayarı kritik. Split-brain durumunda azınlıkta kalan taraf kendini durdurur. Bu, veri tutarsızlığı yaşamak yerine hizmet vermemeyi tercih etmek anlamına gelir. Production’da bu davranış genellikle doğru tercihtir.
Konfigürasyon değişikliği sonrası servisi yeniden başlatın:
systemctl restart rabbitmq-server
Monitoring ve Alerting
Prometheus + Grafana kombinasyonu RabbitMQ izleme için standart haline geldi. RabbitMQ, Prometheus formatında metrik sunan built-in bir plugin’e sahip:
rabbitmq-plugins enable rabbitmq_prometheus
Plugin aktifleştirildikten sonra http://rabbitmq-01:15692/metrics adresinde metriklere ulaşabilirsiniz.
Prometheus scrape konfigürasyonu:
scrape_configs:
- job_name: 'rabbitmq'
static_configs:
- targets:
- 'rabbitmq-01:15692'
- 'rabbitmq-02:15692'
- 'rabbitmq-03:15692'
scrape_interval: 15s
İzlemeniz gereken kritik metrikler:
- rabbitmq_queue_messages: Kuyrukta bekleyen mesaj sayısı, anormal yükselme consumer sorunu işareti
- rabbitmq_queue_messages_unacked: Acknowledge edilmemiş mesajlar, consumer’ın yavaşladığının göstergesi
- rabbitmq_node_mem_used: Bellek kullanımı, watermark’a yaklaşırsa alarm
- rabbitmq_node_disk_free: Disk alarmı tetiklenmeden önce müdahale etmek için
- rabbitmq_connections: Bağlantı sızdıran uygulama kodunu tespit etmek için
Grafana için RabbitMQ resmi dashboard’u dashboard ID 10991 ile import edebilirsiniz. Sıfırdan yazmak yerine bunu özelleştirmek çok daha verimli.
Cluster Bakım Operasyonları
Cluster’daki bir node’u bakım amacıyla devre dışı bırakmak istediğinizde sıralamanın önemi var. Node’u direkt kapatmak yerine önce draining yapın:
# Node'u bakım moduna al (RabbitMQ 3.8+)
rabbitmqctl drain
# Bakım modundan çık
rabbitmqctl revive
Rolling upgrade yaparken bir node’da işlem tamamlanmadan diğerine geçmeyin. Her upgrade sonrası cluster durumunu kontrol edin:
# Cluster sağlık kontrolü
rabbitmqctl cluster_status
rabbitmq-diagnostics check_running
rabbitmq-diagnostics check_local_alarms
# Node'ların senkronize olduğunu kontrol et
rabbitmqctl list_queues name messages mirror_pids synchronised_slave_pids
Quorum Queue’ların lider dağılımını kontrol etmek de iyi bir pratik. Tüm liderler tek bir node’da toplanmışsa yük dengesizliği oluşur:
rabbitmqctl list_queues name leader members
Gerçek Dünya Senaryosu: Node Kaybı ve Recovery
Cluster çalışırken rabbitmq-02 tamamen çöksün. Bu durumda ne olur?
Quorum Queue, kalan iki node (rabbitmq-01 ve rabbitmq-03) üzerinde çoğunluğu koruyarak çalışmaya devam eder. HAProxy, rabbitmq-02‘nin health check’inin başarısız olduğunu fark eder ve trafiği kalan node’lara yönlendirir. Uygulamanız kesintisiz çalışmaya devam eder.
rabbitmq-02 geri geldiğinde otomatik olarak cluster’a yeniden katılır ve Quorum Queue’lar üzerindeki veriler senkronize edilir. Manuel müdahaleye gerek yoktur.
Ancak node uzun süre çevrimdışı kaldıysa (örneğin birkaç gün), geri döndükten sonra senkronizasyon süreci yoğun disk I/O yaratabilir. Bu durumda düşük trafik saatlerinde recovery planlamak mantıklıdır.
# Node geri döndükten sonra durumu kontrol et
rabbitmqctl cluster_status
# Quorum queue'ların sağlık durumu
rabbitmq-diagnostics check_running
rabbitmqctl list_quorum_queues
Sonuç
RabbitMQ cluster kurulumu teknik olarak karmaşık değil, ama her adımın neden yapıldığını anlamadan yapılan kurulumlar production’da sürpriz yaratır. Erlang cookie senkronizasyonu, Quorum Queue’ya geçiş, load balancer entegrasyonu ve doğru partition handling stratejisi, gerçek anlamda yüksek erişilebilirlik için birbirini tamamlayan parçalar.
Özellikle eski kaynaklarda hala mirrored queue örnekleri görüyorum. Eğer RabbitMQ 3.8 ve üzerini kullanıyorsanız, Quorum Queue’ya geçin. Daha az konfigürasyon, daha iyi tutarlılık garantileri ve aktif geliştirme. Mirrored queue artık bir geçmişe ait.
Son olarak: monitoring olmadan cluster kurmak, emniyet kemeri takmadan araba kullanmak gibi. Prometheus entegrasyonunu ve anlamlı alarm eşiklerini baştan yapılandırın. Bir sorun oluştuğunda logları didik didik aramak yerine Grafana dashboard’unuza bakıp durumu anında görmek, gece 2’deki o telefonu almamak demektir.
