Windows Server’da Kapasite Planlaması ve Raporlama

Kapasite planlaması deyince aklıma hep aynı sahne geliyor: Cuma akşamı 17:30, herkes çıkmak üzere, tam o sırada bir uygulama sunucusu disk dolduğu için çöküyor. Sonra bakıyorsun, son 3 aydır disk kullanımı düzenli olarak artıyormuş ama kimse izlememiş, kimse rapor almamış. İşte bu yazıyı tam da bu yüzden yazıyorum.

Windows Server ortamlarında kapasite planlaması, reaktif değil proaktif bir yaklaşım gerektiriyor. Sadece “şu an ne kadar dolmuş” sorusunu değil, “6 ay sonra nerede olacağız” sorusunu da yanıtlaması gerekiyor. Bu ikisi arasındaki fark, iyi bir sysadmin ile sürekli yangın söndüren birinin farkıdır.

Kapasite Planlamasının Temelleri

Önce şunu netleştirelim: Kapasite planlaması sadece disk ve RAM izlemek değil. CPU, ağ bant genişliği, IOPS, bağlantı havuzları, lisans kullanımı hepsi birer kapasite bileşeni. Ama pratikte çoğu ortamda en kritik üç alan şunlar: depolama, bellek ve işlemci. Bu üçünü doğru ölçemiyorsan geri kalanı zaten anlamsız.

Windows Server’da bu verileri toplamanın birkaç yolu var: Performance Monitor (Perfmon), PowerShell, WMI sorgularla ve üçüncü parti araçlar. Ben genellikle yerleşik araçlarla başlarım, çünkü her ortamda olmak zorunda olan araçlardır.

Performance Monitor ile Veri Toplayıcı Kümeleri

Perfmon’un GUI kısmı çoğu sysadmin’in bildiği yer, ama asıl güç “Data Collector Sets” kısmında. Buradan düzenli aralıklarla veri toplayıp .blg dosyalarına yazabilirsiniz. Sonra bu verileri analiz ederek trend çıkartabilirsiniz.

Logman aracı, komut satırından Data Collector Set oluşturmanızı sağlar:

logman create counter "KapasitePlan_Aylik" `
  -c "Processor(_Total)% Processor Time" `
     "MemoryAvailable MBytes" `
     "LogicalDisk(C:)% Free Space" `
     "LogicalDisk(C:)Avg. Disk Queue Length" `
     "Network Interface(*)Bytes Total/sec" `
  -si 00:05:00 `
  -f csv `
  -o "C:PerfLogsKapasiteRapor%computername%_perf.csv" `
  -b 01/01/2025 00:00:00 `
  -e 31/12/2025 23:59:59 `
  -rf 30.00:00:00

Bu komut her 5 dakikada bir veri toplar ve 30 gün boyunca çalışır. CSV çıktısı aldığınızda Excel veya Power BI’a doğrudan aktarabilirsiniz.

PowerShell ile Anlık Kapasite Raporu

Anlık durum tespiti için aşağıdaki script temel ihtiyaçları karşılıyor. Birden fazla sunucuya aynı anda bağlanıp veri çekebilirsiniz:

$sunucular = @("SRV-APP01", "SRV-DB01", "SRV-WEB01", "SRV-FILE01")

$rapor = foreach ($sunucu in $sunucular) {
    try {
        $os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $sunucu -ErrorAction Stop
        $cpu = Get-WmiObject -Class Win32_Processor -ComputerName $sunucu
        $diskler = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $sunucu -Filter "DriveType=3"

        $bellek_toplam_gb = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2)
        $bellek_bos_gb   = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
        $bellek_kullanim = [math]::Round((($bellek_toplam_gb - $bellek_bos_gb) / $bellek_toplam_gb) * 100, 1)

        foreach ($disk in $diskler) {
            $disk_toplam_gb = [math]::Round($disk.Size / 1GB, 2)
            $disk_bos_gb    = [math]::Round($disk.FreeSpace / 1GB, 2)
            $disk_kullanim  = [math]::Round((($disk_toplam_gb - $disk_bos_gb) / $disk_toplam_gb) * 100, 1)

            [PSCustomObject]@{
                Sunucu          = $sunucu
                Disk            = $disk.DeviceID
                DiskToplamGB    = $disk_toplam_gb
                DiskBosGB       = $disk_bos_gb
                DiskKullanim    = "$disk_kullanim%"
                BellekToplamGB  = $bellek_toplam_gb
                BellekKullanim  = "$bellek_kullanim%"
                Tarih           = (Get-Date -Format "yyyy-MM-dd HH:mm")
            }
        }
    }
    catch {
        Write-Warning "$sunucu sunucusuna bagilanılamadı: $_"
    }
}

$rapor | Export-Csv -Path "C:Raporlarkapasite_$(Get-Date -Format 'yyyyMMdd').csv" `
         -NoTypeInformation -Encoding UTF8

$rapor | Format-Table -AutoSize

Bu script’i Task Scheduler’a ekleyip her sabah 07:00’de çalıştırırsanız, ofise geldiğinizde güncellemiş bir CSV dosyanız hazır olur.

Trend Analizi: Asıl İş Buradan Başlıyor

Anlık snapshot almak kolay, ama kapasite planlamasının can damarı geçmiş verilere bakarak gelecek tahmini yapmak. Bunun için düzenli veri toplamak ve bunu analiz etmek gerekiyor.

Aşağıdaki script, geçmiş CSV’leri okuyup belirli bir metriğin zaman içindeki değişimini çıkarıyor:

$veri_klasoru = "C:Raporlar"
$hedef_sunucu = "SRV-DB01"
$hedef_disk   = "C:"

$tum_veriler = Get-ChildItem -Path $veri_klasoru -Filter "kapasite_*.csv" |
    Sort-Object Name |
    ForEach-Object {
        Import-Csv $_.FullName -Encoding UTF8
    }

$filtrelenmis = $tum_veriler |
    Where-Object { $_.Sunucu -eq $hedef_sunucu -and $_.Disk -eq $hedef_disk } |
    Select-Object Tarih,
                  @{N="DiskKullanim_Yuzde"; E={ [double]($_.DiskKullanim -replace '%','') }},
                  DiskBosGB

$filtrelenmis | Sort-Object Tarih |
    Format-Table -AutoSize

# Basit lineer trend hesabı
$veri_sayisi = $filtrelenmis.Count
if ($veri_sayisi -ge 7) {
    $ilk_deger = ($filtrelenmis | Sort-Object Tarih | Select-Object -First 1).DiskKullanim_Yuzde
    $son_deger = ($filtrelenmis | Sort-Object Tarih | Select-Object -Last 1).DiskKullanim_Yuzde
    $gunluk_artis = ($son_deger - $ilk_deger) / $veri_sayisi

    $kalan_kapasite = 100 - $son_deger
    $dolu_olacak_gun = [math]::Round($kalan_kapasite / $gunluk_artis)

    Write-Host "`n=== TREND ANALİZİ ===" -ForegroundColor Cyan
    Write-Host "Sunucu       : $hedef_sunucu" -ForegroundColor White
    Write-Host "Disk         : $hedef_disk" -ForegroundColor White
    Write-Host "Günlük artış : $([math]::Round($gunluk_artis, 2))%" -ForegroundColor Yellow
    Write-Host "Tahmini dolma: $dolu_olacak_gun gün sonra" -ForegroundColor Red
}

Bu basit lineer model, düzensiz büyüme gösteren sistemler için yanıltıcı olabilir. Ama %80 doğrulukla “3 ay içinde sıkıntı yaşarsın” diyebilmek bile büyük değer.

SQL Server Logları ve Windows Event Log’dan Kapasite Sinyalleri

Bir veritabanı sunucusunda kapasite problemleri çoğu zaman disk dolmadan önce başka yerlerden sinyal verir. Transaction log büyümesi, TempDB şişmesi, bunlar birer uyarı işareti. Ama Windows Event Log’da da önemli kapasite olayları var:

# Son 7 günde disk doluluğuna dair Event ID'leri tara
$kritik_eventler = Get-WinEvent -ComputerName "SRV-DB01" `
    -FilterHashtable @{
        LogName   = 'System'
        Id        = @(2013, 2004, 7, 4226)
        StartTime = (Get-Date).AddDays(-7)
    } -ErrorAction SilentlyContinue

# Event ID referansı:
# 2013: Disk doldu uyarısı
# 2004: Bellek baskısı (Working Set trimming)
# 7   : Hizmet başlatma hatası (kaynak yetersizliği)

if ($kritik_eventler) {
    Write-Host "Son 7 günde $($kritik_eventler.Count) kritik kapasite eventi bulundu:" -ForegroundColor Red
    $kritik_eventler | Select-Object TimeCreated, Id, Message |
        Sort-Object TimeCreated -Descending |
        Format-List
} else {
    Write-Host "Son 7 günde kritik kapasite eventi yok." -ForegroundColor Green
}

HTML Rapor Oluşturma

Kapasite verilerini yöneticilere veya müşterilere sunmak için HTML rapor şart. Bakımı kolay, e-posta ile gönderilebilir ve özelleştirme esnekliği var:

function New-KapasiteRaporu {
    param (
        [string[]]$Sunucular,
        [string]$CiktiDosyasi = "C:Raporlarkapasite_raporu.html"
    )

    $html_header = @"
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>Kapasite Raporu - $(Get-Date -Format 'dd.MM.yyyy')</title>
<style>
  body { font-family: Segoe UI, sans-serif; font-size: 13px; background: #f5f5f5; }
  h2   { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 5px; }
  .blok { background: white; border-radius: 6px; padding: 16px; margin: 10px 0;
           box-shadow: 0 1px 4px rgba(0,0,0,.1); }
  .kritik { color: #e74c3c; font-weight: bold; }
  .uyari  { color: #f39c12; font-weight: bold; }
  .iyi    { color: #27ae60; }
</style>
</head>
<body>
<div class="blok">
<h2>Sunucu Kapasite Raporu</h2>
<p>Rapor tarihi: <strong>$(Get-Date -Format 'dd.MM.yyyy HH:mm')</strong></p>
"@

    $html_body = ""

    foreach ($sunucu in $Sunucular) {
        try {
            $os     = Get-WmiObject Win32_OperatingSystem -ComputerName $sunucu -EA Stop
            $diskler = Get-WmiObject Win32_LogicalDisk -ComputerName $sunucu -Filter "DriveType=3"
            $bellek_pct = [math]::Round((1 - ($os.FreePhysicalMemory / $os.TotalVisibleMemorySize)) * 100, 1)

            $html_body += "<div class='blok'><h3>$sunucu</h3>"
            $html_body += "<p>Bellek Kullanımı: <span class='$(if($bellek_pct -gt 90){"kritik"} elseif($bellek_pct -gt 75){"uyari"} else {"iyi"})'>$bellek_pct%</span></p>"

            foreach ($disk in $diskler) {
                $pct  = [math]::Round((1 - ($disk.FreeSpace / $disk.Size)) * 100, 1)
                $bos  = [math]::Round($disk.FreeSpace / 1GB, 1)
                $sinif = if ($pct -gt 90) { "kritik" } elseif ($pct -gt 75) { "uyari" } else { "iyi" }
                $html_body += "<p>Disk $($disk.DeviceID): <span class='$sinif'>$pct% dolu</span> | Boş: ${bos} GB</p>"
            }

            $html_body += "</div>"
        }
        catch {
            $html_body += "<div class='blok'><p class='kritik'>$sunucu : Bağlantı hatası</p></div>"
        }
    }

    $html_footer = "</div></body></html>"
    $html_header + $html_body + $html_footer | Out-File $CiktiDosyasi -Encoding UTF8
    Write-Host "Rapor oluşturuldu: $CiktiDosyasi" -ForegroundColor Green
}

New-KapasiteRaporu -Sunucular @("SRV-APP01","SRV-DB01","SRV-WEB01")

E-posta ile Otomatik Kapasite Uyarısı

Raporu oluşturmak yetmez, ilgililere ulaşması gerekiyor. Aşağıdaki yapı, disk %85’in üzerine çıktığında otomatik e-posta gönderiyor:

$esik_yuzde = 85
$smtp_sunucu = "mail.sirket.local"
$gonderen    = "[email protected]"
$alicilar    = @("[email protected]", "[email protected]")

$sunucular = @("SRV-APP01","SRV-DB01","SRV-WEB01","SRV-FILE01")
$uyarilar  = @()

foreach ($sunucu in $sunucular) {
    try {
        $diskler = Get-WmiObject Win32_LogicalDisk -ComputerName $sunucu `
                   -Filter "DriveType=3" -ErrorAction Stop

        foreach ($disk in $diskler) {
            $pct = [math]::Round((1 - ($disk.FreeSpace / $disk.Size)) * 100, 1)
            if ($pct -ge $esik_yuzde) {
                $uyarilar += "UYARI: $sunucu - $($disk.DeviceID) diski $pct% dolu " +
                             "($([math]::Round($disk.FreeSpace/1GB,1)) GB boş)"
            }
        }
    }
    catch {
        $uyarilar += "HATA: $sunucu sunucusuna ulaşılamadı."
    }
}

if ($uyarilar.Count -gt 0) {
    $mesaj_govde = "Otomatik Kapasite Uyarısı`n`nTarih: $(Get-Date -Format 'dd.MM.yyyy HH:mm')`n`n"
    $mesaj_govde += $uyarilar -join "`n"
    $mesaj_govde += "`n`nLütfen ilgili sunucuları kontrol ediniz."

    Send-MailMessage `
        -From      $gonderen `
        -To        $alicilar `
        -Subject   "[KAPASİTE UYARISI] Disk Eşiği Aşıldı - $(Get-Date -Format 'dd.MM.yyyy')" `
        -Body      $mesaj_govde `
        -SmtpServer $smtp_sunucu `
        -Encoding  UTF8
    
    Write-Host "$($uyarilar.Count) uyarı e-posta ile gönderildi." -ForegroundColor Yellow
}

Büyüme Projeksiyonu ve Kapasite Karar Mekanizması

Veri toplamak ve raporlamak işin teknik kısmı. Ama bütün bunların bir yönetim kararına dönüşmesi için net bir dil lazım. Yöneticiler “disk %78 dolu” yerine “X ay sonra problem yaşayacağız, şimdiden Y TB alırsak Z ay kazanırız” duymak istiyor.

Bunun için kapasite projeksiyonunu şu parametreler üzerinden kurabilirsiniz:

Mevcut kullanım yüzdesi: Anlık ölçüm değil, son 30 günün ortalamasını alın. Ani bir yedekleme işlemi nedeniyle o gün disk dolmuş olabilir.

Büyüme hızı: Haftalık veya aylık bazda hesaplayın. Bazı sistemler mevsimsel büyüme gösterir, e-ticaret siteleri yılın belirli dönemlerinde patlar, muhasebe sistemleri dönem kapanışlarında.

Emniyet tamponu: Hiçbir zaman bir diski %95’e kadar doldurmayın. %80 planlama sınırı, %90 alarm sınırı, %95 kriz sınırı şeklinde çalışmak güvenli bir yaklaşım. NTFS’de sistem dosyaları için rezerv alan, SQL Server log operasyonları için alan, anlık yedeklemeler için alan hep gerekiyor.

Temin süresi: Yeni disk alanı veya sunucu eklemek ne kadar sürüyor? Satın alma, onay süreçleri, kurulum. Bu süreyi geriye sayarak planlama yapın. 3 aylık temin süresi varsa, 3 ay dolmadan önce süreci başlatmak gerekiyor.

Scheduled Task ile Otomasyonu Tamamlamak

Bütün bu script’leri tek seferlik değil düzenli çalışacak şekilde ayarlamak gerekiyor. Task Scheduler’a PowerShell script kaydetmek için:

$eylem = New-ScheduledTaskAction `
    -Execute "powershell.exe" `
    -Argument "-NonInteractive -NoProfile -ExecutionPolicy Bypass -File C:Scriptskapasite_rapor.ps1"

$tetikleyici_gunluk = New-ScheduledTaskTrigger -Daily -At "07:00"
$tetikleyici_haftalik = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At "08:00"

$ayarlar = New-ScheduledTaskSettingsSet `
    -ExecutionTimeLimit (New-TimeSpan -Minutes 30) `
    -RestartCount 2 `
    -RestartInterval (New-TimeSpan -Minutes 5)

Register-ScheduledTask `
    -TaskName    "KapasitePlanlamaGunluk" `
    -Action      $eylem `
    -Trigger     $tetikleyici_gunluk `
    -Settings    $ayarlar `
    -RunLevel    Highest `
    -User        "DOMAINsvc_monitoring" `
    -Description "Günlük kapasite raporu ve uyarı gönderimi"

Write-Host "Zamanlanmış görev oluşturuldu." -ForegroundColor Green

Servis hesabı kullanmak önemli. Kişisel kullanıcı hesabıyla çalışan tasklar, kullanıcı şifre değişikliğinde veya hesap kilitlendiğinde sessizce çalışmayı bırakır ve haber bile vermez.

Sonuç

Windows Server ortamında kapasite planlaması; performans verisi toplamak, saklamak, analiz etmek ve bunu eyleme dönüştürmek zincirinden oluşuyor. Bu yazıda anlattığım yöntemler sıfır bütçeyle, yerleşik araçlarla uygulanabilir. Ek bir lisans veya araç gerekmez.

Başlangıç için minimum uygulanabilir yaklaşım şu şekilde olabilir: Her gün sabah çalışan bir PowerShell script’i, her hafta Pazartesi gönderilen bir HTML e-posta raporu ve kritik eşikler aşıldığında anlık uyarı. Bu üçü bile sizi o Cuma akşamı sürprizinden büyük ölçüde korur.

Daha uzun vadede ise topladığınız verileri Power BI’a bağlayıp görselleştirmek, anomali tespiti için basit istatistiksel modeller kurmak, farklı iş yükleri için ayrı büyüme profilleri çıkarmak değer katacak adımlar. Ama her şeyden önce veri toplamaya başlamak lazım. Geçmişi ölçmeden geleceği tahmin edemezsiniz.

Bir yanıt yazın

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