Unbound DNS Sunucusu Performans Testi ve Benchmark Rehberi

DNS sunucunuzun ne kadar hızlı çalıştığını biliyor musunuz? Çoğu sysadmin Unbound’u kurar, birkaç temel ayarı yapar ve “çalışıyor, tamam” der geçer. Oysa production ortamında yüz binlerce sorgu işleyen bir DNS sunucusunda performans farkı, kullanıcı deneyimini doğrudan etkiler. Bu yazıda Unbound DNS sunucusunun performansını nasıl test edeceğinizi, darboğazları nasıl bulacağınızı ve benchmark sonuçlarını nasıl yorumlayacağınızı ele alacağım.

Neden Benchmark Yapmalıyız?

Sistemi kurarken “yeterince hızlı” gibi muğlak bir hedefle çalışmak yerine somut rakamlar üzerinden konuşmak çok daha sağlıklı. Benchmark yapmanın birkaç kritik amacı var:

  • Baseline oluşturmak: Sistemin normal performansını bilmeden, bir sorun çıktığında neyin değiştiğini anlayamazsınız.
  • Kapasite planlaması: “Bu sunucu kaç sorgu/saniye kaldırır?” sorusuna gerçek veri ile cevap verebilmek.
  • Konfigürasyon değişikliklerinin etkisini ölçmek: Cache boyutunu artırdınız, thread sayısını değiştirdiniz. Bunların etkisi ne oldu?
  • Donanım yükseltmesi kararları: Daha fazla RAM veya CPU almak gerekiyor mu?

Deneyimlerimden şunu söyleyebilirim: Bir e-ticaret altyapısında yapılan DNS optimizasyonu, sayfa yükleme sürelerini ortalama 40-80ms düşürebiliyor. Bu rakamlar conversion rate açısından ciddi fark yaratıyor.

Test Ortamının Hazırlanması

Benchmark yapmadan önce test ortamını doğru kurmak şart. Production sunucusunda doğrudan test yapmak hem riskli hem de yanıltıcı sonuçlar verir; gerçek trafikle test trafiği birbirine karışır.

Gerekli Araçlar

Test için kullanacağımız temel araçlar:

  • dnsperf: ISC tarafından geliştirilen, DNS sunucu performans testi için en yaygın kullanılan araç
  • resperf: dnsperf’in kardeşi, özellikle ramp-up testleri için
  • queryperf: BIND ile gelen ama Unbound testlerinde de kullanılabilen araç
  • drill/dig: Temel gecikme ölçümleri için

Kurulum:

# Ubuntu/Debian
apt-get install dnsperf

# RHEL/CentOS/Rocky Linux
dnf install epel-release
dnf install dnsperf

# Kaynak koddan derleme (en güncel sürüm için)
git clone https://github.com/DNS-OARC/dnsperf.git
cd dnsperf
./configure
make && make install

Test Sorgu Dosyasının Oluşturulması

dnsperf, test sorgularını bir dosyadan okur. Gerçekçi bir test için gerçek dünya trafiğine benzer sorgular kullanmak gerekiyor.

# Temel bir sorgu dosyası oluşturma
cat > /tmp/queryfile.txt << 'EOF'
google.com A
facebook.com A
youtube.com A
github.com A
cloudflare.com A
amazon.com A
stackoverflow.com A
linkedin.com A
twitter.com AAAA
microsoft.com MX
apple.com A
netflix.com A
reddit.com A
wikipedia.org A
instagram.com A
EOF

Daha büyük ve gerçekçi bir sorgu seti için Alexa veya benzeri listelerden yararlanabilirsiniz:

# Örnek büyük sorgu dosyası oluşturma scripti
#!/bin/bash
DOMAINS=(
    "google.com" "youtube.com" "facebook.com" "twitter.com" "instagram.com"
    "linkedin.com" "github.com" "stackoverflow.com" "reddit.com" "wikipedia.org"
    "amazon.com" "netflix.com" "apple.com" "microsoft.com" "cloudflare.com"
)

TYPES=("A" "AAAA" "MX" "NS" "TXT")

for i in $(seq 1 1000); do
    domain=${DOMAINS[$RANDOM % ${#DOMAINS[@]}]}
    type=${TYPES[$RANDOM % ${#TYPES[@]}]}
    echo "$domain $type"
done > /tmp/large_queryfile.txt

echo "Sorgu dosyası oluşturuldu: $(wc -l /tmp/large_queryfile.txt) satır"

Temel Benchmark Testleri

İlk Baseline Testi

Herhangi bir optimizasyon yapmadan önce mevcut performansı ölçmek gerekiyor. Bu baseline olmadan iyileştirmelerin etkisini göremezsiniz.

# Temel dnsperf testi
# -s: hedef sunucu
# -d: sorgu dosyası
# -l: test süresi (saniye)
# -c: eşzamanlı bağlantı sayısı
# -Q: maksimum sorgu/saniye
dnsperf -s 127.0.0.1 
        -d /tmp/queryfile.txt 
        -l 30 
        -c 10 
        -Q 1000 
        -p 53

# Çıktı örneği:
# DNS Performance Testing Tool
# Queries sent:         30000
# Queries completed:    29987 (99.96%)
# Queries lost:         13 (0.04%)
# Run time (s):         30.000
# Queries per second:   999.57
# Average latency (s):  0.002341
# Latency std dev (s):  0.001205

Cache Hit Oranını Test Etme

Unbound’un en büyük güçlerinden biri cache mekanizması. Cache hit oranı performansın en kritik göstergelerinden biri.

# Önce cache'i temizle
unbound-control flush_zone "."
unbound-control reload

# İlk geçiş - cold cache
echo "=== COLD CACHE TESTİ ==="
dnsperf -s 127.0.0.1 
        -d /tmp/queryfile.txt 
        -l 30 
        -c 20 
        -p 53 2>&1 | grep -E "(Queries per second|Average latency|completed)"

# Kısa bekleme - cache dolsun
sleep 5

# İkinci geçiş - warm cache
echo "=== WARM CACHE TESTİ ==="
dnsperf -s 127.0.0.1 
        -d /tmp/queryfile.txt 
        -l 30 
        -c 20 
        -p 53 2>&1 | grep -E "(Queries per second|Average latency|completed)"

Kendi test ortamımda tipik olarak cold cache’de 2-5ms gecikme, warm cache’de 0.1-0.5ms gecikme görüyorum. Bu fark Unbound’un neden önde geldiğini net olarak ortaya koyuyor.

Unbound Konfigürasyon Optimizasyonları ve Etkilerini Ölçme

Thread ve Bellek Ayarları

# /etc/unbound/unbound.conf - performans odaklı ayarlar
server:
    # CPU çekirdek sayısına göre ayarlayın
    num-threads: 4
    
    # Her thread için ayrı cache (false daha az bellek kullanır ama lock contention yaratır)
    so-reuseport: yes
    
    # Cache boyutları - mevcut RAM'in %25'ini geçmeyin
    msg-cache-size: 256m
    rrset-cache-size: 512m
    
    # Negative cache
    neg-cache-size: 4m
    
    # Outgoing bağlantı sayısı
    outgoing-range: 4096
    num-queries-per-thread: 4096
    
    # Prefetch - TTL dolmadan önce cache yenile
    prefetch: yes
    prefetch-key: yes
    
    # Minimal yanıtlar (daha az data transfer)
    minimal-responses: yes
    
    # EDNS buffer size
    edns-buffer-size: 1232

Bu ayarları uyguladıktan sonra benchmark tekrar çalıştırın:

#!/bin/bash
# Konfigürasyon karşılaştırma scripti

run_test() {
    local label=$1
    local duration=30
    
    echo "=== $label ==="
    result=$(dnsperf -s 127.0.0.1 
                     -d /tmp/large_queryfile.txt 
                     -l $duration 
                     -c 50 
                     -p 53 2>&1)
    
    qps=$(echo "$result" | grep "Queries per second" | awk '{print $NF}')
    latency=$(echo "$result" | grep "Average latency" | awk '{print $NF}')
    loss=$(echo "$result" | grep "Queries lost" | awk '{print $NF}')
    
    echo "QPS: $qps"
    echo "Ortalama Gecikme: $latency saniye"
    echo "Kayıp: $loss"
    echo "---"
}

systemctl restart unbound
sleep 3
run_test "Varsayılan Ayarlar"

# Ayarları uygula...
# systemctl restart unbound
# sleep 3
# run_test "Optimize Edilmiş Ayarlar"

So-reuseport Etkisi

Linux kernel 3.9 ve sonrasında SO_REUSEPORT socket opsiyonu, çok thread’li DNS sunucularında ciddi performans artışı sağlıyor.

# Unbound istatistiklerini kontrol et
unbound-control stats_noreset | grep -E "(total.|num.)" | head -20

# Önemli metrikler:
# total.num.queries: toplam sorgu sayısı
# total.num.cachehits: cache'den karşılanan sorgular
# total.num.cachemiss: upstream'e giden sorgular
# total.num.prefetch: prefetch ile yenilenen kayıtlar

# Cache hit oranını hesapla
hits=$(unbound-control stats_noreset | grep "total.num.cachehits" | awk -F= '{print $2}')
total=$(unbound-control stats_noreset | grep "total.num.queries" | awk -F= '{print $2}')

if [ -n "$hits" ] && [ -n "$total" ] && [ "$total" -gt 0 ]; then
    ratio=$(echo "scale=2; $hits * 100 / $total" | bc)
    echo "Cache hit oranı: %$ratio"
fi

Stres Testi ve Kapasite Planlaması

Normal koşullar altında iyi çalışan bir sunucu, trafik aniden yükseldiğinde nasıl davranır? Resperf bu soruyu cevaplamak için biçilmiş kaftan.

# resperf ile kademeli yük testi
# -s: hedef
# -d: sorgu dosyası
# -r: test süresi (saniye)
# -m: maksimum QPS (ramp-up hedefi)
resperf -s 127.0.0.1 
        -d /tmp/large_queryfile.txt 
        -r 60 
        -m 50000 
        -p 53 > /tmp/resperf_output.txt 2>&1

# Sonuçları görüntüle
tail -20 /tmp/resperf_output.txt

Resperf çıktısı size sistemin hangi QPS değerinde doyuma ulaştığını, yani “elbow point”i gösterir. Bu nokta teorik kapasitenizdir ve güvenli operasyon için bu değerin %70-80’inde çalışmanızı öneririm.

Uzun Süreli Dayanıklılık Testi

#!/bin/bash
# 10 dakikalık dayanıklılık testi
echo "Dayanıklılık testi başlıyor: $(date)"

dnsperf -s 127.0.0.1 
        -d /tmp/large_queryfile.txt 
        -l 600 
        -c 100 
        -Q 5000 
        -p 53 
        -v > /tmp/endurance_test.log 2>&1 &

DNSPERF_PID=$!

# Test sırasında sistem kaynaklarını izle
while kill -0 $DNSPERF_PID 2>/dev/null; do
    timestamp=$(date '+%H:%M:%S')
    cpu=$(top -bn1 | grep "unbound" | awk '{print $9}' | head -1)
    mem=$(ps aux | grep unbound | grep -v grep | awk '{print $6}' | head -1)
    echo "$timestamp - CPU: ${cpu}%, MEM: ${mem}KB" >> /tmp/resource_usage.log
    sleep 10
done

echo "Test tamamlandı: $(date)"
echo "Kaynak kullanımı özeti:"
tail -5 /tmp/resource_usage.log

Gecikme Dağılımı Analizi

Ortalama gecikme bazen yanıltıcı olabilir. 1ms ortalama gecikmeniz olabilir ama P99 (yüzde doksan dokuzuncu yüzdelik) gecikmeniz 500ms ise bu ciddi bir sorun.

# dnsperf ile percentile analizi
dnsperf -s 127.0.0.1 
        -d /tmp/large_queryfile.txt 
        -l 60 
        -c 50 
        -p 53 
        -T 200 2>&1 | tee /tmp/latency_test.txt

# Çıktıdan latency percentile'larını okuyun
grep -E "(latency|percentile)" /tmp/latency_test.txt

# Manuel percentile hesaplama için
# dnsperf -T flag'i 200 hesaplama aralığı kullanır
# Sonuçlar şöyle görünür:
# Latency distribution:
#   < 0.001000 s: 45.23%
#   < 0.002000 s: 78.91%
#   < 0.005000 s: 95.43%
#   < 0.010000 s: 99.12%
#   < 0.020000 s: 99.87%

P95 ve P99 değerlerinizi takip etmek, sporadik yavaşlık sorunlarını tespit etmek için kritik öneme sahip.

Unbound İstatistikleri ile Sürekli Monitoring

Benchmark tek seferlik değil, sürekli yapılması gereken bir aktivite. Unbound’un built-in istatistikleri bu konuda çok işe yarıyor.

#!/bin/bash
# Unbound performans monitoring scripti
# Bunu cron'a ekleyebilir veya bir monitoring sistemine entegre edebilirsiniz

collect_stats() {
    stats=$(unbound-control stats_noreset)
    
    total_queries=$(echo "$stats" | grep "^total.num.queries=" | cut -d= -f2)
    cache_hits=$(echo "$stats" | grep "^total.num.cachehits=" | cut -d= -f2)
    cache_miss=$(echo "$stats" | grep "^total.num.cachemiss=" | cut -d= -f2)
    avg_latency=$(echo "$stats" | grep "^total.recursion.time.avg=" | cut -d= -f2)
    median_latency=$(echo "$stats" | grep "^total.recursion.time.median=" | cut -d= -f2)
    
    # Cache hit oranı
    if [ "$total_queries" -gt 0 ] 2>/dev/null; then
        hit_ratio=$(echo "scale=4; $cache_hits / $total_queries * 100" | bc 2>/dev/null)
    fi
    
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "$timestamp | Toplam: $total_queries | Hit: $cache_hits | Miss: $cache_miss | Hit Oranı: %${hit_ratio} | Ort. Gecikme: ${avg_latency}s | Medyan: ${median_latency}s"
}

# Her 60 saniyede bir istatistik topla
while true; do
    collect_stats >> /var/log/unbound_perf.log
    sleep 60
done

Bu scripti bir systemd service olarak çalıştırabilir, çıktıyı Prometheus + Grafana gibi monitoring sistemlerinize besleyebilirsiniz.

Yaygın Performans Sorunları ve Çözümleri

Benchmark sonuçlarınız beklentilerin altında kalıyorsa kontrol etmeniz gereken noktalar:

Yüksek cache miss oranı (%20’nin üzeri): Sorgu çeşitliliği çok yüksek olabilir ya da cache boyutu yetersiz. msg-cache-size ve rrset-cache-size değerlerini artırın.

Yüksek recursion süresi: Upstream DNS sunucularınız yavaş olabilir. outbound-msg-retry ve target-fetch-policy ayarlarını gözden geçirin.

Thread başına düşen sorgu sayısı dengesiz: so-reuseport: yes aktif değilse thread’ler arasında yük dengesiz dağılabilir.

Yüksek paket kaybı: outgoing-range değeri too low olabilir. Özellikle yüksek QPS testlerinde bu değeri artırın.

# Hızlı tanı komutu
unbound-control stats | grep -E "(num.queries|cachehits|cachemiss|recursion)" | 
while IFS='=' read key value; do
    printf "%-45s: %sn" "$key" "$value"
done

Karşılaştırmalı Test: Unbound vs Bind vs PowerDNS Recursor

Kendi sunucunuzun rakiplerle karşılaştırmasını yapmak isteyebilirsiniz. Bunun için Docker kullanarak izole test ortamı oluşturabilirsiniz:

# Unbound test container
docker run -d --name unbound-test 
    -p 5301:53/udp -p 5301:53/tcp 
    mvance/unbound:latest

# Bind test container
docker run -d --name bind-test 
    -p 5302:53/udp -p 5302:53/tcp 
    internetsystemsconsortium/bind9:9.18

# Her iki sunucuya karşı test
echo "=== UNBOUND ==="
dnsperf -s 127.0.0.1 -p 5301 -d /tmp/large_queryfile.txt -l 30 -c 50 2>&1 | 
    grep -E "(per second|latency|lost)"

echo "=== BIND ==="
dnsperf -s 127.0.0.1 -p 5302 -d /tmp/large_queryfile.txt -l 30 -c 50 2>&1 | 
    grep -E "(per second|latency|lost)"

# Temizlik
docker stop unbound-test bind-test
docker rm unbound-test bind-test

Sonuç

Unbound performans testi sadece “çalışıyor mu” sorusunun ötesine geçip “ne kadar iyi çalışıyor” sorusuna cevap arıyor. Bu yazıda ele aldığımız yaklaşımları özetlemek gerekirse:

  • Baseline oluşturun: Her optimizasyon öncesi ve sonrası ölçüm yapın, sezgiyle değil veriyle karar verin.
  • Gerçekçi test verileri kullanın: Gerçek trafiğe benzer sorgu setleri hazırlayın, yüzlerce rastgele alan adı değil, gerçek dağılımı yansıtan setler kullanın.
  • Sadece ortalamaya bakmayın: P95 ve P99 gecikme değerleri çoğu zaman ortalamadan daha anlamlı bilgi verir.
  • Stres testini ihmal etmeyin: Sisteminizin teorik kapasitesini biliyor olmanız, ani trafik artışlarına hazırlıklı olmanızı sağlar.
  • Sürekli izleyin: Tek seferlik benchmark yeterli değil; unbound-control stats çıktısını düzenli aralıklarla toplayın.

Cache hit oranınız %80’in altındaysa veya P99 gecikmeniz 50ms’yi geçiyorsa konfigürasyonunuzu gözden geçirme zamanı gelmiş demektir. Sayılar yalan söylemez; sadece onlara kulak vermek gerekiyor.

Bir yanıt yazın

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