BIND ile Yük Dengeleme: Round Robin DNS Nasıl Yapılandırılır

Büyük bir web uygulaması yönetiyorsun, trafiğin tek bir sunucuya yığılıyor ve geceleri uyku uyuyamıyorsun. İşte tam bu noktada DNS tabanlı yük dengeleme devreye giriyor. Round Robin DNS, belki de sistemcilerin elindeki en eski ve en basit yük dengeleme araçlarından biri, ama doğru kullanıldığında hâlâ son derece etkili. Bu yazıda BIND üzerinde Round Robin DNS’i kurmayı, ince ayarlarını yapmayı ve production ortamında karşılaşabileceğin gerçek senaryoları ele alacağız.

Round Robin DNS Nedir ve Neden Kullanırız?

Round Robin DNS’in çalışma mantığı son derece basit: Aynı hostname için birden fazla A kaydı tanımlarsın, DNS sunucusu da her sorguya farklı bir sırayla bu IP adreslerini döndürür. İstemci genellikle listenin başındaki adresi kullanır, bir sonraki istemci farklı bir IP alır. Böylece trafik sunucular arasında dağıtılmış olur.

Bu yöntemin avantajları:

  • Altyapı maliyeti sıfır: Ekstra load balancer donanımı gerekmez
  • Kurulumu dakikalar alır: BIND zone dosyasına birkaç satır eklemek yeterli
  • Donanımdan bağımsız: Herhangi bir web sunucusu, uygulama sunucusu veya servis için kullanılabilir
  • DNS seviyesinde çalışır: Uygulama katmanında hiçbir değişiklik gerekmez

Tabii ki dezavantajları da var. Session persistence yok, yani aynı kullanıcı her istekte farklı bir sunucuya düşebilir. Bir sunucu çöktüğünde DNS hâlâ o IP’yi dağıtmaya devam edebilir. Health check mekanizması built-in gelmiyor. Bunları bilerek kullanmak gerekiyor.

BIND Kurulumu ve Temel Yapılandırma

Önce BIND’ın kurulu olduğundan emin olalım. Debian/Ubuntu için:

apt update
apt install bind9 bind9utils bind9-doc dnsutils -y
systemctl enable named
systemctl start named

RHEL/CentOS/Rocky Linux için:

dnf install bind bind-utils -y
systemctl enable named
systemctl start named

BIND’ın düzgün çalıştığını doğrulayalım:

systemctl status named
named -v
# BIND 9.16.x gibi bir çıktı görmelisin

Temel konfigürasyon dosyası /etc/bind/named.conf (Debian) veya /etc/named.conf (RHEL). Yapıyı anlamak için önce bu dosyaya bakalım:

cat /etc/bind/named.conf

Tipik bir yapı şu şekilde görünür:

# /etc/bind/named.conf içeriği
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";

Round Robin için Zone Dosyası Hazırlama

Diyelim ki ornek.com adlı alan adı için üç web sunucumuz var:

  • Web1: 192.168.1.10
  • Web2: 192.168.1.11
  • Web3: 192.168.1.12

Önce named.conf.local dosyasına zone tanımını ekleyelim:

zone "ornek.com" {
    type master;
    file "/etc/bind/zones/db.ornek.com";
    allow-query { any; };
};

Şimdi zone dosyasını oluşturalım:

mkdir -p /etc/bind/zones
nano /etc/bind/zones/db.ornek.com

İşte temel Round Robin zone dosyası:

$TTL 300
@   IN  SOA ns1.ornek.com. admin.ornek.com. (
            2024120101  ; Serial
            3600        ; Refresh
            1800        ; Retry
            604800      ; Expire
            300 )       ; Negative Cache TTL

; Name Server kayitlari
@   IN  NS  ns1.ornek.com.
@   IN  NS  ns2.ornek.com.

; Name Server A kayitlari
ns1 IN  A   192.168.1.5
ns2 IN  A   192.168.1.6

; Round Robin A kayitlari - web sunuculari
www IN  A   192.168.1.10
www IN  A   192.168.1.11
www IN  A   192.168.1.12

; Diger kayitlar
@   IN  A   192.168.1.10
mail IN  A  192.168.1.20
@   IN  MX 10 mail.ornek.com.

Buradaki kritik nokta: www için üç ayrı A kaydı tanımladık. BIND her DNS sorgusunda bu üç IP’yi farklı sırayla döndürecek.

TTL değerini 300 saniye (5 dakika) olarak ayarlamak önemli. Eğer TTL çok yüksekse (örneğin 86400 saniye/1 gün), istemciler aynı IP’yi cache’de tutacak ve round robin etkisi ortadan kalkacak.

Zone dosyasının syntax hatası içerip içermediğini kontrol edelim:

named-checkzone ornek.com /etc/bind/zones/db.ornek.com
# "OK" ciktisi almalisin

BIND konfigürasyonunu genel olarak doğrulayalım:

named-checkconf
# Hata yoksa sessizce cıkar

BIND’ı yeniden yükleyelim:

rndc reload
# veya
systemctl reload named

Round Robin’i Test Etme

Zone dosyasını deploy ettikten sonra test etmek kritik. dig komutu en iyi arkadaşın:

# Birden fazla sorgu gönderip sıralamayı gözlemle
for i in {1..6}; do
    dig @localhost www.ornek.com A +short
    echo "---"
done

Bu komutun çıktısında IP adreslerinin sırasının değiştiğini görmelisin:

192.168.1.10
192.168.1.11
192.168.1.12
---
192.168.1.11
192.168.1.12
192.168.1.10
---
192.168.1.12
192.168.1.10
192.168.1.11

Daha detaylı bilgi için:

dig @localhost www.ornek.com A
# ANSWER SECTION'da üç A kaydını göreceksin

nslookup ile de test edebilirsin ama dig çok daha fazla bilgi veriyor. Production’da sorun yaşandığında dig hayat kurtarır.

BIND Options ile Round Robin Davranışını Özelleştirme

BIND’ın named.conf.options dosyasında Round Robin davranışını etkileyen birkaç önemli direktif var:

options {
    directory "/var/cache/bind";
    
    # Round Robin siralama modu
    rrset-order {
        class IN type A name "www.ornek.com" order cyclic;
    };
    
    # Diger genel ayarlar
    dnssec-validation auto;
    listen-on { any; };
    allow-recursion { localhost; 192.168.1.0/24; };
};

rrset-order direktifinin kabul ettiği değerler:

  • cyclic: Klasik Round Robin, sıralı rotasyon (varsayılan)
  • random: Her sorguda tamamen rastgele sıralama
  • fixed: Her zaman zone dosyasındaki sıra korunur (yük dengeleme için kullanışsız)

Tüm A kayıtları için random mod istiyorsan:

options {
    rrset-order {
        class IN type A order random;
    };
};

Random mod bazı durumlarda cyclic’e göre daha iyi dağılım sağlayabilir, özellikle çok sayıda istemci aynı anda sorgu yapıyorsa.

Gerçek Dünya Senaryosu: E-Ticaret Sitesi İçin DNS Yük Dengeleme

Bir e-ticaret sitesi düşün. Black Friday yaklaşıyor, beklenen trafik normalin 10 katı. Elinde üç uygulama sunucusu var, bir de CDN’den dönen statik içerik var. Şöyle bir yapı kurabilirsin:

$TTL 60
@   IN  SOA ns1.magaza.com. hostmaster.magaza.com. (
            2024120102
            3600
            900
            604800
            60 )

@       IN  NS  ns1.magaza.com.
@       IN  NS  ns2.magaza.com.

ns1     IN  A   10.0.0.1
ns2     IN  A   10.0.0.2

; Ana site - round robin ile 3 sunucu
www     IN  A   10.0.1.10
www     IN  A   10.0.1.11
www     IN  A   10.0.1.12

; API sunuculari ayri round robin grubu
api     IN  A   10.0.2.10
api     IN  A   10.0.2.11

; Statik icerik - CDN node'lari
static  IN  A   10.0.3.10
static  IN  A   10.0.3.11
static  IN  A   10.0.3.12
static  IN  A   10.0.3.13

; Admin paneli - tek sunucu (round robin yok)
admin   IN  A   10.0.1.5

; Magaza ana sayfasi
@       IN  A   10.0.1.10
@       IN  A   10.0.1.11
@       IN  A   10.0.1.12

Bu yapıda TTL’i 60 saniye olarak ayarladım. Neden bu kadar düşük? Çünkü Black Friday gecesi bir sunucu devre dışı kalırsa, o IP’yi zone’dan kaldırdıktan sonra en fazla 60 saniye içinde tüm istemciler yeni IP dağılımına geçmiş olacak.

Ağırlıklı Round Robin: Sunucu Kapasitelerine Göre Dengeleme

Standart Round Robin her sunucuya eşit trafik gönderir. Ama ya sunucularından biri diğerlerinden iki kat güçlüyse? BIND’da built-in ağırlık desteği yok, ama bunu bir numarayla simüle edebilirsin. Güçlü sunucuya daha fazla A kaydı eklersin:

; Sunucu kapasiteleri: web1=4 core, web2=4 core, web3=8 core
; web3 iki kat daha fazla trafik alsın

www IN  A   192.168.1.10  ; web1 - 4 core
www IN  A   192.168.1.11  ; web2 - 4 core
www IN  A   192.168.1.12  ; web3 - 8 core (ilk kayit)
www IN  A   192.168.1.12  ; web3 - 8 core (ikinci kayit, agirlik 2x)

Böylece 4 kayıt arasında web3 iki kez geçiyor ve teorik olarak trafiğin yarısını alıyor. Kaba bir yöntem ama işe yarıyor.

Monitoring ve Otomatik Failover

Round Robin DNS’in en büyük sorunu health check mekanizmasının olmaması. Bir sunucu çökerse BIND bunu bilmez ve o IP’yi dağıtmaya devam eder. Bunu çözmek için basit bir monitoring scripti yazabilirsin:

#!/bin/bash
# /usr/local/bin/dns-health-check.sh

ZONE_FILE="/etc/bind/zones/db.ornek.com"
ZONE_FILE_BACKUP="/etc/bind/zones/db.ornek.com.backup"
LOG_FILE="/var/log/dns-health-check.log"
SMTP_SERVER="mail.ornek.com"
ALERT_EMAIL="[email protected]"

# Kontrol edilecek sunucular ve portlar
declare -A SERVERS=(
    ["192.168.1.10"]="80"
    ["192.168.1.11"]="80"
    ["192.168.1.12"]="80"
)

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

check_server() {
    local ip=$1
    local port=$2
    
    # nc ile port kontrolu, 3 saniye timeout
    if nc -z -w3 "$ip" "$port" 2>/dev/null; then
        return 0
    else
        return 1
    fi
}

update_zone() {
    local failed_ip=$1
    
    # Zone dosyasini yedekle
    cp "$ZONE_FILE" "$ZONE_FILE_BACKUP"
    
    # Arızalı IP'yi zone dosyasindan kaldir
    sed -i "/wwws*INs*As*$failed_ip/d" "$ZONE_FILE"
    
    # Serial'i guncelle
    local current_serial=$(grep "Serial" "$ZONE_FILE" | awk '{print $1}')
    local new_serial=$(date +%Y%m%d%H)
    sed -i "s/$current_serial/$new_serial/" "$ZONE_FILE"
    
    # Zone'u dogrula ve yeniden yukle
    if named-checkzone ornek.com "$ZONE_FILE" > /dev/null 2>&1; then
        rndc reload ornek.com
        log "KRITIK: $failed_ip zone dosyasindan kaldirildi ve zone yeniden yuklendi"
        
        # Email bildirimi gonder
        echo "ALARM: $failed_ip adresli sunucu erisim disinda. Zone'dan kaldirildi." | 
            mail -s "DNS Health Check ALARM" "$ALERT_EMAIL"
    else
        # Zone hatasi varsa backup'tan geri yukle
        cp "$ZONE_FILE_BACKUP" "$ZONE_FILE"
        log "HATA: Zone dosyasi guncelleme basarisiz, yedekten geri yüklendi"
    fi
}

# Ana kontrol dongusu
for ip in "${!SERVERS[@]}"; do
    port=${SERVERS[$ip]}
    
    if check_server "$ip" "$port"; then
        log "OK: $ip:$port erisebilir durumda"
    else
        log "HATA: $ip:$port erisim saglanamadi"
        update_zone "$ip"
    fi
done

Bu scripti crontab’a ekle:

# Her 2 dakikada bir calistir
*/2 * * * * /usr/local/bin/dns-health-check.sh

# Script'e calisma izni ver
chmod +x /usr/local/bin/dns-health-check.sh

Bu script production’da kullanmadan önce iyice test et ve edge case’leri düşün. Örneğin, bütün sunucular aynı anda çökerse zone boş kalmamalı.

DNS View ile Lokasyon Tabanlı Round Robin

BIND’ın view özelliğini kullanarak iç ağ ve dış ağ istemcilerine farklı IP listesi döndürebilirsin. Bu hem güvenlik hem de performans açısından mantıklı:

# /etc/bind/named.conf.local

# Ic ag gorunumu
view "internal" {
    match-clients { 
        192.168.0.0/16; 
        10.0.0.0/8; 
    };
    
    zone "ornek.com" {
        type master;
        file "/etc/bind/zones/db.ornek.com.internal";
    };
};

# Dis ag gorunumu
view "external" {
    match-clients { any; };
    
    zone "ornek.com" {
        type master;
        file "/etc/bind/zones/db.ornek.com.external";
    };
};

İç zone dosyasında özel IP’leri, dış zone dosyasında ise public IP’leri kullanırsın. Böylece iç ağdaki kullanıcılar doğrudan private IP’lere bağlanırken, dış kullanıcılar DMZ veya public IP’lere yönlendiriliyor.

Performans Testi ve Doğrulama

Round Robin’in gerçekten çalışıp çalışmadığını production’da test etmek için:

# 100 sorgu gönder ve IP dagilimini gözlemle
for i in {1..100}; do
    dig @localhost www.ornek.com A +short | head -1
done | sort | uniq -c | sort -rn

Bu komutun çıktısı yaklaşık eşit dağılım göstermelidir:

 34 192.168.1.10
 33 192.168.1.11
 33 192.168.1.12

Eğer dağılım çok dengesizse, istemci tarafındaki DNS cache etkisi olabilir. Test ederken +noedns ve +nocache flaglarını kullanabilirsin:

dig @localhost www.ornek.com A +short +noedns

Response time’ı test etmek için:

# DNS sorgu süresini ölç
dig @localhost www.ornek.com A +stats | grep "Query time"

# Birden fazla sorgu için ortalama süre
for i in {1..50}; do
    dig @localhost www.ornek.com A +stats 2>/dev/null | grep "Query time"
done | awk '{sum+=$4; count++} END {print "Ortalama:", sum/count, "ms"}'

Sık Yapılan Hatalar ve Çözümleri

Yıllar içinde gördüğüm en yaygın hatalar şunlar:

Yüksek TTL kullanmak: TTL’i 86400 ayarlayıp “neden round robin çalışmıyor” diye sormak çok yaygın. Yük dengeleme için TTL’i maksimum 300 saniye, aktif değişiklik dönemlerinde 60 saniye yap.

Serial numarasını güncellemememek: Zone dosyasını değiştirip serial’i artırmamak. BIND secondary’ler ve bazı cache sunucuları serial değişmemişse zone’u güncellemiyor.

# Serial guncelleme best practice - YYYYMMDDXX formati
# Ornek: 20241201 + 01 = 2024120101
# Ayni gun ikinci degisiklik: 2024120102

named-checkzone yapmadan reload etmek: Syntax hatası olan bir zone yüklenmeye çalışıldığında eski zone silinebilir veya servis restart gerektirebilir. Her değişiklikten önce mutlaka kontrol et.

IPv6 unutmak: Sadece A kaydı ekleyip AAAA kaydını unutmak. IPv6 kullanan istemciler hep aynı sunucuya düşer.

# IPv6 round robin
www IN  AAAA  2001:db8::10
www IN  AAAA  2001:db8::11
www IN  AAAA  2001:db8::12

BIND Logging ile Round Robin Debuggeme

Production sorunlarını çözmek için BIND logging’i aktif etmek hayat kurtarır:

# named.conf.options içine ekle
logging {
    channel default_log {
        file "/var/log/named/named.log" versions 3 size 20m;
        print-time yes;
        print-severity yes;
        print-category yes;
        severity dynamic;
    };
    
    channel query_log {
        file "/var/log/named/query.log" versions 3 size 50m;
        print-time yes;
        severity info;
    };
    
    category default { default_log; };
    category queries { query_log; };
    category resolver { default_log; };
};

Log dizinini oluştur ve izinleri ayarla:

mkdir -p /var/log/named
chown bind:bind /var/log/named
chmod 755 /var/log/named

Query log’u izlemek için:

tail -f /var/log/named/query.log | grep "www.ornek.com"

Bu sayede hangi istemcinin hangi IP’yi aldığını gerçek zamanlı görebilirsin.

Sonuç

Round Robin DNS, ne karmaşık bir load balancer kurabilecek bütçen ne de buna zaman harcayabileceğin durumlarda son derece işe yarayan, battle-tested bir çözüm. BIND ile kurulumu gerçekten on beş dakikalık bir iş ve uygun TTL ayarlarıyla makul düzeyde yük dağıtımı sağlıyor.

Ama şunu açıkça söylemek gerekiyor: Round Robin DNS, HAProxy, Nginx upstream veya bulut sağlayıcıların load balancer servislerinin yerini tutamaz. Session persistence gerekmiyorsa, health check’i kendin scriptlerle yönetebiliyorsan ve uygulamanın stateless çalıştığından eminsen, mükemmel bir tercih.

Production’da kullanmadan önce şu kontrol listesini geçtiğinden emin ol:

  • TTL değerlerin uygun (yük dengeleme için max 300 saniye)
  • Zone dosyaları named-checkzone ile doğrulanmış
  • Health check scripti çalışıyor ve alerting yapılandırılmış
  • IPv4 ve IPv6 kayıtlarının her ikisi de var
  • Logging aktif ve log rotation yapılandırılmış
  • Fallback planın var (bir sunucu düşerse ne olacak)

DNS tabanlı yük dengeleme, modern yüksek trafik senaryolarında sadece ilk katman olarak kullanılmalı. Üstüne bir application-level load balancer koy, altına sağlam monitoring ekle, ve gerçekten ölçeklenebilir bir mimarin olur. Round Robin DNS o mimarinin ucuz ama etkili bir parçası olmaya devam ediyor.

Yorum yapın