Yüksek Disk I/O: Kaynak Tespiti ve Optimizasyon
Bir gece yarısı alarm çalıyor, monitöringe bakıyorsun ve sunucunun disk I/O bekleme süresi tavana vurmuş. Uygulamalar yavaşlamış, kullanıcılar şikayet ediyor, ekip mesaj atıyor. İşte tam bu anda panik yapmak yerine sistematik bir yaklaşımla sorunu çözmek gerekiyor. Disk I/O sorunları, Linux sistem yöneticilerinin en sık karşılaştığı performans problemlerinden biri. Bu yazıda, yüksek disk I/O’nun nasıl tespit edileceğini, kaynağının nasıl bulunacağını ve uzun vadeli optimizasyon stratejilerini gerçek dünya senaryolarıyla ele alacağız.
Önce Durumu Anlamak: Temel Kavramlar
Disk I/O sorunlarına dalmadan önce birkaç temel kavramı netleştirmek gerekiyor.
I/O Wait (iowait) nedir? CPU’nun disk işlemlerinin tamamlanmasını beklediği süreyi ifade eder. top çıktısında %wa olarak görürsünüz. Normal koşullarda bu değerin %5’in altında olması beklenir. %20’nin üzerine çıktığında ciddi bir sorun var demektir.
Throughput vs Latency farkı önemli. Throughput, birim zamanda ne kadar veri okuyup yazabildiğiniz. Latency ise bir I/O işleminin tamamlanma süresi. Yüksek throughput ile çalışan bir sistem bile yüksek latency yaşayabilir, özellikle çok sayıda küçük rastgele I/O söz konusu olduğunda.
Sequential vs Random I/O ayrımı da kritik. Sıralı okuma/yazma (büyük dosyalar, log yazma gibi) mekanik disklerde çok daha hızlı. Rastgele I/O ise veritabanı sorguları, sanal makine disk işlemleri gibi senaryolarda ortaya çıkar ve özellikle HDD’lerde büyük performans kaybına yol açar.
Teşhis Araçları: İlk Adımlar
iostat ile Genel Duruma Bakmak
iostat, disk I/O analizinin ilk durağı. sysstat paketi içinde geliyor.
# 2 saniyede bir, 10 kez raporla
iostat -xz 2 10
# Belirli bir disk için
iostat -xz /dev/sda 2 5
# Human-readable format
iostat -xzh 2 5
iostat -x çıktısında dikkat etmeniz gereken alanlar:
- %util: Diskin ne kadar meşgul olduğu. %100’e yaklaşıyorsa disk doymuş demektir
- await: Ortalama I/O bekleme süresi (milisaniye). HDD için 20ms üzeri, SSD için 1ms üzeri sorunlu
- r/s ve w/s: Saniyedeki okuma ve yazma işlem sayısı
- rkB/s ve wkB/s: Saniyedeki okuma ve yazma hızı (KB cinsinden)
- svctm: Ortalama servis süresi. await’ten çok düşükse kuyruk var demektir
- avgqu-sz: Ortalama I/O kuyruk boyutu. 1’in üzerindeyse disk ayak uyduramıyor
iotop ile Hangi Prosesin Sebep Olduğunu Bulmak
iostat size genel tabloyu gösterir ama kim yapıyor bunu? İşte iotop burada devreye giriyor.
# Interaktif mod (root gerekli)
iotop
# Sadece I/O yapan prosesleri göster
iotop -o
# Batch modda çalıştır, log almak için
iotop -bod 2 -n 10 >> /var/log/iotop.log
# Belirli bir kullanıcının proseslerini izle
iotop -u www-data
iotop çıktısında TID (Thread ID), DISK READ, DISK WRITE, SWAPIN, IO> sütunlarını takip edin. IO> sütunu o threadin I/O bekleme yüzdesini gösterir. Aniden yükselen bir proses gördüğünüzde p tuşuyla proses bazına geçebilirsiniz.
dstat ile Anlık Takip
dstat, birden fazla kaynağı aynı anda izlemek için harika bir araç.
# Disk, CPU ve ağ birlikte
dstat -cdngy 2
# Disk istatistiklerini detaylı göster
dstat --disk-stat --disk-util 2
# Hangi proses en çok disk kullanıyor (top-procs eklentisi ile)
dstat --top-io --top-bio 2
Derinlemesine Teşhis: Asıl Kaynağı Bulmak
/proc Dosya Sistemi ile Manuel İnceleme
Bazen araçlara güvenmek yetmez, işin mutfağına girmek gerekir.
# Sistemdeki tüm blok cihazların anlık istatistikleri
cat /proc/diskstats
# Belirli bir prosesin I/O istatistikleri (PID yerine gerçek PID yaz)
cat /proc/$(pgrep mysql)/io
# Tüm proseslerin I/O istatistiklerini listele
for pid in /proc/[0-9]*/io; do
echo "=== PID: $(echo $pid | cut -d/ -f3) ==="
cat $pid 2>/dev/null
done | grep -A6 "rchar"
/proc/PID/io dosyasındaki alanlar:
- rchar: Okunan toplam byte (önbellek dahil)
- wchar: Yazılan toplam byte (önbellek dahil)
- read_bytes: Gerçekten diskten okunan byte
- write_bytes: Gerçekten diske yazılan byte
- cancelled_write_bytes: İptal edilen yazma işlemleri (dosya silinmeden önce yazılıp silinmiş)
blktrace ile Detaylı I/O Takibi
Gerçekten ileri düzey analiz gerekiyorsa blktrace ve blkparse ikilisi devreye giriyor. Üretim ortamında dikkatli kullanın, overhead yaratabilir.
# sda diski için 30 saniye kayıt al
blktrace -d /dev/sda -w 30 -o trace
# Kaydı analiz et
blkparse -i trace -o trace.txt
# Özet rapor oluştur
btt -i trace.blktrace.0 | head -50
blkparse çıktısında Q (Queue), M (Merge), D (Driver), C (Complete) aşamalarını takip ederek bir I/O isteğinin ne kadar sürede hangi aşamada geçirdiğini görebilirsiniz. Uzun Q süreleri scheduler sorununa, uzun D süreleri ise donanım sorununa işaret eder.
lsof ile Hangi Dosyaların Kullanıldığını Görmek
# En çok dosya açan prosesler
lsof 2>/dev/null | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# Belirli bir disk bölümündeki açık dosyalar
lsof /var/log
# Silinmiş ama hala açık tutulan büyük dosyalar (disk alanı sorunu)
lsof | grep deleted | awk '{print $7, $1, $2}' | sort -rn | head -20
Son komut özellikle kritik. Log dosyası silinip servis yeniden başlatılmadığında dosya handle hala açık kalır ve disk alanı serbest olmaz. Bu klasik bir senaryodur.
Gerçek Dünya Senaryoları
Senaryo 1: MySQL’in Geceyi Mahvetmesi
Bir e-ticaret sitesinde gece 02:00’de disk I/O tavana vurdu. iotop ile baktığımda mysqld prosesi saniyede 150MB yazıyordu. Sorun slow query logun aktif olması ve büyük sorguların log dosyasını patlatmasıydı.
# MySQL'in I/O durumunu izle
iotop -p $(pgrep mysqld) -b -d 2
# MySQL binary log boyutlarına bak
ls -lh /var/lib/mysql/mysql-bin.*
# InnoDB buffer pool kullanımı
mysql -e "SHOW ENGINE INNODB STATUSG" | grep -A5 "BUFFER POOL"
# Slow query log nereye yazıyor
mysql -e "SHOW VARIABLES LIKE 'slow_query_log%';"
Çözüm: Slow query log geçici olarak kapatıldı, innodb_buffer_pool_size RAM’in %70’ine çıkarıldı, binary log rotasyon periyodu düşürüldü.
Senaryo 2: Runaway Backup Süreci
Bir başka klasik senaryo. Backup scripti gündüz çalıştırılmış, rsync tüm diski tarıyor ve production workload ile yarışıyor.
# rsync prosesinin I/O sınırlandırma
ionice -c 3 rsync -av /data /backup
# Mevcut bir backup prosesini yavaşlat
ionice -c 3 -p $(pgrep rsync)
# ionice sınıflarını anlamak için
# -c 1: Realtime (tehlikeli, sistemi dondurabillir)
# -c 2: Best-effort (default, nice gibi)
# -c 3: Idle (sadece disk boşta çalışır)
ionice ile backup prosesini idle class’a alınca production I/O normal seviyeye döndü. Uzun vadeli çözüm olarak backup işleri cron‘da gece 03:00’e alındı ve ionice -c 3 ile çalıştırılır hale getirildi.
Senaryo 3: Elasticsearch Segment Merge Fırtınası
Elasticsearch yoğun indexing sırasında arka planda segment merge işlemi yapar. Bu işlem ciddi I/O üretir.
# ES node'un I/O durumu
iotop -p $(pgrep java) -b -o -d 2
# ES index istatistikleri API üzerinden
curl -s localhost:9200/_nodes/stats/indices/merges | python3 -m json.tool | grep -A5 "merges"
# Merge throttle değerini düşür (MB/s cinsinden)
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"indices.store.throttle.max_bytes_per_sec": "50mb"
}
}'
I/O Scheduler Optimizasyonu
Linux I/O scheduler seçimi performans üzerinde büyük etkiye sahip. Yanlış scheduler yanlış iş yüküyle büyük sorunlara yol açabilir.
# Mevcut scheduler'ı görüntüle
cat /sys/block/sda/queue/scheduler
# Kullanılabilir scheduler'lar
# [mq-deadline] kyber bfq none - köşeli parantez aktifi gösterir
# Scheduler değiştir (anlık, reboot sonrası kaybolur)
echo "mq-deadline" > /sys/block/sda/queue/scheduler
# Tüm diskler için döngüyle değiştir
for disk in /sys/block/sd*/queue/scheduler; do
echo "mq-deadline" > $disk
done
# Kalıcı yapmak için udev rule oluştur
cat > /etc/udev/rules.d/60-scheduler.rules << 'EOF'
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="mq-deadline"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none"
ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="none"
EOF
Scheduler önerileri:
- none (noop): SSD ve NVMe için ideal. Cihaz kendi optimizasyonunu yönetiyor
- mq-deadline: HDD ve genel amaçlı kullanım için. Latency garantisi sunar
- bfq: Masaüstü sistemler ve interaktif iş yükleri için. Eşit dağılım sağlar
- kyber: Düşük latency gerektiren NVMe sistemler için
Kernel ve Dosya Sistemi Parametreleri
vm.dirty Parametreleri
Kernel’in dirty page yönetimi I/O performansı için kritik.
# Mevcut değerleri görüntüle
sysctl vm.dirty_ratio vm.dirty_background_ratio vm.dirty_writeback_centisecs
# Yazma yoğun sistemler için optimize et
cat >> /etc/sysctl.conf << 'EOF'
# Dirty page oranı - toplam RAM'in yüzdesi
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
# Dirty page tarama periyodu (centisaniye)
vm.dirty_writeback_centisecs = 500
# Dirty page expire süresi (centisaniye)
vm.dirty_expire_centisecs = 3000
EOF
sysctl -p
vm.dirty_ratio: Bu orana ulaşınca uygulama prosesleri bloke olup direk yazma yapar. Çok düşük tutarsanız sürekli flush olur, çok yüksek tutarsanız ani I/O spike’ları yaşarsınız.
vm.dirty_background_ratio: Bu orana ulaşınca pdflush arka planda yazmaya başlar. dirty_rationun 1/3’ü civarında tutmak mantıklı.
Read-Ahead Optimizasyonu
# Mevcut read-ahead değeri (512 byte blok cinsinden)
blockdev --getra /dev/sda
# Sıralı okuma yoğun iş yükleri için artır (8192 = 4MB)
blockdev --setra 8192 /dev/sda
# Veritabanı gibi rastgele I/O için düşür
blockdev --setra 256 /dev/sda
# Kalıcı yapmak için
cat > /etc/udev/rules.d/60-readahead.rules << 'EOF'
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/blockdev --setra 8192 /dev$name"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", RUN+="/sbin/blockdev --setra 256 /dev$name"
EOF
Dosya Sistemi Seviyesinde Optimizasyon
Mount Seçenekleri
/etc/fstab mount seçenekleri I/O performansını doğrudan etkiler.
# ext4 için performans odaklı mount seçenekleri
# /etc/fstab satırı örneği:
# /dev/sdb1 /data ext4 defaults,noatime,nodiratime,data=writeback 0 2
# noatime: Dosya erişim zamanı güncellemesi yapma (büyük I/O tasarrufu)
# nodiratime: Dizin erişim zamanı güncellemesi yapma
# data=writeback: Metadata journaling, data için değil (hız vs güvenlik tradeoff)
# Mevcut mount seçeneklerini görüntüle
findmnt -o TARGET,OPTIONS /data
# Yeniden mount et (fstab güncellendikten sonra)
mount -o remount /data
XFS Optimizasyonu
XFS, büyük dosyalar ve yüksek throughput için ext4’ten daha iyi performans gösterebilir.
# XFS dosya sistemi istatistikleri
xfs_info /dev/sdb1
# XFS I/O istatistikleri
xfs_stats /dev/sdb1
# XFS için fstab mount seçenekleri
# /dev/sdb1 /data xfs defaults,noatime,largeio,inode64,logbsize=256k 0 2
# largeio: Büyük I/O işlemlerini optimize eder
# inode64: 64-bit inode numaraları, büyük dosya sistemleri için
# logbsize: Journal buffer boyutu
Monitoring ve Alerting Kurulumu
Sorunu çözmek kadar önemli olan, bir daha aynı sorunu erkenden yakalamak.
#!/bin/bash
# /usr/local/bin/io-monitor.sh
# Basit I/O monitoring scripti
THRESHOLD_UTIL=80
THRESHOLD_AWAIT=50
ALERT_EMAIL="[email protected]"
while true; do
# iostat çıktısından util ve await değerlerini al
iostat -xz 1 1 | awk 'NR>3 && $1 ~ /^[sv]d/ {
util=$NF
await=$10
disk=$1
if (util+0 > '$THRESHOLD_UTIL') {
print "ALERT: " disk " util=" util "%"
}
if (await+0 > '$THRESHOLD_AWAIT') {
print "ALERT: " disk " await=" await "ms"
}
}' | while read alert; do
echo "$alert - $(date)" | mail -s "Disk I/O Alert" $ALERT_EMAIL
logger -t io-monitor "$alert"
done
sleep 60
done
Daha ciddi ortamlar için Prometheus + node_exporter + Grafana kombinasyonu kullanın. Node_exporter node_disk_io_time_seconds_total, node_disk_reads_completed_total gibi metrikleri otomatik olarak toplar.
Uzun Vadeli Optimizasyon Stratejileri
Teknik düzeltmelerin ötesinde mimari kararlar da I/O sorunlarını kökten çözer.
Depolama katmanlama: Sık erişilen verileri SSD’de, arşiv verilerini HDD’de tutmak. LVM thin provisioning ile bu geçişi şeffaf yapabilirsiniz.
Uygulama seviyesinde cache: Redis veya Memcached gibi in-memory cache katmanı eklemek, disk I/O’yu dramatik biçimde düşürür. Bir e-ticaret projesinde sadece ürün listesi sayfalarını Redis’e cache’leyerek disk okuma I/O’sunu %60 düşürdük.
Asenkron yazma: Uygulamaların senkron yazma yerine mesaj kuyruğu (RabbitMQ, Kafka) üzerinden asenkron yazması, I/O spike’larını düzleştirir.
RAID ve LVM striping: Birden fazla diski RAID-0 ya da LVM striping ile birleştirerek throughput’u artırabilirsiniz. RAID-10, performans ve redundancy için iyi bir denge noktası.
tmpfs kullanımı: Geçici dosyalar, uygulama cache’leri, session verileri için tmpfs kullanmak disk I/O’yu sıfıra indirir.
# tmpfs mount örneği
mount -t tmpfs -o size=2G tmpfs /tmp
mount -t tmpfs -o size=4G tmpfs /var/cache/nginx
# fstab'a ekle
echo "tmpfs /tmp tmpfs defaults,size=2G 0 0" >> /etc/fstab
Sonuç
Yüksek disk I/O sorunları, tek bir sihirli çözümü olmayan, katmanlı bir teşhis ve optimizasyon süreci gerektiren problemlerdir. Yaklaşım her zaman şu sırayı izlemeli: önce iostat ile genel durumu anla, iotop ile sorumlu prosesi bul, /proc ile detaylı veri topla, ardından scheduler, kernel parametreleri ve dosya sistemi ayarlarını optimize et.
Unutmayın, production’da körü körüne değişiklik yapmayın. Her değişikliği izleyin, etkisini ölçün. iostat ve iotop çıktılarını değişiklik öncesi ve sonrası kaydedin. Özellikle vm.dirty_ratio gibi kernel parametrelerini değiştirirken veri kaybı riskini göz önünde bulundurun.
En iyi optimizasyon, sorunu hiç yaşamamak. Proactive monitoring, kapasite planlaması ve uygulama seviyesinde cache stratejileri, gece 02:00’deki o telefonu almanızı engelleyecek yatırımlardır. Sisteminizi tanıyın, metriklerinizi toplayın ve baseline değerlerinizi bilin. Sorun çıktığında “bu normal mi?” sorusunun cevabını verebilmek, problemin yarısını çözmüş olmak demektir.
