Azure Service Bus Mesaj Kuyruğu Kurulumu ve Yönetimi

Mesajlaşma altyapısı kurmak, modern mikroservis mimarilerinin belki de en kritik adımlarından biri. Uygulamalar arası iletişimi güvenilir, ölçeklenebilir ve asenkron hale getirmek istiyorsanız, Azure Service Bus tam da bu iş için tasarlanmış. Ben de bu yazıda size gerçek bir prodüksiyon ortamında Azure Service Bus kurulumunu, yapılandırmasını ve yönetimini adım adım anlatacağım.

Azure Service Bus Nedir ve Neden Kullanmalısınız?

Azure Service Bus, Microsoft’un yönetilen mesajlaşma hizmetidir. RabbitMQ veya Apache Kafka ile çalıştıysanız konsept size yabancı gelmeyecek, ancak Service Bus’ın en büyük avantajı tamamen yönetilen bir hizmet olması. Sunucu bakımı yok, broker yapılandırması yok, yüksek erişilebilirlik için ekstra çaba harcamıyorsunuz.

Gerçek dünya senaryosunu düşünelim: Bir e-ticaret platformu yönetiyorsunuz. Sipariş servisi, envanter servisi, bildirim servisi ve ödeme servisi birbirleriyle konuşmak zorunda. Bu servisleri doğrudan API çağrılarıyla birbirine bağlarsanız, bir servis çökünce tüm sistem etkilenir. Service Bus bu servislerin arasına girerek mesajları güvenilir şekilde iletir, yeniden deneme mekanizması sağlar ve ölü mesaj kuyruğu (dead-letter queue) ile başarısız mesajları yönetir.

Queue vs Topic farkı konusunda da hızlıca değinelim:

  • Queue (Kuyruk): Bire bir iletişim. Bir mesaj bir alıcıya gider. Sipariş işleme gibi senaryolar için ideal.
  • Topic (Konu): Bire çok iletişim. Bir mesaj birden fazla aboneye gider. Bildirim sistemleri için mükemmel.

Ön Gereksinimler

Başlamadan önce şunlara ihtiyacınız var:

  • Aktif bir Azure aboneliği
  • Azure CLI kurulu ve yapılandırılmış
  • az komutlarına aşinalık
  • Tercihen bir Python veya .NET ortamı (test için)

Azure CLI kurulumunu doğrulayalım önce:

az --version
az account show
az account list --output table

Doğru abonelikte olduğunuzdan emin olun. Yanlış aboneliğe kaynak oluşturmak klasik bir hata ve sonradan düzeltmek zahmetli olabiliyor.

Resource Group ve Namespace Oluşturma

Her şey bir resource group ile başlar. Organizasyonunuzu mantıklı tutun:

# Resource group oluştur
az group create 
  --name rg-servicebus-prod 
  --location westeurope 
  --tags Environment=Production Project=ECommerce Owner=SysAdmin

# Service Bus namespace oluştur
az servicebus namespace create 
  --resource-group rg-servicebus-prod 
  --name sb-ecommerce-prod 
  --location westeurope 
  --sku Standard 
  --tags Environment=Production

Burada SKU seçimi çok önemli. Üç seçeneğiniz var:

  • Basic: Sadece queue desteği, mesaj boyutu 256KB, geliştirme ortamları için uygun, en ucuz seçenek
  • Standard: Queue ve topic desteği, mesaj boyutu 256KB, çoğu prodüksiyon senaryosu için yeterli
  • Premium: Queue ve topic, mesaj boyutu 1MB’a kadar, dedicated resources, VNET entegrasyonu, yüksek trafikli kurumsal uygulamalar için

Eğer VNET entegrasyonu veya Private Endpoint gerekiyorsa Premium’a geçmek zorundasınız. Bunu baştan planlamak, sonradan migration acısından sizi kurtarır.

Kuyruk Oluşturma ve Yapılandırma

Namespace hazır olduktan sonra kuyruğumuzu oluşturalım:

# Temel sipariş kuyruğu
az servicebus queue create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --name orders-queue 
  --max-size 1024 
  --default-message-time-to-live P7D 
  --lock-duration PT30S 
  --max-delivery-count 5 
  --dead-lettering-on-message-expiration true 
  --enable-duplicate-detection true 
  --duplicate-detection-history-time-window PT10M

# Bildirim kuyruğu (daha az kritik, kısa TTL)
az servicebus queue create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --name notifications-queue 
  --max-size 1024 
  --default-message-time-to-live P1D 
  --lock-duration PT15S 
  --max-delivery-count 3 
  --dead-lettering-on-message-expiration true

Bu parametreleri anlamanız kritik önem taşıyor:

  • –max-size: Kuyruğun maksimum boyutu (MB cinsinden). 1024 MB yani 1GB yeterli olur çoğu senaryo için.
  • –default-message-time-to-live: Mesajın kuyrukta ne kadar bekleyeceği. P7D = 7 gün. ISO 8601 format kullanılıyor.
  • –lock-duration: Bir mesajı alan alıcının işleme için sahip olduğu süre. Bu süre içinde acknowledge etmezse mesaj tekrar kuyruğa döner.
  • –max-delivery-count: Kaç kez deneme yapılacak. Bu sayıyı aşınca mesaj dead-letter queue’ya gider.
  • –enable-duplicate-detection: Aynı mesajın iki kez işlenmesini önler. Ödeme sistemleri için mutlaka açın.

Topic ve Subscription Yapılandırması

Bire çok mesajlaşma için topic kullanacağız. Yine e-ticaret senaryomuzda düşünelim: Sipariş tamamlandığında hem envanter servisinin hem de bildirim servisinin haberdar olması lazım.

# Topic oluştur
az servicebus topic create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --name order-events 
  --max-size 1024 
  --default-message-time-to-live P7D 
  --enable-duplicate-detection true 
  --duplicate-detection-history-time-window PT10M

# Envanter servisi subscription
az servicebus topic subscription create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --topic-name order-events 
  --name inventory-sub 
  --max-delivery-count 5 
  --lock-duration PT30S 
  --default-message-time-to-live P3D 
  --dead-lettering-on-message-expiration true

# Bildirim servisi subscription
az servicebus topic subscription create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --topic-name order-events 
  --name notification-sub 
  --max-delivery-count 3 
  --lock-duration PT15S 
  --default-message-time-to-live P1D

# Filtre ekle - sadece yüksek değerli siparişler için ayrı subscription
az servicebus topic subscription create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --topic-name order-events 
  --name high-value-orders-sub 
  --max-delivery-count 10 
  --lock-duration PT60S

# SQL filter ekle (yüksek değerli siparişler için)
az servicebus topic subscription rule create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --topic-name order-events 
  --subscription-name high-value-orders-sub 
  --name high-value-filter 
  --filter-sql-expression "OrderAmount > 1000"

SQL filter özelliği çok güçlü. Mesaj properties’lerine göre filtreleme yapabiliyorsunuz. Bu sayede tek bir topic üzerinden farklı servislere farklı mesajlar iletebilirsiniz.

Erişim Yönetimi ve Güvenlik

Prodüksiyonda connection string kullanmak yerine Managed Identity veya en azından Shared Access Policy kullanın. Her uygulama kendi politikasına sahip olsun:

# Namespace düzeyinde SAS policy (genel amaçlı admin)
az servicebus namespace authorization-rule create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --name order-service-policy 
  --rights Send Listen

# Sadece gönderme yetkisi (producer servisler için)
az servicebus queue authorization-rule create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --queue-name orders-queue 
  --name producer-policy 
  --rights Send

# Sadece okuma yetkisi (consumer servisler için)
az servicebus queue authorization-rule create 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --queue-name orders-queue 
  --name consumer-policy 
  --rights Listen

# Connection string al
az servicebus queue authorization-rule keys list 
  --resource-group rg-servicebus-prod 
  --namespace-name sb-ecommerce-prod 
  --queue-name orders-queue 
  --name producer-policy 
  --query primaryConnectionString 
  --output tsv

Güvenlik ipucu: Connection string’leri asla kaynak kodunda saklamayın. Azure Key Vault kullanın veya en azından environment variable olarak inject edin. Prodüksiyon ortamında Managed Identity ile RBAC kullanmak çok daha temiz bir yaklaşım.

Azure CLI ile Monitoring ve Yönetim

Kuyruklarınızı izlemek için bazı kullanışlı komutlar:

#!/bin/bash
# service_bus_monitor.sh - Service Bus izleme scripti

NAMESPACE="sb-ecommerce-prod"
RG="rg-servicebus-prod"

echo "=== Service Bus Kuyruk Durumu ==="
echo "Namespace: $NAMESPACE"
echo "Tarih: $(date)"
echo ""

# Tüm kuyrukları listele
echo "--- Kuyruklar ---"
az servicebus queue list 
  --resource-group $RG 
  --namespace-name $NAMESPACE 
  --query "[].{Name:name, Status:status, MessageCount:countDetails.activeMessageCount, DeadLetter:countDetails.deadLetterMessageCount}" 
  --output table

echo ""
echo "--- Topic Subscriptions ---"
az servicebus topic list 
  --resource-group $RG 
  --namespace-name $NAMESPACE 
  --query "[].name" 
  --output tsv | while read topic; do
    echo "Topic: $topic"
    az servicebus topic subscription list 
      --resource-group $RG 
      --namespace-name $NAMESPACE 
      --topic-name $topic 
      --query "[].{Sub:name, Active:countDetails.activeMessageCount, DL:countDetails.deadLetterMessageCount}" 
      --output table
done

# Dead letter uyarısı
echo ""
echo "--- Dead Letter Uyarıları ---"
az servicebus queue list 
  --resource-group $RG 
  --namespace-name $NAMESPACE 
  --query "[?countDetails.deadLetterMessageCount > `0`].{Queue:name, DeadLetterCount:countDetails.deadLetterMessageCount}" 
  --output table

Bu scripti cron job olarak çalıştırıp çıktısını bir monitoring sistemine gönderin. Dead letter count sıfırdan büyükse mutlaka incelemeniz gerekiyor demektir.

Dead Letter Queue Yönetimi

Dead letter queue (DLQ), başarısız mesajların gittiği yerdir. Bunları düzenli olarak kontrol etmek ve işlemek kritik önem taşır. Prodüksiyonda DLQ’yu görmezden gelmek, sessiz veri kaybına yol açar.

#!/bin/bash
# dlq_check.sh - Dead letter queue kontrolü ve raporlama

NAMESPACE="sb-ecommerce-prod"
RG="rg-servicebus-prod"
ALERT_THRESHOLD=10

echo "DLQ Kontrol Raporu - $(date)"
echo "================================"

# Her kuyruk için DLQ kontrolü
az servicebus queue list 
  --resource-group $RG 
  --namespace-name $NAMESPACE 
  --output json | jq -r '.[] | "(.name) (.countDetails.deadLetterMessageCount)"' | 
while read queue_name dlq_count; do
    if [ "$dlq_count" -gt "$ALERT_THRESHOLD" ]; then
        echo "UYARI: $queue_name kuyruğunda $dlq_count dead letter mesajı var!"
        # Buraya Slack webhook veya email notification ekleyebilirsiniz
        # curl -X POST -H 'Content-type: application/json' 
        #   --data "{"text":"DLQ Uyarı: $queue_name - $dlq_count mesaj"}" 
        #   $SLACK_WEBHOOK_URL
    else
        echo "OK: $queue_name - DLQ: $dlq_count"
    fi
done

DLQ’daki mesajları yeniden işleme (requeue) için genellikle bir araç geliştirirsiniz. Azure Portal üzerinden de manuel olarak yapılabilir ama otomasyon her zaman daha iyi.

Azure Alerts ve Diagnostics Yapılandırması

Monitoring olmadan prodüksiyon ortamı kör uçuş yapmak gibidir. Action group ve alert oluşturalım:

# Action group oluştur (email bildirimi için)
az monitor action-group create 
  --resource-group rg-servicebus-prod 
  --name ag-servicebus-ops 
  --short-name sb-ops 
  --action email admin-email [email protected]

# Namespace ID al
NAMESPACE_ID=$(az servicebus namespace show 
  --resource-group rg-servicebus-prod 
  --name sb-ecommerce-prod 
  --query id 
  --output tsv)

# Dead letter mesaj sayısı için alert
az monitor metrics alert create 
  --resource-group rg-servicebus-prod 
  --name alert-dlq-high 
  --scopes $NAMESPACE_ID 
  --condition "avg DeadletteredMessages > 50" 
  --window-size 5m 
  --evaluation-frequency 1m 
  --action ag-servicebus-ops 
  --description "Dead letter kuyruk sayısı yüksek" 
  --severity 2

# Aktif mesaj sayısı çok yüksekse (consumer geride kalıyor)
az monitor metrics alert create 
  --resource-group rg-servicebus-prod 
  --name alert-queue-backlog 
  --scopes $NAMESPACE_ID 
  --condition "avg ActiveMessages > 10000" 
  --window-size 10m 
  --evaluation-frequency 2m 
  --action ag-servicebus-ops 
  --description "Kuyruk birikimi tespit edildi, consumer kapasitesini artırın" 
  --severity 1

# Diagnostics log ayarla
STORAGE_ID=$(az storage account show 
  --resource-group rg-servicebus-prod 
  --name stservicebusprod 
  --query id 
  --output tsv 2>/dev/null || echo "")

az monitor diagnostic-settings create 
  --resource $NAMESPACE_ID 
  --name diag-servicebus 
  --logs '[{"category":"OperationalLogs","enabled":true,"retentionPolicy":{"days":30,"enabled":true}}]' 
  --metrics '[{"category":"AllMetrics","enabled":true,"retentionPolicy":{"days":30,"enabled":true}}]'

Terraform ile Altyapı Kodu

Eğer Infrastructure as Code kullanıyorsanız, tüm bu kaynakları Terraform ile de yönetebilirsiniz. Kısa bir örnek:

# Terraform ile Service Bus yönetimi
# Önce mevcut namespace'i Terraform state'e import et
terraform init

cat > main.tf << 'EOF'
resource "azurerm_resource_group" "sb_rg" {
  name     = "rg-servicebus-prod"
  location = "West Europe"
}

resource "azurerm_servicebus_namespace" "main" {
  name                = "sb-ecommerce-prod"
  location            = azurerm_resource_group.sb_rg.location
  resource_group_name = azurerm_resource_group.sb_rg.name
  sku                 = "Standard"

  tags = {
    Environment = "Production"
    Project     = "ECommerce"
  }
}

resource "azurerm_servicebus_queue" "orders" {
  name         = "orders-queue"
  namespace_id = azurerm_servicebus_namespace.main.id

  max_size_in_megabytes    = 1024
  max_delivery_count       = 5
  lock_duration            = "PT30S"
  default_message_ttl      = "P7D"

  dead_lettering_on_message_expiration = true
  requires_duplicate_detection         = true
  duplicate_detection_history_time_window = "PT10M"
}
EOF

terraform plan -out=tfplan
terraform apply tfplan

Terraform ile yönetmek, configuration drift’i önler ve değişiklikleri code review sürecine dahil etmenizi sağlar.

Prodüksiyon Checklist

Gerçek prodüksiyon ortamına geçmeden önce şunları doğrulayın:

  • Namespace SKU: İhtiyacınıza uygun seçildi mi? Premium gerekiyor mu?
  • Duplicate detection: Kritik işlemler (ödeme, sipariş) için mutlaka açık
  • Dead letter queue monitoring: Alert kuruldu mu?
  • Max delivery count: Çok düşük seçmeyin, geçici hatalar için yeniden deneme şansı verin. Çok yüksek de seçmeyin, gerçek hatalı mesajlar sistemi meşgul eder.
  • Lock duration: Mesaj işleme sürenizden büyük olmalı. 30 saniyede işleyemiyorsanız artırın.
  • Connection string güvenliği: Key Vault’ta mı? Managed Identity kullanılıyor mu?
  • Geo-redundancy: Premium SKU ile geo-disaster recovery yapılandırıldı mı?
  • Firewall kuralları: Sadece belirli IP’lerden erişim mü? Private Endpoint var mı?

Yaygın Hatalar ve Çözümleri

Mesajlar dead letter’a düşüyor ama neden bilmiyoruz: DLQ’daki mesajları okuyun ve DeadLetterReason ile DeadLetterErrorDescription property’lerini inceleyin. Bunlar size neyin yanlış gittiğini söyler.

Consumer geride kalıyor, kuyruk büyüyor: Bu bir scaling sorunudur. Consumer instance sayısını artırın. Azure Container Apps veya AKS kullanıyorsanız KEDA ile Service Bus trigger’ı kuyruk derinliğine göre otomatik scale edebilirsiniz.

Duplicate mesajlar işleniyor: MessageId property’sini her mesaj için unique set ettiğinizden emin olun. Duplicate detection açıksa ama mesaj ID’ler farklıysa duplicate detection çalışmaz.

Lock expired hatası: İşleme süreniz lock duration’ı aşıyor. Ya lock duration’ı artırın ya da mesajı işlerken RenewMessageLockAsync() çağrısı yapın.

Sonuç

Azure Service Bus kurulumu ilk bakışta karmaşık görünebilir ancak kavramları bir kez oturdurduğunuzda, yönetilen bir hizmet olduğu için işletme yükünün çok düşük olduğunu fark ediyorsunuz. Namespace ve queue oluşturdunuz, SAS politikaları ile erişim yönetimini sağladınız, monitoring ve alerting kurulumu yaptınız.

En önemli nokta şu: Service Bus’ı kurmak işin kolay kısmı. Asıl iş, dead letter queue’ları doğru yönetmek, consumer’larınızı idempotent yazmak ve mesaj işleme hatalarını gracefully handle etmek. Bu konulara gereken önemi verin ve mesajlaşma altyapınız sizi hiç zorlamadan çalışmaya devam eder.

Bir sonraki yazıda Azure Service Bus ile KEDA kullanarak Kubernetes üzerinde otomatik scaling konusunu ele alacağız. Sorularınız varsa yorumlarda buluşalım.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir