Azure Cosmos DB Kurulum ve Yönetimi

Bulut tabanlı veritabanı yönetimi söz konusu olduğunda, Azure Cosmos DB gerçekten farklı bir yerde duruyor. Hem NoSQL esnekliği hem de küresel dağıtım yetenekleriyle modern uygulamaların ihtiyaç duyduğu şeylerin büyük çoğunluğunu karşılıyor. Peki bu gücü nasıl doğru şekilde kuruyoruz, yönetiyoruz ve optimum hale getiriyoruz? Bu yazıda Cosmos DB’yi sıfırdan kurmaktan, production ortamında izlemeye kadar olan süreci adım adım ele alacağız.

Azure Cosmos DB Nedir ve Ne Zaman Kullanmalısınız

Cosmos DB, Microsoft’un tam yönetimli, çok modelli bir NoSQL veritabanı hizmetidir. SQL API, MongoDB API, Cassandra API, Gremlin API ve Table API desteklediği için mevcut uygulamaları büyük değişiklik yapmadan taşıyabilirsiniz.

Şunu net söyleyelim: Cosmos DB her senaryo için ideal değil. Eğer ilişkisel verileriniz tutarlı şema gerektiriyorsa ve yüksek join işlemleriniz varsa, Azure SQL Database daha mantıklı olacaktır. Ama şu durumlarda Cosmos DB gerçek anlamda parlar:

  • Küresel dağıtım gereksinimi: İstanbul’daki kullanıcı ile Tokyo’daki kullanıcıya eşit düşük gecikme süresi sağlamak istiyorsunuz
  • Esnek şema: Belge yapınız sık değişiyor, farklı nesneleri aynı koleksiyonda saklıyorsunuz
  • Yüksek okuma/yazma throughput: Milyonlarca işlem/saniye ölçeğine çıkmanız gerekiyor
  • Otomatik ölçeklendirme: Trafik dalgalanmalarına karşı hazırlıklı olmak istiyorsunuz

Azure CLI ile Cosmos DB Hesabı Oluşturma

Portal üzerinden kurulum yapmak mümkün ama IaC (Infrastructure as Code) prensiplerine sadık kalarak CLI ile gidelim. Önce ortamınızı hazırlayın:

# Azure CLI kurulumu (Ubuntu/Debian)
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# Giriş yapın
az login

# Aboneliği kontrol edin
az account show --output table

# Doğru aboneliği seçin (birden fazla varsa)
az account set --subscription "Production-Subscription"

Şimdi resource group ve Cosmos DB hesabı oluşturalım:

# Resource group oluştur
az group create 
  --name rg-cosmosdb-prod 
  --location westeurope

# Cosmos DB hesabı oluştur (SQL API, çok bölgeli)
az cosmosdb create 
  --name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --locations regionName=westeurope failoverPriority=0 isZoneRedundant=true 
  --locations regionName=northeurope failoverPriority=1 isZoneRedundant=false 
  --default-consistency-level Session 
  --enable-automatic-failover true 
  --enable-multiple-write-locations false 
  --kind GlobalDocumentDB

Bu komutta birkaç kritik parametre var:

  • –default-consistency-level Session: Çoğu uygulama için en dengeli seçenek. Kullanıcı kendi yazdığı veriyi her zaman okuyabilir
  • –enable-automatic-failover true: Primary region çökerse North Europe otomatik devralır
  • –enable-multiple-write-locations false: Multi-master yazmak isterseniz true yapın ama conflict resolution stratejisi belirlemeniz gerekir
  • –kind GlobalDocumentDB: SQL API için bu değer, MongoDB için MongoDB kullanın

Veritabanı ve Container Oluşturma

Hesap hazır, şimdi veritabanı ve container yapısını kuralım. Burada throughput stratejisi çok önemli:

# Veritabanı oluştur (shared throughput - ekonomik seçenek)
az cosmosdb sql database create 
  --account-name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --name ProductionDB 
  --throughput 1000

# Ana container oluştur - partition key seçimi kritik!
az cosmosdb sql container create 
  --account-name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --database-name ProductionDB 
  --name Orders 
  --partition-key-path "/customerId" 
  --throughput 400 
  --idx @index-policy.json

Index policy dosyasını hazırlayalım. Cosmos DB varsayılan olarak her alanı indexler, bu çok yazma senaryolarında maliyeti artırır:

# index-policy.json içeriği
cat > index-policy.json << 'EOF'
{
  "indexingMode": "consistent",
  "automatic": true,
  "includedPaths": [
    {
      "path": "/customerId/?",
      "indexes": [{"kind": "Hash", "dataType": "String", "precision": -1}]
    },
    {
      "path": "/orderDate/?",
      "indexes": [{"kind": "Range", "dataType": "String", "precision": -1}]
    },
    {
      "path": "/status/?",
      "indexes": [{"kind": "Hash", "dataType": "String", "precision": -1}]
    }
  ],
  "excludedPaths": [
    {
      "path": "/largeDescriptionField/*"
    },
    {
      "path": "/_etag/?"
    }
  ]
}
EOF

Autoscale Yapılandırması

Production ortamında sabit throughput yerine autoscale kullanmak çok daha akıllıca. Gece 3’te 400 RU/s, öğle vakti 4000 RU/s gerekebilir:

# Mevcut container'ı autoscale'e geçir
az cosmosdb sql container throughput migrate 
  --account-name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --database-name ProductionDB 
  --name Orders 
  --throughput-type autoscale

# Autoscale maksimum limitini ayarla (10x'e kadar scale down yapar)
az cosmosdb sql container throughput update 
  --account-name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --database-name ProductionDB 
  --name Orders 
  --max-throughput 10000

Autoscale ile 10.000 RU/s max belirlediğinizde, sistem 1.000 RU/s’den 10.000 RU/s arasında otomatik ayarlama yapar. Gerçek kullanıma göre faturalandırılırsınız, bu genellikle sabit throughput’a göre yüzde 30-50 tasarruf sağlar.

Güvenlik Yapılandırması

Cosmos DB hesabınızı internete açık bırakmak ciddi bir güvenlik riskidir. Gerçek dünya senaryosunda network izolasyonu şart:

# Private endpoint oluştur
az network private-endpoint create 
  --name pe-cosmosdb-prod 
  --resource-group rg-cosmosdb-prod 
  --vnet-name vnet-prod 
  --subnet subnet-data 
  --private-connection-resource-id $(az cosmosdb show 
    --name cosmos-myapp-prod 
    --resource-group rg-cosmosdb-prod 
    --query id -o tsv) 
  --group-id Sql 
  --connection-name conn-cosmosdb-prod

# Public network erişimini tamamen kapat
az cosmosdb update 
  --name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --public-network-access Disabled

# IP firewall kuralı ekle (sadece geliştirme için, production'da kullanmayın)
az cosmosdb update 
  --name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --ip-range-filter "203.0.113.0/24,198.51.100.0/24"

Connection string’i güvenli şekilde almak için:

# Primary connection string (Azure Key Vault'a aktarın, kod içinde tutmayın!)
az cosmosdb keys list 
  --name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --type connection-strings 
  --query "connectionStrings[0].connectionString" 
  -o tsv

# Key Vault'a kaydet
az keyvault secret set 
  --vault-name kv-myapp-prod 
  --name CosmosDbConnectionString 
  --value "$(az cosmosdb keys list 
    --name cosmos-myapp-prod 
    --resource-group rg-cosmosdb-prod 
    --type connection-strings 
    --query 'connectionStrings[0].connectionString' -o tsv)"

Monitoring ve Alerting Kurulumu

Cosmos DB’de dikkat etmeniz gereken iki kritik metrik var: Request Units (RU) tüketimi ve 429 Too Many Requests hataları. Throttling başladığında uygulamanız yavaşlar.

# Log Analytics Workspace oluştur
az monitor log-analytics workspace create 
  --resource-group rg-cosmosdb-prod 
  --workspace-name law-cosmosdb-prod 
  --location westeurope 
  --sku PerGB2018

# Diagnostic settings ekle
az monitor diagnostic-settings create 
  --name diag-cosmosdb-prod 
  --resource $(az cosmosdb show 
    --name cosmos-myapp-prod 
    --resource-group rg-cosmosdb-prod 
    --query id -o tsv) 
  --workspace $(az monitor log-analytics workspace show 
    --resource-group rg-cosmosdb-prod 
    --workspace-name law-cosmosdb-prod 
    --query id -o tsv) 
  --logs '[
    {"category": "DataPlaneRequests", "enabled": true, "retentionPolicy": {"days": 30, "enabled": true}},
    {"category": "QueryRuntimeStatistics", "enabled": true, "retentionPolicy": {"days": 30, "enabled": true}},
    {"category": "PartitionKeyStatistics", "enabled": true, "retentionPolicy": {"days": 30, "enabled": true}},
    {"category": "ControlPlaneRequests", "enabled": true, "retentionPolicy": {"days": 90, "enabled": true}}
  ]' 
  --metrics '[
    {"category": "Requests", "enabled": true, "retentionPolicy": {"days": 30, "enabled": true}}
  ]'

Throttling için alert oluşturalım:

# 429 hatası alert kuralı
az monitor metrics alert create 
  --name alert-cosmosdb-throttling 
  --resource-group rg-cosmosdb-prod 
  --scopes $(az cosmosdb show 
    --name cosmos-myapp-prod 
    --resource-group rg-cosmosdb-prod 
    --query id -o tsv) 
  --condition "count TotalRequestUnits where StatusCode includes '429' > 100" 
  --window-size 5m 
  --evaluation-frequency 1m 
  --severity 2 
  --action-group ag-oncall-prod 
  --description "Cosmos DB throttling detected - RU limit exceeded"

Log Analytics ile Performans Analizi

Diagnostic logs kurulduktan sonra KQL (Kusto Query Language) ile derinlemesine analiz yapabilirsiniz:

# Azure CLI üzerinden KQL sorgusu çalıştırma örneği
az monitor log-analytics query 
  --workspace $(az monitor log-analytics workspace show 
    --resource-group rg-cosmosdb-prod 
    --workspace-name law-cosmosdb-prod 
    --query customerId -o tsv) 
  --analytics-query "
    AzureDiagnostics
    | where ResourceType == 'DATABASEACCOUNTS'
    | where Category == 'DataPlaneRequests'
    | where statusCode_s == '429'
    | summarize ThrottledRequests = count() by bin(TimeGenerated, 5m), collectionName_s
    | order by TimeGenerated desc
    | take 100
  " 
  --output table

Bu sorgu hangi collection’ların throttling yaşadığını gösterir. Eğer belirli bir container sürekli throttling görüyorsa, throughput artırmanız ya da partition key stratejinizi gözden geçirmeniz gerekiyor.

Partition Key Stratejisi: En Kritik Karar

Cosmos DB’de en sık yapılan hata yanlış partition key seçmektir. Bu karar sonradan değiştirilemez ve performansı doğrudan etkiler.

İyi bir partition key özellikleri:

  • Yüksek kardinalite: Binlerce farklı değer alabilmeli. /status gibi alanlar felaket olur, sadece 3-5 değer alır
  • Okuma/yazma dağılımı: Sorguların büyük çoğunluğu aynı partition key değeriyle yapılabilmeli
  • Hot partition olmamalı: Bir müşteri günde 1 milyon işlem yaparken diğeri 10 işlem yapıyorsa /customerId sorun çıkarır

E-ticaret senaryosunda gerçekçi bir örnek:

  • Sipariş verisi için /customerId + synthetic partition key kombinasyonu düşünün
  • Ürün kataloğu için /categoryId mantıklı
  • Kullanıcı profili için /userId ideal, tek kullanıcı verisi tek partition’da kalır
  • Log verisi için /date kesinlikle yanlış, tüm günlük log aynı partition’a gider

Backup ve Restore Yönetimi

Cosmos DB iki farklı backup modu sunar. Periodic backup varsayılan, continuous backup ise point-in-time restore sağlar:

# Mevcut backup politikasını görüntüle
az cosmosdb show 
  --name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --query "backupPolicy" 
  -o json

# Continuous backup moduna geç (geri dönüşü yok, dikkatli olun)
az cosmosdb update 
  --name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --backup-policy-type Continuous

# Point-in-time restore işlemi (yeni hesap oluşturur)
az cosmosdb restore 
  --target-database-account-name cosmos-myapp-restored 
  --account-name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --restore-timestamp "2024-01-15T10:30:00Z" 
  --location westeurope

Continuous backup ile 30 güne kadar geriye gidebilirsiniz. Bir geliştirici yanlışlıkla production container’ı temizlediğinde bu özellik can kurtarıcı olur.

Maliyet Optimizasyonu

Cosmos DB faturası kontrol edilmezse beklenmedik seviyelere çıkabilir. Birkaç pratik önlem:

Serverless mod: Geliştirme ve test ortamları için mükemmel. Sıfır taban maliyet, sadece kullandığınız RU için ödeme yaparsınız. Production’da tahmin edilemeyen yük için uygun değil.

TTL (Time-to-Live) kullanın: Geçici verileri otomatik silmek hem depolama maliyetini düşürür hem de index boyutunu küçülterek okuma performansını artırır.

# Container üzerinde TTL etkinleştir
az cosmosdb sql container update 
  --account-name cosmos-myapp-prod 
  --resource-group rg-cosmosdb-prod 
  --database-name ProductionDB 
  --name Sessions 
  --ttl 86400

# Hesap bazlı maliyet görüntüleme
az consumption usage list 
  --start-date 2024-01-01 
  --end-date 2024-01-31 
  --query "[?contains(instanceName, 'cosmos-myapp-prod')]" 
  --output table

Analitik depolama (Synapse Link): Analitik sorgular için row-store yerine column-store kullanın. Raporlama sorgularınız operational workload’u etkilemez ve RU tüketmez.

Shared throughput: Birden fazla küçük container varsa, veritabanı seviyesinde throughput paylaştırın. Her container’a ayrı throughput vermek yerine 1000 RU/s’yi 5 container’a dağıtmak çok daha ekonomik.

Gerçek Dünya Senaryosu: E-Ticaret Platformu Migrasyonu

Bir müşterinin MongoDB on-premises kurulumunu Cosmos DB MongoDB API’ye taşıdığımızda şu adımları izledik:

İlk olarak mevcut MongoDB veri boyutunu analiz ettik. 500 GB veri, 50 collection, en büyük collection’da 80 milyon belge vardı. Partition key analizinde şunu gördük: Sipariş collection’ı orderId ile partition’lanmış, ama sorguların yüzde 90’ı customerId bazlı yapılıyordu. Bu, her sorguda cross-partition fan-out anlamına geliyordu, yani büyük maliyet.

# MongoDB API hesabı oluştur
az cosmosdb create 
  --name cosmos-ecommerce-prod 
  --resource-group rg-cosmos-prod 
  --kind MongoDB 
  --server-version "4.2" 
  --locations regionName=westeurope failoverPriority=0 
  --default-consistency-level Session 
  --enable-automatic-failover true

# MongoDB collection oluştur doğru partition key ile
az cosmosdb mongodb collection create 
  --account-name cosmos-ecommerce-prod 
  --resource-group rg-cosmos-prod 
  --database-name ecommerce 
  --name orders 
  --shard "/customerId" 
  --throughput 5000

Migration sürecinde mongodump/mongorestore yerine Azure Database Migration Service kullandık. Çevrimiçi migrasyon sayesinde kesintiyi sıfıra indirdik. İlk sync tamamlandıktan sonra uygulamayı yeni connection string’e yönlendirdik ve eski MongoDB’yi salt okunur moda aldık. 24 saat gözlem sonrası eski sistemi kapattık.

Sık Karşılaşılan Sorunlar ve Çözümleri

429 Too Many Requests: Throughput limitine ulaştınız. Kısa vadede max throughput artırın. Uzun vadede sorgu optimizasyonu ve partition stratejisi gözden geçirin.

Request charge beklenenden yüksek: Büyük belge boyutları, cross-partition sorgular ve gereksiz index’ler başlıca sebeplerdir. Her belge için request charge değerini loglardan analiz edin.

Replication lag: Geo-redundant kurulumda secondary region geride kalıyorsa consistency level’ı kontrol edin. Session consistency sadece oturum içinde garanti verir, Bounded Staleness daha güçlü garanti ister ama maliyet artar.

Connection pool tükenmesi: SDK default ayarları çoğu senaryo için yetersizdir. .NET SDK için CosmosClientOptions içinde MaxRetryAttemptsOnRateLimitedRequests ve MaxRetryWaitTimeOnRateLimitedRequests değerlerini ayarlayın.

Sonuç

Azure Cosmos DB, doğru yapılandırıldığında gerçekten etkileyici bir platform. Ama bu “doğru yapılandırma” kısmı bazen göz ardı ediliyor. Partition key seçimi, throughput stratejisi, network güvenliği ve monitoring kurulumu olmadan Cosmos DB hem pahalı hem de öngörülemeyen bir hizmet haline gelebilir.

Özetlemek gerekirse öncelikleriniz şunlar olmalı: Önce partition key’i doğru seçin, sonradan değiştiremezsiniz. Autoscale kullanın, sabit throughput nadiren ekonomiktir. Private endpoint ile güvenliği sağlayın, public erişimi kapatın. Diagnostic logs açın, kör uçmayın. TTL ile eski verileri temizleyin, depolama maliyetini kontrol altında tutun.

Cosmos DB’yi masraf merkezi değil, ölçeklenebilirlik yatırımı olarak gördüğünüzde tablonun nasıl değiştiğini fark edeceksiniz. Küresel bir kullanıcı tabanına hizmet verirken milisaniye gecikme süreleri gerçekten rekabet avantajı sağlıyor.

Bir yanıt yazın

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