Arşivleme İşlemlerinde Bellek ve CPU Kullanımını İzleme: nice, ionice ve cgroups ile Kaynak Sınırlandırma
Prodüksiyon ortamında büyük bir arşivleme işlemi başlatıyorsunuz, tam o sırada monitoring sisteminiz CPU kullanımının %95’e çıktığını bildiriyor. Veritabanı sorguları yavaşlıyor, kullanıcılar şikayetçi ve siz ne yapacağınızı bilemiyorsunuz. Bu senaryo, birçok sistem yöneticisinin en az bir kez yaşadığı o klasik “neden bunu düşünmedim ki” anlarından biri. Arşivleme işlemleri, özellikle gece yarısı çalışan backup scriptleri, disk I/O ve CPU açısından son derece agresif davranabilir. Bu yazıda nice, ionice ve cgroups araçlarını kullanarak arşivleme süreçlerini nasıl kontrol altına alacağımızı, kaynak kullanımını nasıl izleyeceğimizi ve gerçek dünyada işe yarayan çözümleri ele alacağız.
Önce Sorunun Kaynağını Anlamak
Bir tar veya gzip işleminin sisteme ne kadar yük bindirdiğini ölçmeden kaynak sınırlandırmasına geçmek, körü körüne hareket etmek demektir. Önce mevcut durumu gözlemleyin.
top veya htop açık bir terminalde arşivleme işlemini başlatın ve PID’i not alın. Sonra şu komutlarla daha detaylı bilgi toplayın:
# Arşivleme işleminin PID'ini bulun
pid=$(pgrep -f "tar czf")
# CPU ve bellek kullanımını izle
watch -n 1 "ps aux --pid $pid --no-headers | awk '{print "CPU:", $3"%", "MEM:", $4"%", "VSZ:", $5, "RSS:", $6}'"
Bu çıktı size gerçek zamanlı olarak işlemin ne kadar CPU ve RAM tükettiğini gösterir. Özellikle RSS (Resident Set Size) değeri önemlidir; swap’a düşmeden bellekte tutulan gerçek veriyi gösterir.
Disk I/O tarafına bakmak için iotop kullanın:
# Sadece arşivleme işleminin I/O istatistiklerini göster
sudo iotop -p $pid -b -n 5 -d 2
Buradan elde ettiğiniz okuma/yazma hızları, ionice parametrelerini belirlerken referans noktanız olacak. Eğer 150MB/s üzeri yazma hızı görüyorsanız ve bu bir production disk ise, sorun zaten burada başlıyor demektir.
nice ile CPU Önceliğini Düzenlemek
nice değeri, Linux scheduler’ına bir sürecin ne kadar “nazik” davranması gerektiğini söyler. -20 ile 19 arasında değer alır; -20 en yüksek öncelik, 19 en düşük öncelik anlamına gelir. Varsayılan değer 0’dır.
Arşivleme işlemlerini başlatırken nice değerini düşünmeden çalıştırmanın bedeli ağır olabilir. Benim önerim, özellikle production saatlerinde çalışan her arşivleme işini en az nice 10 ile başlatmaktır.
# Yeni bir arşivleme işlemini düşük öncelikle başlat
nice -n 15 tar czf /backup/arsiv_$(date +%Y%m%d).tar.gz /var/www/html/
# Birden fazla sıkıştırma işlemini pipe ile düşük öncelikle çalıştır
nice -n 15 tar cf - /data/buyuk_dizin/ | nice -n 15 gzip -9 > /backup/buyuk_arsiv.tar.gz
İkinci komuttaki pipe örneği çok önemli: tar ve gzip ayrı process olarak çalışır. Her ikisini de nice ile sarmallamazsanız, gzip yüksek öncelikte çalışmaya devam eder.
Halihazırda çalışan bir sürece sonradan müdahale etmek için renice kullanın:
# Çalışan bir işlemin nice değerini değiştir
sudo renice -n 19 -p $(pgrep -f "gzip")
# Bir kullanıcıya ait tüm süreçlerin nice değerini değiştir
sudo renice -n 10 -u backup_user
Burada bir gerçekliği paylaşayım: nice değeri CPU scheduler’ı üzerinde etki eder ama sistem meşgul olmadığında nice 19 ile çalışan bir süreç de CPU’nun tamamını kullanabilir. Nice, sadece rekabette kimin önce gideceğini belirler. Sistem boştaysa nice 19 bile “koşabilir”.
ionice ile Disk I/O Önceliğini Kontrol Altına Almak
CPU’dan daha kritik olan nokta genellikle disk I/O’dur. Özellikle birden fazla uygulamanın aynı diski paylaştığı ortamlarda, sınırsız disk erişimi olan bir tar işlemi sistemi kolayca felç edebilir.
ionice, Linux CFQ (Completely Fair Queuing) I/O scheduler’ı ile çalışır ve üç sınıf üzerinden öncelik belirler:
- Sınıf 1 (RT – Real Time): En yüksek öncelik, isteği hemen karşılanır
- Sınıf 2 (Best Effort): Varsayılan sınıf, 0-7 arası öncelik değeri alır
- Sınıf 3 (Idle): Sistemde başka disk işi yoksa çalışır
# Arşivleme işlemini idle I/O sınıfında başlat
ionice -c 3 tar czf /backup/arsiv.tar.gz /home/
# Best Effort sınıfında ama düşük öncelikle (7 en düşük)
ionice -c 2 -n 7 tar czf /backup/arsiv.tar.gz /home/
# nice ile birleştirerek hem CPU hem I/O önceliğini düşür
ionice -c 3 nice -n 19 tar czf /backup/buyuk_arsiv.tar.gz /mnt/data/
Çalışan bir sürece ionice uygulamak için:
# PID'e göre ionice değeri değiştir
sudo ionice -c 3 -p $(pgrep -f "tar czf")
Gerçek dünyadan bir örnek vereyim: 50GB’lık bir web dizinini her gece 02:00’da arşivleyen bir cron job’ı vardı. Sabah 08:00’e kadar bitmesi gerekiyordu ama sorun şu ki, gece yarısından 06:00’a kadar başka bir ETL süreci de aynı disklere yazıyordu. ionice -c 3 ile çalıştırınca ETL işi önce geliyor, tar boş anlarda ilerliyor, her ikisi de zamanında bitiyordu.
# Crontab'a doğru şekilde ekleme
# /etc/cron.d/backup_job
0 2 * * * backup_user ionice -c 3 nice -n 19 tar czf /backup/web_$(date +%Y%m%d).tar.gz /var/www/
cgroups ile Kapsamlı Kaynak Sınırlandırma
nice ve ionice belirli senaryolarda yeterli olsa da, gerçek kontrol için cgroups (Control Groups) kullanmanız gerekir. cgroups ile CPU, bellek, disk I/O ve hatta ağ bant genişliğini kesin limitlerle kontrol altına alabilirsiniz.
cgroups v2 ile Temel Kurulum
Modern dağıtımlar (RHEL 9, Ubuntu 22.04 ve sonrası) varsayılan olarak cgroups v2 kullanır. Hangi versiyonu kullandığınızı kontrol edin:
# cgroups versiyonunu kontrol et
mount | grep cgroup
# veya
stat -fc %T /sys/fs/cgroup/
Eğer cgroup2fs çıktısı görüyorsanız v2 kullanıyorsunuz demektir.
systemd-run ile Geçici cgroup Oluşturma
En pratik yöntem, systemd-run ile arşivleme işinizi sınırlandırılmış bir cgroup içinde çalıştırmaktır:
# CPU ve bellek sınırı ile tar işlemini başlat
# CPUQuota: toplam CPU'nun %20'si
# MemoryLimit: maksimum 512MB RAM
systemd-run --scope
--property=CPUQuota=20%
--property=MemoryLimit=512M
--property=IOWeight=10
-- tar czf /backup/arsiv.tar.gz /var/lib/mysql/backup/
# Daha kapsamlı sınırlandırma
systemd-run --unit=backup-arsivleme
--scope
--property=CPUQuota=25%
--property=MemoryLimit=1G
--property=MemorySwapMax=0
--property=IOWeight=50
--property=IOReadBandwidthMax="/dev/sdb 50M"
--property=IOWriteBandwidthMax="/dev/sdb 50M"
-- nice -n 15 tar czf /backup/buyuk_arsiv.tar.gz /data/
MemorySwapMax=0 parametresi swap kullanımını tamamen engeller. Bu önemli bir detay; bellek limitine takılan bir işlem swap’a geçmeye çalışırsa disk I/O iki katına çıkar.
Manuel cgroup Oluşturma
Daha ince ayarlı kontrol için cgroup’u elle oluşturabilirsiniz:
# Yeni bir cgroup oluştur
sudo mkdir /sys/fs/cgroup/backup_limit
# CPU limitini ayarla (100000 = 1 CPU core, 20000 = %20 CPU)
echo "20000 100000" | sudo tee /sys/fs/cgroup/backup_limit/cpu.max
# Bellek limitini ayarla (536870912 = 512MB)
echo "536870912" | sudo tee /sys/fs/cgroup/backup_limit/memory.max
# I/O ağırlığını ayarla (1-10000 arası, varsayılan 100)
echo "10" | sudo tee /sys/fs/cgroup/backup_limit/io.weight
# Mevcut shell'i bu cgroup'a ekle, sonra backup komutunu çalıştır
echo $$ | sudo tee /sys/fs/cgroup/backup_limit/cgroup.procs
tar czf /backup/arsiv.tar.gz /home/
Bu yaklaşımda dikkat edilmesi gereken nokta: cgroup’a eklediğinizde mevcut shell process’i de bu gruba girer. İşiniz bitince shell’i başka bir cgroup’a taşımanız gerekir. Bu nedenle systemd-run yaklaşımı genellikle daha temizdir.
Gerçek Dünya Senaryosu: Backup Script’ini Sınırlandırma
Şimdi tüm bu araçları bir araya getirelim. Aşağıdaki script, bir production ortamında güvenle çalıştırabileceğiniz kapsamlı bir backup wrapper’ıdır:
#!/bin/bash
# /usr/local/bin/safe_backup.sh
# Kaynak sınırlandırmalı arşivleme scripti
KAYNAK_DIZIN="${1:-/var/www}"
HEDEF_DIZIN="${2:-/backup}"
TARIH=$(date +%Y%m%d_%H%M%S)
ARSIV_ADI="${HEDEF_DIZIN}/backup_${TARIH}.tar.gz"
LOG_DOSYASI="/var/log/backup_monitor.log"
# CPU ve I/O izleme fonksiyonu
izle_ve_kaydet() {
local pid=$1
while kill -0 "$pid" 2>/dev/null; do
ps aux --pid "$pid" --no-headers 2>/dev/null |
awk -v ts="$(date '+%H:%M:%S')"
'{printf "[%s] CPU: %s%% MEM: %s%% RSS: %sKBn", ts, $3, $4, $6}'
>> "$LOG_DOSYASI"
sleep 30
done
}
echo "[$(date)] Backup basliyor: $KAYNAK_DIZIN -> $ARSIV_ADI" >> "$LOG_DOSYASI"
# systemd-run ile sınırlandırılmış ortamda çalıştır
systemd-run --scope
--property=CPUQuota=30%
--property=MemoryLimit=768M
--property=MemorySwapMax=0
--property=IOWeight=25
-- ionice -c 2 -n 6 nice -n 15
tar czf "$ARSIV_ADI" "$KAYNAK_DIZIN" &
BACKUP_PID=$!
# Arka planda izlemeyi başlat
izle_ve_kaydet $BACKUP_PID &
IZLEME_PID=$!
# Backup bitmesini bekle
wait $BACKUP_PID
CIKIS_KODU=$?
# İzleme process'ini durdur
kill $IZLEME_PID 2>/dev/null
if [ $CIKIS_KODU -eq 0 ]; then
BOYUT=$(du -sh "$ARSIV_ADI" | cut -f1)
echo "[$(date)] Backup basarili. Boyut: $BOYUT" >> "$LOG_DOSYASI"
else
echo "[$(date)] HATA: Backup basarisiz oldu! Cikis kodu: $CIKIS_KODU" >> "$LOG_DOSYASI"
fi
exit $CIKIS_KODU
Bu script, tüm arşivleme sürecini izler, log tutar ve kaynak kullanımını sınırlandırır.
Anlık İzleme ve Alarm Mekanizması
Çalışan bir arşivleme işlemi sırasında anlık izleme yapmak için şu kombinasyonu kullanabilirsiniz:
# Arşivleme işleminin detaylı kaynak kullanımını izle
pid=$(pgrep -f "tar czf" | head -1)
# /proc üzerinden gerçek zamanlı bilgi oku
watch -n 2 "
echo '=== CPU ve Bellek ==='
cat /proc/${pid}/status | grep -E 'VmRSS|VmSwap|voluntary'
echo ''
echo '=== I/O İstatistikleri ==='
cat /proc/${pid}/io
echo ''
echo '=== cgroup Limitleri ==='
cat /proc/${pid}/cgroup
"
/proc/[pid]/io dosyası özellikle değerlidir; toplam okunan ve yazılan byte miktarını, syscall sayısını gösterir. Arşivleme işlemi tamamlandığında bu değerleri kaydederseniz gelecekteki kapassite planlaması için güzel bir veri noktası elde edersiniz.
Farklı Sıkıştırma Algoritmalarının Kaynak Etkisi
Son olarak algoritma seçiminin kaynak kullanımına etkisini de göz önünde bulundurun. gzip hızlı ama CPU tüketen, bzip2 daha iyi sıkıştırma ama daha fazla CPU, xz en iyi sıkıştırma ama en fazla CPU, lz4 ise minimum CPU ile orta düzey sıkıştırma sunar.
# Düşük CPU kullanımı için lz4 ile arşivleme (paralel sıkıştırma desteği de var)
nice -n 15 ionice -c 3 tar --use-compress-program=lz4 -cf /backup/hizli_arsiv.tar.lz4 /data/
# xz ile maksimum sıkıştırma ama CPU limitiyle
systemd-run --scope
--property=CPUQuota=15%
-- tar cJf /backup/yuksek_sikistirma.tar.xz /data/
lz4 ile sıkıştırılan arşivlerin gzip’e kıyasla 3-4 kat daha hızlı oluşturulduğunu, buna karşın dosya boyutunun %15-20 daha büyük olduğunu pratikte göreceksiniz. Disk alanı bol ama CPU kısıtlıysa lz4, tam tersi durumda xz tercih edilmelidir.
Sonuç
Arşivleme işlemlerinde kaynak yönetimi, birçok sysadmin’in ihmal ettiği ama bir kez production krizi yaşandıktan sonra asla unutmadığı bir konudur. nice ile CPU önceliğini, ionice ile disk I/O önceliğini kontrol altına alabilir, cgroups ile ise her ikisine kesin limitler koyabilirsiniz. Üç aracın birlikte kullanımı ise size hem esneklik hem de güvenilirlik sağlar.
Pratik özet olarak şunu söyleyebilirim: Başlangıç için tüm backup scriptlerinize ionice -c 2 -n 7 nice -n 15 eklemek bile büyük fark yaratır. Sonraki adımda systemd-run ile CPU ve bellek kotası koyun. Kritik ortamlarda ise /proc/[pid]/io çıktılarını düzenli kaydedin ve kapasite planlamasına dahil edin. Kaynak sınırlandırması işleri yavaşlatır, evet, ama production servislerinizi çökmekten korur. Bu denge her zaman doğru tarafta olmanızı sağlar.
