Exchange Server’da Kapasite Planlaması ve Boyutlandırma

Kapasite planlaması konusu, Exchange projelerinde hep en çok ertelenen ama en çok acı çektiren kısım olmuştur. “Önce kaldıralım, sonra büyütürüz” mantığıyla kurulan sistemlerin nasıl bir gece mesaisine dönüştüğünü bizzat yaşadım. Bu yazıda Exchange Server için gerçekçi, ölçülebilir ve sahada işe yarayan bir boyutlandırma yaklaşımı anlatacağım.

Neden Kapasite Planlaması Bu Kadar Kritik?

Exchange, Microsoft’un en kaynak yoğun ürünlerinden biri. Bunu hafife alan ortamlarda ne olur? Kullanıcılar sabah 9’da Outlook’u açtığında sunucu yanıt vermez, RPC bağlantıları zaman aşımına uğrar, MoveMailbox işlemleri günlerce sürer. IT müdürü sizi arar, siz de “donanım yetersiz” dersiniz ama bu bahaneler kimseyi tatmin etmez.

Doğru boyutlandırma için şu üç soruyu net yanıtlamanız gerekiyor:

  • Kaç kullanıcı, nasıl kullanıyor?
  • Verinin bugünkü ve 3 yıl sonraki boyutu ne olacak?
  • Hangi servis seviyesi taahhüdü (SLA) geçerli?

Bu sorulara sağlam yanıtlar vermeden yapılan her planlama tahmin değil, kumar.

Kullanıcı Profili Analizi

Exchange boyutlandırmasında Microsoft’un yıllardır kullandığı “mailbox profile” kavramı hâlâ geçerliliğini koruyor. Temel profiller şunlar:

  • Light kullanıcı: Günde 5-10 mesaj gönderen, 50 MB’ın altında posta kutusu olan, Outlook’u seyrek kullanan. Muhasebe ekibindeki bazı personel, depo çalışanları bu gruba girer.
  • Average kullanıcı: Günde 50-75 mesaj, 1-2 GB posta kutusu, sürekli bağlı Outlook istemcisi. Çoğu ofis çalışanı buradadır.
  • Heavy kullanıcı: Günde 150+ mesaj, büyük ekler, 10 GB üzeri posta kutusu, mobil cihaz + Outlook + OWA kombinasyonu. Satış ekipleri, yöneticiler.

Mevcut bir ortamı analiz ediyorsanız, Exchange Management Shell ile gerçek verileri çekebilirsiniz:

# Tum kullanici posta kutusu boyutlarini ve mesaj sayilarini al
Get-Mailbox -ResultSize Unlimited | 
Get-MailboxStatistics | 
Select-Object DisplayName, TotalItemSize, ItemCount, LastLogonTime |
Export-Csv C:ReportsMailboxStats.csv -NoTypeInformation -Encoding UTF8

Bu çıktıyı Excel’e aktarıp histograma döküldüğünde gerçek dağılımı görürsünüz. Genellikle şunu fark edersiniz: Kullanıcıların %20’si toplam posta kutusu alanının %60’ını tüketiyor. Bu grup “heavy” kategoriye girer ve boyutlandırmayı onlara göre yapmanız gerekir.

CPU Boyutlandırması

Exchange 2016 ve 2019 için Microsoft’un referans metriği megacycles per second (Mcycles/sec) cinsinden hesaplanır. Ama pratik sahada şu basit formülü kullanıyorum:

Her 1000 aktif kullanıcı için yaklaşık 2 fiziksel çekirdek (heavy profil). Light kullanıcı ağırlıklı ortamlarda bu sayı 3000’e kadar çıkabilir.

Yeni kurulum yapıyorsanız önce mevcut ortamın CPU tüketimini ölçmek yerine Perfmon ile Exchange’e özel sayaçları takip edin:

# Exchange CPU ve RPC sayaclarini logla (PowerShell ile)
$counters = @(
    "Processor(_Total)% Processor Time",
    "MSExchange RPC Client AccessRPC Requests",
    "MSExchange RPC Client AccessRPC Averaged Latency",
    "MSExchangeIS Store(*)RPC Requests",
    "MSExchangeIS Store(*)RPC Average Latency"
)

$logFile = "C:PerfLogsExchange_Perf_$(Get-Date -Format 'yyyyMMdd').blg"

Start-Process -FilePath "logman" -ArgumentList "create counter ExchangePerf -cf `"$($counters -join '`n')`" -f bincirc -si 30 -max 512 -o `"$logFile`" -ow" -NoNewWindow

RPC Average Latency değeri 250 ms’nin altında kalmalı. Bu eşiği sürekli geçiyorsanız ya CPU yetersizdir ya da disk I/O darboğazı vardır.

Bellek Planlaması

Exchange’in bellek iştahı ciddi. Mailbox Database’lerin ESE cache mekanizması, ne kadar RAM verirseniz o kadar kullanır ve bu aslında istenen bir durum. Daha büyük cache = daha az disk okuması = daha iyi performans.

Minimum RAM hesabı:

  • İşletim sistemi için: 4 GB
  • Exchange base: 4 GB
  • Her aktif posta kutusu veritabanı için: 1-2 GB
  • Ek ESE cache için buffer: Kalan her şey

500 kullanıcı ve 4 veritabanı olan bir ortam için:

4 (OS) + 4 (Exchange) + 8 (4 DB x 2GB) + buffer = minimum 32 GB
Tercihen 64 GB

Mevcut sistemde cache’in etkin kullanılıp kullanılmadığını kontrol etmek için:

# Exchange Store cache durumu
Get-Counter "MSExchangeIS Store(*)Page Reads/sec" -SampleInterval 5 -MaxSamples 12 |
    ForEach-Object {
        $_.CounterSamples | 
        Select-Object InstanceName, 
            @{N="PageReadsPerSec";E={[math]::Round($_.CookedValue,2)}}
    }

Page Reads/sec değeri sürekli yüksekse (örneğin 20+), sistem diskten okumak zorunda kalıyor demektir. RAM artırımı bu noktada doğrudan performans kazanımına dönüşür.

Disk ve Storage Planlaması

Burası boyutlandırmanın en kritik noktası. Exchange veritabanları I/O yoğun yapılar, yanlış disk seçimi tüm sistemi çökertir.

IOPS Hesabı

Her kullanıcı profili için ortalama IOPS değerleri:

  • Light: ~0.05 IOPS/kullanıcı
  • Average: ~0.10 IOPS/kullanıcı
  • Heavy: ~0.25 IOPS/kullanıcı

500 heavy kullanıcı için: 500 x 0.25 = 125 IOPS (sadece veritabanı okuma/yazma için)

Transaction log yazmaları için %20 ek ekleyin: 125 x 1.20 = 150 IOPS minimum

Modern SSD’lerle bu artık sorun değil ama hâlâ eski SATA diskli sunucularla çalışan ortamlar var. 7200 RPM SATA disk başına ~75-80 random IOPS bekleyebilirsiniz. 3-4 disk RAID10 bile bu senaryoda yetersiz kalır.

Mevcut disk I/O durumunu analiz etmek için:

# Disk latency ve throughput olcumu
$diskCounters = @(
    "LogicalDisk(D:)Avg. Disk sec/Read",
    "LogicalDisk(D:)Avg. Disk sec/Write",
    "LogicalDisk(D:)Disk Reads/sec",
    "LogicalDisk(D:)Disk Writes/sec",
    "LogicalDisk(D:)% Disk Time"
)

Get-Counter $diskCounters -SampleInterval 10 -MaxSamples 6 |
    ForEach-Object { 
        $_.CounterSamples | 
        Format-Table Path, 
            @{N="Value";E={[math]::Round($_.CookedValue,4)}}, 
            Timestamp -AutoSize
    }

Kritik eşikler:

  • Avg. Disk sec/Read: 20ms altında olmalı (tercihen 10ms)
  • Avg. Disk sec/Write: 10ms altında olmalı
  • % Disk Time: Sürekli %80 üzerindeyse sorun var

Veritabanı Boyutu Projeksiyonu

Mevcut büyüme hızını hesaplayarak 2-3 yıllık projeksiyon yapın:

# Posta kutusu buyume trendini cek
$stats = Get-MailboxDatabase -Status | 
    Select-Object Name, DatabaseSize, AvailableNewMailboxSpace

foreach ($db in $stats) {
    $totalGB = [math]::Round(($db.DatabaseSize.ToBytes() / 1GB), 2)
    $freeGB  = [math]::Round(($db.AvailableNewMailboxSpace.ToBytes() / 1GB), 2)
    $usedGB  = $totalGB - $freeGB
    
    Write-Host "DB: $($db.Name) | Toplam: $totalGB GB | Kullanulan: $usedGB GB | Bos: $freeGB GB"
}

Bu verileri 6 ay önce ve bugün karşılaştırırsanız aylık büyüme oranını çıkarabilirsiniz. Aylık %5 büyüme görüyorsanız, 2 yıl sonra alan ihtiyacınız yaklaşık 3.2 kat artmış olacak. Buna göre depolama alın.

Veritabanı Tasarımı ve Boyutlandırma

Kaç tane veritabanı olmalı? Bu sorunun pratik cevabı şu: Kullanıcı başına 2-4 GB veritabanı boyutu hedefleyin, veritabanlarını yönetilebilir büyüklükte tutun.

500 kullanıcı, ortalama 5 GB posta kutusu = 2500 GB toplam. Bunu 5 adet 500 GB veritabanına bölmek, 2 adet 1.25 TB veritabanına kıyasla çok daha sağlıklı. Nedeni:

  • Backup/restore süreleri kısalır
  • Sorun yaşandığında etkilenen kullanıcı sayısı azalır
  • Defragmentasyon ve bakım süreleri makul kalır

Database Availability Group (DAG) kullanıyorsanız kopyalama gecikmeleri de daha az sorun çıkarır.

# Yeni veritabani olustur ve mailbox ekle
New-MailboxDatabase -Name "MBX-DB-03" `
    -EdbFilePath "D:ExchangeDBMBX-DB-03MBX-DB-03.edb" `
    -LogFolderPath "E:ExchangeLogsMBX-DB-03" `
    -Server EXCH01

# Veritabani kota ayarları
Set-MailboxDatabase "MBX-DB-03" `
    -IssueWarningQuota 8GB `
    -ProhibitSendQuota 9GB `
    -ProhibitSendReceiveQuota 10GB `
    -DeletedItemRetention 14.00:00:00 `
    -MailboxRetention 30.00:00:00

Log sürücüsünü veritabanı sürücüsünden her zaman ayırın. Bu iki I/O akışının rekabet etmesi, performansı dramatik biçimde düşürür.

Network Bant Genişliği Hesabı

Exchange için network genişliği genellikle gözardı edilir ama özellikle DAG ortamlarında kritik hale gelir.

İstemci trafiği tahmini:

  • Outlook Cached Mode: Kullanıcı başına ~0.5 Mbps peak
  • OWA: Kullanıcı başına ~0.3 Mbps peak
  • ActiveSync: Cihaz başına ~0.1 Mbps peak

DAG replikasyon trafiği:

Günlük toplam transaction log üretimini ölçün ve bunu üye sunucu sayısıyla çarpın. Aktif replikasyon sırasında 1 Gbps dedicated link önerilir; WAN üzerinden DAG yapıyorsanız minimum 100 Mbps garantili bant genişliği şart.

# Transaction log uretim hizini izle
Get-Counter "MSExchange Database ==> Instances(*)Log Record Stalls/sec",
            "MSExchange Database ==> Instances(*)Log Bytes Write/sec" `
    -SampleInterval 30 -MaxSamples 4 |
    ForEach-Object {
        $_.CounterSamples | 
        Where-Object {$_.InstanceName -ne "_total"} |
        Select-Object InstanceName, 
            @{N="Metric";E={$_.Path.Split("")[-1]}},
            @{N="Value";E={[math]::Round($_.CookedValue,2)}}
    }

Log Bytes Write/sec değerinin günlük ortalamasını alın, 86400 saniye ile çarpın, toplam günlük log üretimini MB cinsinden elde edin. Bu değer DAG replikasyon bant genişliği planlamanızın temelini oluşturur.

Sanallaştırma Ortamlarında Exchange

“Exchange’i VM üzerine kurmak doğru mu?” sorusu artık geçerliliğini yitirdi, çünkü doğru yapılandırılmış bir vSphere veya Hyper-V üzerinde Exchange mükemmel çalışıyor. Ama dikkat edilmesi gereken noktalar var:

NUMA topolojisine uyun: VM’e atadığınız vCPU sayısı, fiziksel NUMA node başına düşen çekirdek sayısını geçmesin. Aksi takdirde cross-NUMA erişimler bellek gecikmesini artırır ve bu Exchange için ölümcüldür.

Memory balloon sürücüsünü devre dışı bırakın: Exchange RAM’ini agresif kullandığı için hypervisor’ın belleği geri alması felaket olabilir.

Disk I/O’yu izole edin: Exchange VM’i shared datastorelar yerine dedicated disk kaynaklarına yönlendirin.

# Hyper-V uzerinde Exchange VM icin onerilecek ayarlar
# PowerShell ile yapılandırma

# Dynamic memory KAPALI olmali
Set-VMMemory -VMName "EXCH01" `
    -DynamicMemoryEnabled $false `
    -StartupBytes 65GB

# NUMA span kapatma
Set-VM -VMName "EXCH01" -NumaAligned $true

# Checkpointlari kapat (Exchange VSS ile celisir)
Set-VM -VMName "EXCH01" -CheckpointType Disabled

Gerçek Dünya Senaryosu: 800 Kullanıcılı Üretim Ortamı

Geçen yıl bir holding grubunun Exchange 2019 geçişinde şu yapıyı önerip uyguladık:

Ortam profili:

  • 800 kullanıcı (600 average, 200 heavy)
  • Mevcut posta kutusu ortalama boyutu: 6 GB
  • Büyüme trendi: Aylık %4
  • SLA: %99.9 uptime, mail teslim süresi max 2 dakika

Hesaplamalar:

Toplam depolama: 800 x 6 GB = 4.8 TB + %30 white space + 2 yıllık büyüme buffer (x1.5) = yaklaşık 9.4 TB kullanılabilir alan

IOPS: (600 x 0.10) + (200 x 0.25) = 110 IOPS minimum, peak için x2 = 220 IOPS

RAM: 2 sunucu, her birinde 128 GB, DAG ile aktif/aktif yapı

Sonuç yapı:

  • 2 adet Mailbox Server (DAG)
  • Her sunucuda 2x 10 çekirdek CPU
  • 128 GB RAM
  • All-flash storage, her sunucuda 2x 500 GB SSD (OS + Exchange binary) + 4x 2 TB NVMe (veritabanı)
  1. yılın sonunda sistemin kaynakların %65’ini kullandığını görüyoruz; büyüme devam ederse 3. yılda storage genişletmesi gerekecek ama CPU ve RAM hâlâ rahat.

Kapasite İzleme ve Erken Uyarı

Planlama bittikten sonra iş bitmez. Sürekli izleme olmadan kapasite planlaması kağıt üzerinde kalır. Şu metrikleri düzenli ölçün ve eşik aşıldığında alarm üretin:

# Haftalik kapasite raporu scripti
$report = @()
$databases = Get-MailboxDatabase -Status

foreach ($db in $databases) {
    $mbStats    = Get-MailboxStatistics -Database $db.Name
    $totalSize  = ($mbStats | Measure-Object TotalItemSize -Sum).Sum
    $dbSizeGB   = [math]::Round($db.DatabaseSize.ToBytes() / 1GB, 2)
    $freeSizeGB = [math]::Round($db.AvailableNewMailboxSpace.ToBytes() / 1GB, 2)
    $usedPct    = [math]::Round((($dbSizeGB - $freeSizeGB) / $dbSizeGB) * 100, 1)
    
    $report += [PSCustomObject]@{
        Database      = $db.Name
        TotalSizeGB   = $dbSizeGB
        FreeSizeGB    = $freeSizeGB
        UsedPercent   = $usedPct
        MailboxCount  = $mbStats.Count
        AlertStatus   = if ($usedPct -gt 80) {"KRITIK"} elseif ($usedPct -gt 65) {"UYARI"} else {"NORMAL"}
    }
}

$report | Format-Table -AutoSize

# Kritik durumlari e-posta ile bildir
$kritikDBler = $report | Where-Object {$_.AlertStatus -eq "KRITIK"}
if ($kritikDBler) {
    Send-MailMessage -To "[email protected]" `
        -From "[email protected]" `
        -Subject "Exchange Kapasite UYARISI" `
        -Body ($kritikDBler | Out-String) `
        -SmtpServer "localhost"
}

Bu scripti Task Scheduler’a her Pazartesi sabahı çalışacak şekilde ekleyin. Haftalık trendleri gözlemleyerek bir sonraki kapasite genişlemesini en az 3 ay önceden planlayabilirsiniz.

Sonuç

Exchange kapasite planlaması sezgiye değil, verilere dayanmalı. Kullanıcı profillerini doğru kategorize edin, mevcut tüketim metriklerini sistematik olarak toplayın, büyüme trendini en az 6 aylık geriye dönük veriye dayandırın.

En sık yapılan hata şu: Anlık peak değerleri yerine ortalama değerler üzerine boyutlandırma yapmak. Exchange sabah 8-9 arası, öğlen ve akşam üstü ciddi spike’lar yaşar. Peak yükü karşılayamayan bir sistem “çalışıyor ama yavaş” görünümü verir, sorun bulunması zaman alır ve kullanıcı memnuniyeti yerle bir olur.

Doğru yapılan bir kapasite planlaması, hem gereksiz donanım harcamasını engeller hem de sizi gece yarısı uyandıran olaylardan korur. Exchange hâlâ pek çok Türk kurumunun kritik iletişim altyapısı. Bunu hak ettiği ciddiyetle boyutlandırmak, sonunda sizin de işinizi kolaylaştırır.

Bir yanıt yazın

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