IIS Web Farm ile Yük Dengeleme Yapılandırması

Üretim ortamında yük dengeleme kurmak, teoride her zaman düzgün görünen ama pratikte insanı epey terletebilen bir süreç. Özellikle IIS tabanlı web farm yapılandırmalarında, küçük bir gözden kaçan detay saatlerce hata ayıklamaya dönüşebilir. Bu yazıda sıfırdan bir IIS Web Farm kurulumunu, ARR (Application Request Routing) ile yük dengelemeyi ve session yönetimini ele alacağız. Gerçek bir production ortamına hazır yapılandırma hedefliyoruz.

Mimari Genel Bakış

Temel senaryomuz şu şekilde: Önde bir ARR proxy sunucusu, arkada iki veya daha fazla IIS web sunucusu. Trafik ARR üzerinden gelir, arka taraftaki sunuculara dağıtılır. Bu yapıyı kurmak için ihtiyacımız olan bileşenler:

  • ARR (Application Request Routing): Microsoft’un IIS için sunduğu reverse proxy ve yük dengeleme modülü
  • Web Farm Framework (WFF): Sunucu grubunu merkezi yönetmek için
  • URL Rewrite Module: ARR’ın çalışabilmesi için zorunlu bağımlılık
  • Shared Configuration: Tüm node’ların aynı IIS yapılandırmasını paylaşması için

Mimari olarak şöyle düşün: ARR sunucusu hem proxy hem de sağlık kontrolü yapıyor. Bir backend node çöktüğünde, ARR bunu fark edip trafiği sağlıklı node’lara yönlendiriyor. Bu geçiş birkaç saniye içinde gerçekleşiyor.

Gerekli Modüllerin Kurulumu

İlk adım olarak ARR sunucusuna (proxy katmanı) gerekli modülleri yüklemeliyiz. Bu işlemi PowerShell ile yapabiliriz, ama önce Web Platform Installer veya doğrudan MSI dosyalarını kullanacağız.

# ARR ve URL Rewrite modüllerini kontrol et
Get-WebGlobalModule | Where-Object {$_.Name -like "*RequestRouter*" -or $_.Name -like "*RewriteModule*"}

# IIS yönetim konsolundan modül kurulum durumunu doğrula
Import-Module WebAdministration
Get-Module -ListAvailable | Where-Object {$_.Name -eq "WebAdministration"}

URL Rewrite Module’ü kurduktan sonra ARR’ı yükleyin. ARR kurulumu sırasında önemli bir nokta: kurulum tamamlandıktan sonra IIS’i yeniden başlatmanız gerekiyor, aksi takdirde modül düzgün yüklenmez.

# IIS servisini yeniden başlat
Restart-Service W3SVC -Force

# ARR modülünün yüklendiğini doğrula
& "$env:windirsystem32inetsrvappcmd.exe" list module /name:ApplicationRequestRouting

Server Farm Oluşturma

IIS Manager üzerinden Server Farm oluşturabilirsiniz, ama ben komut satırından yapmayı tercih ederim. Tekrarlanabilir ve script’e eklenebilir olması açısından çok daha kullanışlı.

# applicationHost.config üzerinden farm yapılandırması
# C:WindowsSystem32inetsrvconfigapplicationHost.config dosyasını düzenleyeceğiz
# Önce yedeğini al
Copy-Item "C:WindowsSystem32inetsrvconfigapplicationHost.config" `
          "C:WindowsSystem32inetsrvconfigapplicationHost.config.bak_$(Get-Date -Format 'yyyyMMdd_HHmmss')"

# Farm yapılandırmasını XML olarak ekle
$farmConfig = @"
<webFarms>
    <webFarm name="MyWebFarm" enabled="true">
        <server address="WEB01.domain.local" enabled="true">
            <applicationRequestRouting httpPort="80" />
        </server>
        <server address="WEB02.domain.local" enabled="true">
            <applicationRequestRouting httpPort="80" />
        </server>
        <applicationRequestRouting>
            <healthCheck url="http://WEB01.domain.local/health.aspx" 
                         interval="00:00:05" 
                         responseMatch="OK" />
            <loadBalancing algorithm="WeightedRoundRobin" />
        </applicationRequestRouting>
    </webFarm>
</webFarms>
"@

Write-Host "Farm yapılandırması hazır, IIS Manager'dan uygulayın veya appcmd kullanın"

IIS Manager üzerinden yapıyorsanız: Server Farms bölümüne sağ tıklayın, Create Server Farm seçin. Wizard sizi adım adım götürecek. Sunucu adreslerini girdikten sonra, wizard sizi URL Rewrite kuralı oluşturmak isteyip istemediğinizi soracak. Evet deyin, bu adımı atlamayın.

ARR Proxy Ayarları

Farm oluşturduktan sonra ARR’ın proxy modunu aktif etmemiz gerekiyor. Bu adım çok sık unutuluyor ve “neden çalışmıyor” sorularının başlıca kaynağı.

# ARR proxy özelliğini etkinleştir
$arrConfig = Get-WebConfiguration -PSPath "IIS:" -Filter "system.webServer/proxy"

# Proxy'yi etkinleştir
Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter "system.webServer/proxy" `
    -Name "enabled" `
    -Value $true

# Reverse rewrite host header aktif et
Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter "system.webServer/proxy" `
    -Name "reverseRewriteHostInResponseHeaders" `
    -Value $false

Write-Host "ARR Proxy modu aktif edildi"

reverseRewriteHostInResponseHeaders parametresini false yapma nedenimiz şu: Eğer true bırakırsanız, backend sunuculardan gelen redirect yanıtlarındaki Host header’ı ARR sunucusunun adresiyle değiştiriyor. Bu bazen istemci tarafında beklenmedik yönlendirme hatalarına yol açıyor. Özellikle HTTPS üzerinden çalışan uygulamalarda bu sorun daha sık karşılaşılır.

Yük Dengeleme Algoritmaları

ARR birkaç farklı yük dengeleme algoritması sunuyor:

  • WeightedRoundRobin: Her sunucuya sırayla istek gönderir, ağırlık değeri atanabilir
  • WeightedTotalTraffic: Toplam trafik miktarına göre dağıtım yapar
  • LeastRequests: En az aktif isteği olan sunucuya yönlendirir
  • LeastResponseTime: En hızlı yanıt veren sunucuyu tercih eder
  • UrlHash: URL’ye göre belirli sunucuya yönlendirme (sticky session alternatifi)
  • RequestHash: İstek özelliklerine göre hash tabanlı dağıtım

Production ortamında çoğunlukla LeastRequests veya WeightedRoundRobin kullanıyorum. API tabanlı uygulamalarda LeastRequests daha iyi sonuç veriyor çünkü bazı endpoint’ler çok daha uzun süren işlemler yapıyor olabilir.

# Yük dengeleme algoritmasını değiştir
Set-WebConfigurationProperty `
    -PSPath "IIS:" `
    -Filter "system.webServer/proxy/loadBalancing" `
    -Name "algorithm" `
    -Value "LeastRequests"

# Sunucu ağırlıklarını ayarla (WeightedRoundRobin için)
# WEB01 daha güçlü bir sunucu, daha fazla trafik alsın
$farm = "MyWebFarm"
Set-WebConfigurationProperty `
    -PSPath "IIS:" `
    -Filter "system.webServer/webFarms/webFarm[@name='$farm']/server[@address='WEB01.domain.local']/applicationRequestRouting" `
    -Name "weight" `
    -Value 100

Set-WebConfigurationProperty `
    -PSPath "IIS:" `
    -Filter "system.webServer/webFarms/webFarm[@name='$farm']/server[@address='WEB02.domain.local']/applicationRequestRouting" `
    -Name "weight" `
    -Value 50

Health Check Yapılandırması

Sağlık kontrolü doğru yapılandırılmadığında, farm bir sunucu çöktüğünde bunu geç fark edebilir ya da hiç fark etmeyebilir. Ben her uygulamamda özel bir health check endpoint’i oluştururum.

Backend web sunucularında basit bir health check sayfası:

<%@ Page Language="C#" %>
<%
    // Veritabanı bağlantısını kontrol et
    try 
    {
        // Basit bir DB ping veya uygulama durumu kontrolü
        Response.StatusCode = 200;
        Response.Write("OK");
    }
    catch
    {
        Response.StatusCode = 503;
        Response.Write("SERVICE_UNAVAILABLE");
    }
%>

Health check’i PowerShell ile yapılandıralım:

# Health check yapılandırması
$farmName = "MyWebFarm"
$healthCheckPath = "system.webServer/webFarms/webFarm[@name='$farmName']/applicationRequestRouting/healthCheck"

Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter $healthCheckPath `
    -Name "url" `
    -Value "http://localhost/health.aspx"

Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter $healthCheckPath `
    -Name "interval" `
    -Value "00:00:05"

Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter $healthCheckPath `
    -Name "timeout" `
    -Value "00:00:02"

Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter $healthCheckPath `
    -Name "responseMatch" `
    -Value "OK"

# Başarısız deneme sayısı - bu kadar başarısız olduktan sonra sunucuyu devre dışı bırak
Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter $healthCheckPath `
    -Name "responseTimeOut" `
    -Value "00:00:10"

Write-Host "Health check yapılandırması tamamlandı"

Interval değerini çok düşük tutmayın. 5 saniye genellikle yeterli. Çok agresif health check, backend sunucularda gereksiz yük oluşturur ve bu da özellikle yoğun saatlerde sorun çıkarabilir.

Session Yönetimi ve Sticky Sessions

Bu konu web farm kurulumunun en kritik parçası. Eğer uygulamanız InProc session kullanıyorsa, yani session verisi sunucunun bellekte tutuluyorsa, aynı kullanıcının isteklerinin hep aynı sunucuya gitmesi gerekiyor. Buna sticky session veya session affinity deniyor.

ARR bu konuda iki yöntem sunuyor:

  • Cookie tabanlı affinity: ARR özel bir cookie ekler, sonraki isteklerde bu cookie’ye bakarak aynı sunucuya yönlendirir
  • URL tabanlı affinity: Session ID URL’ye eklenir

Cookie tabanlı olanı tercih edin. URL tabanlı hem güvenlik hem de SEO açısından sorunlu.

# Affinity (sticky session) yapılandırması
$farmName = "MyWebFarm"
$affinityPath = "system.webServer/webFarms/webFarm[@name='$farmName']/applicationRequestRouting"

# Client affinity'yi etkinleştir
Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter $affinityPath `
    -Name "clientCacheSize" `
    -Value 10

# Affinity cookie adını özelleştir (ARR_AFFINITY varsayılan)
# applicationHost.config içinde webFarm elementine ekle
$xml = [xml](Get-Content "C:WindowsSystem32inetsrvconfigapplicationHost.config")
$webFarm = $xml.configuration.'system.webServer'.webFarms.webFarm | 
           Where-Object { $_.name -eq $farmName }

if ($webFarm) {
    $arr = $webFarm.applicationRequestRouting
    if ($arr) {
        $arr.SetAttribute("affinity.useCookie", "true")
        $arr.SetAttribute("affinity.cookieName", "ARR_AFFINITY")
    }
    $xml.Save("C:WindowsSystem32inetsrvconfigapplicationHost.config")
    Write-Host "Affinity yapılandırması kaydedildi"
}

Uzun vadeli düşündüğünüzde, sticky session’dan kurtulmak en sağlıklısı. Bunun için session’ı SQL Server veya Redis’e taşıyın. ASP.NET uygulamalarında SQL session state için:

<!-- Web.config içinde session state yapılandırması -->
<system.web>
    <sessionState mode="SQLServer" 
                  sqlConnectionString="Data Source=SQLCLUSTER;Initial Catalog=ASPState;Integrated Security=True"
                  cookieless="false" 
                  timeout="20" 
                  allowCustomSqlDatabase="true" />
</system.web>

Bu yapılandırmayla artık hangi sunucuya giderse gitsin, session verisi SQL Server’dan okunuyor. Farm’a yeni node eklemek, bakım yapmak çok daha kolay hale geliyor.

Shared Configuration

Birden fazla IIS sunucusunu aynı anda yönetmek için Shared Configuration kullanın. Bu özellik, tüm sunucuların aynı applicationHost.config dosyasını paylaşmasını sağlar.

# Shared configuration için UNC path hazırla
# Önce bir network share oluştur
$sharePath = "\FILESERVERIISConfig"
$userName = "DOMAINiis_service"
$password = ConvertTo-SecureString "StrongPassword123!" -AsPlainText -Force

# Shared configuration'ı etkinleştir (her web sunucusunda çalıştır)
$inetMgr = New-Object -ComObject Microsoft.ApplicationHost.WritableAdminManager
Write-Host "IIS Manager üzerinden Server > Shared Configuration bölümünü kullanın"
Write-Host "Physical path: $sharePath"
Write-Host "Username: $userName"

# Alternatif: appcmd ile
$appcmd = "$env:windirsystem32inetsrvappcmd.exe"
& $appcmd set config -section:configPaths `
    /+"[path='/'].configPath:$sharePath" 2>&1

Shared configuration kullanırken dikkat etmeniz gereken kritik bir nokta var: Uygulama pool kimliklerinde ve SSL sertifikalarında sorun çıkabilir. SSL sertifikaları her sunucuya ayrı ayrı import edilmeli, shared config bu konuda yardımcı olmaz.

URL Rewrite Kuralları

ARR’ın trafiği farm’a yönlendirebilmesi için URL Rewrite kuralına ihtiyaç var. Farm oluştururken wizard bunu otomatik yapıyor, ama manuel olarak da ekleyebilirsiniz:

<!-- web.config veya applicationHost.config içine eklenecek rewrite kuralı -->
<system.webServer>
    <rewrite>
        <rules>
            <rule name="ARR_MyWebFarm_loadbalance" patternSyntax="Wildcard">
                <match url="*" />
                <conditions>
                    <add input="{HTTP_HOST}" pattern="www.mysite.com" />
                </conditions>
                <action type="Rewrite" url="http://MyWebFarm/{R:0}" />
            </rule>
        </rules>
    </rewrite>
</system.webServer>

Birden fazla site için farm kullanıyorsanız, her site için ayrı kural yazın ve condition’ları HTTP_HOST üzerinden ayırt edin. Bu sayede tek bir ARR sunucusu birden fazla web farm’ı yönetebilir.

Monitoring ve Logging

Farm’ın sağlığını izlemek için birkaç önemli nokta var. IIS Manager üzerinden Server Farm seçildiğinde Monitoring and Management bölümünden her sunucunun anlık durumunu görebilirsiniz.

PowerShell ile periyodik monitoring scripti:

# Web Farm sunucu durumlarını kontrol eden script
# Task Scheduler ile her 1 dakikada bir çalıştırın

function Check-WebFarmHealth {
    param (
        [string]$FarmName = "MyWebFarm",
        [string]$LogPath = "C:LogsWebFarm_Health.log"
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$timestamp] Farm: $FarmName - "
    
    try {
        $farmConfig = Get-WebConfiguration `
            -PSPath "IIS:" `
            -Filter "system.webServer/webFarms/webFarm[@name='$FarmName']/server"
        
        foreach ($server in $farmConfig) {
            $serverAddress = $server.address
            $serverState = $server.enabled
            
            # HTTP health check
            try {
                $response = Invoke-WebRequest `
                    -Uri "http://$serverAddress/health.aspx" `
                    -TimeoutSec 5 `
                    -UseBasicParsing
                
                $status = if ($response.StatusCode -eq 200) { "HEALTHY" } else { "DEGRADED" }
            }
            catch {
                $status = "UNHEALTHY"
            }
            
            $logEntry += "$serverAddress=$status; "
            
            # Kritik durumda email veya alert gönder
            if ($status -eq "UNHEALTHY") {
                Write-Warning "UYARI: $serverAddress sunucusu yanıt vermiyor!"
                # Send-MailMessage veya monitoring sisteminize alert gönderin
            }
        }
        
        Add-Content -Path $LogPath -Value $logEntry
    }
    catch {
        Add-Content -Path $LogPath -Value "[$timestamp] HATA: $($_.Exception.Message)"
    }
}

Check-WebFarmHealth -FarmName "MyWebFarm"

ARR’ın kendi logları C:inetpublogsarr altında tutuluyor. Bu logları düzenli olarak incelemenizi tavsiye ederim, özellikle backend sunuculara yapılan başarısız istek sayısını takip edin.

Gerçek Dünya Sorunları ve Çözümleri

Birkaç gerçek senaryoyu paylaşayım.

Senaryo 1: SSL Offloading ARR sunucusunda SSL terminate edip backend’e HTTP ile gönderdiğinizde, uygulamanız Request.IsSecureConnection false görür ve HTTPS’e yönlendirme döngüsüne girer. Çözüm: ARR, backend’e X-Forwarded-Proto: https header’ı ekler. Uygulamayı bu header’ı okuyacak şekilde yapılandırın.

Senaryo 2: WebSocket desteği ARR 3.0 öncesinde WebSocket desteği yoktu. Eğer SignalR veya WebSocket kullanan bir uygulamanız varsa, ARR’ı en güncel sürüme güncelleyin ve system.webServer/webSocket bölümünden WebSocket’i etkinleştirin.

Senaryo 3: Large file upload sorunları Varsayılan olarak ARR büyük dosya yüklemelerinde timeout yaşayabilir. requestTimeout değerini artırın:

# ARR proxy timeout ayarları
Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter "system.webServer/proxy" `
    -Name "timeout" `
    -Value "00:05:00"  # 5 dakika

# Maximum allowed content length (bytes cinsinden, burada 500MB)
Set-WebConfigurationProperty -PSPath "IIS:" `
    -Filter "system.webServer/security/requestFiltering" `
    -Name "maxAllowedContentLength" `
    -Value 524288000

Senaryo 4: Backend sunucu bakım modu Bir sunucuyu farm’dan çıkarmadan önce, üzerindeki aktif isteklerin tamamlanmasını bekleyin. Aniden disable etmek aktif kullanıcı oturumlarını keser.

# Sunucuyu "drain" moduna al - yeni istek almaz, mevcutları tamamlar
$farmName = "MyWebFarm"
$serverAddress = "WEB01.domain.local"

Set-WebConfigurationProperty `
    -PSPath "IIS:" `
    -Filter "system.webServer/webFarms/webFarm[@name='$farmName']/server[@address='$serverAddress']" `
    -Name "enabled" `
    -Value $false

Write-Host "$serverAddress bakım moduna alındı. Aktif bağlantılar tamamlanıyor..."
Start-Sleep -Seconds 30  # Mevcut isteklerin bitmesi için bekle
Write-Host "Sunucu üzerinde bakım yapılabilir"

Sonuç

IIS Web Farm kurulumu, doğru yapılandırıldığında son derece sağlam bir yük dengeleme altyapısı sunuyor. ARR’ın özellikle Microsoft ekosistemi içinde çalışan uygulamalar için iyi bir tercih olduğunu söyleyebilirim. Session yönetimini merkezi bir yere taşımak, health check endpoint’lerini uygulamaya özgü yazmak ve monitoring scriptlerini baştan kurmak uzun vadede büyük zaman kazandırıyor.

Özellikle vurgulamak istediğim iki nokta var: Birincisi, sticky session’dan mümkün olan en kısa sürede kurtulun. SQL Server veya Redis bazlı session, operasyonel açıdan çok daha esnek. İkincisi, farm yapılandırmasını mutlaka kod veya script olarak tutun. “IIS Manager’dan tıkla tıkla yaptım” şeklindeki yapılandırmalar, bir sunucu yeniden kurulduğunda saatlerce vakit çalabiliyor. Infrastructure as Code yaklaşımı burada da geçerli.

Bir yanıt yazın

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