Arşivleme İşlemlerinde FIFO ve Named Pipe Kullanımı: Geçici Dosya Oluşturmadan Sıkıştırma Pipeline’ı Kurma

Disk alanı her zaman sınırlıdır. Özellikle büyük log arşivleri, veritabanı yedekleri veya medya dosyaları üzerinde çalışırken “önce sıkıştır, sonra aktar” ya da “önce oluştur, sonra işle” gibi geçici dosya bağımlı iş akışları hem zaman hem de disk kaybına yol açar. Oysa Linux’un bize sunduğu FIFO (named pipe) mekanizması, bu geçici dosya cehenneminden çıkmanın en zarif yolu. Bugün bu konuyu hem teorik hem de gerçek dünya senaryolarıyla masaya yatıracağız.

FIFO Nedir ve Neden Önemlidir?

FIFO, “First In, First Out” kelimelerinin kısaltmasıdır ve Unix/Linux dünyasında named pipe olarak da bilinir. Anonim pipe’lardan (| operatörü) temel farkı, dosya sistemi üzerinde gerçek bir isimle görünmesidir. Yani bir süreç bir uca yazarken, tamamen bağımsız başka bir süreç diğer uçtan okuyabilir.

Normal bir pipe’ta iki komutun aynı komut satırında bulunması gerekir. FIFO’da ise süreçler birbirinden bağımsız olabilir, farklı terminallerde hatta farklı zamanlarda çalışabilirler. Bu özellik, arşivleme pipeline’larında olağanüstü esneklik sağlar.

# FIFO oluşturmanın iki yolu
mkfifo /tmp/arsiv_pipe
mknod /tmp/arsiv_pipe p  # Eski yöntem, ama hala çalışır

FIFO’yu oluşturduktan sonra ls -la ile baktığınızda dosya tipinin p olduğunu görürsünüz:

ls -la /tmp/arsiv_pipe
# prw-r--r-- 1 user user 0 Ara 15 14:23 /tmp/arsiv_pipe

Başındaki p harfi, bu “dosyanın” aslında bir pipe olduğunu gösterir. Boyutu sıfır, çünkü bu bir depolama alanı değil, veri akış kanalıdır.

Geçici Dosya Olmadan Sıkıştırma: Temel Mantık

Klasik iş akışında şöyle bir senaryo düşünün: 50GB’lık bir dizini önce tar ile arşivleyip ardından sıkıştırıyorsunuz.

# GEÇİCİ DOSYA YAKLAŞIMI - kaçınılması gereken
tar -cf /tmp/yedek_gecici.tar /var/log/uygulama/
gzip /tmp/yedek_gecici.tar
mv /tmp/yedek_gecici.tar.gz /backup/yedek.tar.gz

Bu yaklaşımda hem 50GB geçici dosya oluşturdunuz hem de işlem iki aşamalı olduğu için iki kez disk I/O yaptınız. Sistem yöneticiliğinde disk I/O genellikle darboğazın ta kendisidir.

Anonim pipe ile bunu şöyle yapabilirsiniz:

# ANONİM PIPE - tek komut satırı sınırlaması var
tar -cf - /var/log/uygulama/ | gzip -9 > /backup/yedek.tar.gz

Buradaki -cf - ifadesinde ikinci tire, stdout’a yaz anlamına gelir. Peki ya bu iki işlemi birbirinden bağımsız yönetmeniz gerekiyorsa? İşte FIFO devreye giriyor.

FIFO ile Bağımsız Süreç Pipeline’ı

Gerçek bir senaryo düşünelim: Bir üretim sunucusunda geceleri çalışan bir yedekleme scripti var. Sıkıştırma işlemi CPU açısından ağır, arşivleme ise I/O ağır. Bu iki işlemi farklı nice değerleriyle çalıştırmak istiyorsunuz.

# FIFO oluştur
mkfifo /tmp/yedek_kanal

# Terminal 1'de - I/O ağır iş, düşük öncelik gerekmez
tar -cf /tmp/yedek_kanal /var/log/uygulama/ &

# Terminal 2'de - CPU ağır iş, yüksek nice değeri ile
nice -n 15 gzip -9 < /tmp/yedek_kanal > /backup/yedek.tar.gz

# İşlem bittikten sonra temizlik
rm /tmp/yedek_kanal

Burada güzel olan şu: tar süreci /tmp/yedek_kanal‘a yazıyor, gzip süreci ise aynı kanaldan okuyor. İkisi arasında hiçbir geçici dosya yok. Veri doğrudan kernel’ın pipe buffer’ı üzerinden akıyor.

Paralel Sıkıştırma ile Performans Optimizasyonu

Modern sunucularda çok çekirdekli işlemciler neredeyse standart. Ama klasik gzip tek çekirdek kullanır. FIFO kullanarak paralel sıkıştırma araçlarıyla çok daha verimli pipeline’lar kurabilirsiniz.

# pigz (parallel gzip) ile FIFO kullanımı
mkfifo /tmp/paralel_pipe

# Arka planda tar başlat
tar -cf /tmp/paralel_pipe /veri/buyuk_dizin/ &
TAR_PID=$!

# Tüm çekirdekleri kullanan pigz ile sıkıştır
pigz -9 -p $(nproc) < /tmp/paralel_pipe > /backup/buyuk_arsiv.tar.gz

# tar'ın düzgün kapandığını kontrol et
wait $TAR_PID
echo "Çıkış kodu: $?"

rm /tmp/paralel_pipe

$(nproc) ifadesi sistemdeki mantıksal çekirdek sayısını döndürür. 8 çekirdekli bir sistemde gzip‘e kıyasla 4-6 kat hızlanma görmek mümkün. Bu fark, özellikle günlük terabayt ölçeğinde yedekleme yapan ortamlarda çok ciddi bir operasyonel kazanım.

Çok Aşamalı Pipeline: Bir FIFO’dan Fazlası

Bazen arşivleme işlemi sadece sıkıştırmaktan ibaret değildir. Şifreli ve sıkıştırılmış yedek oluşturmak istiyorsunuz diyelim. Klasik yöntemde önce sıkıştırırsınız, sonra şifrelersiniz, iki geçici dosya daha. FIFO zinciri ile:

# İki FIFO oluştur
mkfifo /tmp/pipe_sikistir
mkfifo /tmp/pipe_sifrele

# Aşama 1: tar -> pipe_sikistir
tar -cf /tmp/pipe_sikistir /kritik_veriler/ &

# Aşama 2: pipe_sikistir -> bzip2 -> pipe_sifrele
bzip2 -9 < /tmp/pipe_sikistir > /tmp/pipe_sifrele &

# Aşama 3: pipe_sifrele -> openssl -> hedef dosya
openssl enc -aes-256-cbc -pbkdf2 -pass pass:$YEDEK_SIFRE 
    < /tmp/pipe_sifrele > /backup/kritik_sifreliyedek.tar.bz2.enc

# Temizlik
rm /tmp/pipe_sikistir /tmp/pipe_sifrele

Bu pipeline’da üç bağımsız süreç çalışıyor ve aralarında sıfır geçici dosya var. Veri kernel buffer’larından geçerek akıyor. 100GB’lık kritik veriyi bu şekilde işlediğinizde disk tasarrufu da ciddi boyutlara ulaşıyor.

Gerçek Dünya Senaryosu: Log Rotasyonu ve Uzak Sunucuya Transfer

Birçok ortamda log dosyaları yerel olarak sıkıştırılıp uzak bir arşiv sunucusuna gönderilir. Bu senaryo tipik olarak şöyle işler: sıkıştır, aktif ağ bağlantısını bekle, gönder, sil. FIFO ile bu işlemi tek seferde yapabilirsiniz:

#!/bin/bash
# log_arsivle.sh

LOG_DIZIN="/var/log/nginx"
UZAK_SUNUCU="[email protected]"
UZAK_YOL="/arsiv/nginx"
TARIH=$(date +%Y%m%d_%H%M%S)
PIPE_YOLU="/tmp/log_pipe_$$"  # $$ = PID, benzersiz isim

# Temizlik fonksiyonu
temizle() {
    rm -f "$PIPE_YOLU"
}
trap temizle EXIT

# FIFO oluştur
mkfifo "$PIPE_YOLU"

# Yerel sıkıştırma yok, doğrudan SSH üzerinden aktar
tar -czf "$PIPE_YOLU" "$LOG_DIZIN"/ &
TAR_PID=$!

# FIFO'dan oku ve SSH ile uzak sunucuya yaz
ssh "$UZAK_SUNUCU" "cat > ${UZAK_YOL}/nginx_${TARIH}.tar.gz" < "$PIPE_YOLU"

# tar'ın durumunu kontrol et
wait $TAR_PID
if [ $? -eq 0 ]; then
    echo "Başarılı: nginx_${TARIH}.tar.gz aktarıldı"
    find "$LOG_DIZIN" -name "*.log" -mtime +7 -delete
else
    echo "HATA: tar başarısız oldu" >&2
    exit 1
fi

Bu scriptte birkaç önemli nokta var. $$ ile pipe dosyasına benzersiz isim veriliyor, böylece birden fazla script eş zamanlı çalışsa da çakışma olmaz. trap temizle EXIT ile script herhangi bir şekilde sonlansa da (hata dahil) FIFO temizleniyor. Uzak sunucuda herhangi bir özel yazılım gerektirmiyor, salt cat yeterli.

tee Komutu ile Çoklu Hedef

Bazen aynı arşivi hem yerel hem de uzak hedefe göndermek, ya da hem sıkıştırılmış hem de sıkıştırılmamış halini saklamak gerekir. tee komutu FIFO ile birleşince bu çok temiz bir hal alıyor:

# Aynı arşivi hem yerel hem uzak hedefe gönder
mkfifo /tmp/tee_pipe1
mkfifo /tmp/tee_pipe2

tar -cf - /onemli_veriler/ | tee /tmp/tee_pipe1 /tmp/tee_pipe2 > /dev/null &

# Pipe 1'den gzip ile yerel yedek
gzip -9 < /tmp/tee_pipe1 > /backup/yerel_yedek.tar.gz &

# Pipe 2'den xz ile uzak yedek (daha iyi sıkıştırma oranı, yavaş)
xz -9 < /tmp/tee_pipe2 | ssh backup@uzak-sunucu "cat > /backup/uzak_yedek.tar.xz"

wait
rm /tmp/tee_pipe1 /tmp/tee_pipe2

Burada tee komutu gelen veriyi iki farklı FIFO’ya aynı anda yazıyor. Bir tarafta hız odaklı gzip, diğer tarafta sıkıştırma oranı odaklı xz çalışıyor. İkisi de aynı kaynak veriden beslendiği için tar yalnızca bir kez çalışıyor, disk sadece bir kez okunuyor.

Dikkat Edilmesi Gereken Durumlar

FIFO kullanırken bazı kritik noktalar var. Bunları görmezden gelmek script’lerinizin sessizce askıda kalmasına neden olabilir.

Blocking davranışı: FIFO, okuyucu ve yazıcı hazır olmadan bloke eder. Eğer bir ucu açarsanız ve diğer ucu kimse açmazsa süreciniz bekler. Bu yüzden genellikle bir tarafı & ile arka plana almak gerekir.

Hata yönetimi: Pipe’ın bir ucundaki süreç çökerse, diğer taraf SIGPIPE sinyali alır. Scriptlerinizde set -o pipefail kullanmak bu durumları yakalamak için kritik:

#!/bin/bash
set -euo pipefail

PIPE="/tmp/guvenli_pipe_$$"
mkfifo "$PIPE"
trap "rm -f $PIPE" EXIT

tar -cf "$PIPE" /veri/ &
TAR_PID=$!

gzip -9 < "$PIPE" > /backup/cikti.tar.gz
GZIP_STATUS=$?

wait $TAR_PID
TAR_STATUS=$?

if [ $TAR_STATUS -ne 0 ] || [ $GZIP_STATUS -ne 0 ]; then
    echo "Pipeline hatası: tar=$TAR_STATUS, gzip=$GZIP_STATUS" >&2
    rm -f /backup/cikti.tar.gz  # Eksik dosyayı temizle
    exit 1
fi

İzin sorunları: FIFO dosyası oluşturan kullanıcı ile onu kullanan kullanıcı farklı olabilir. Özellikle cron job’larında bu sorun sık yaşanır. Varsayılan izinler 644, ama genellikle yazıcı için 622 ya da doğru grup ataması ile bu sorun çözülür.

Pipe buffer boyutu: Linux’ta varsayılan pipe buffer boyutu 64KB (bazı sistemlerde 1MB’a kadar çıkabilir). Çok yavaş tüketilen bir FIFO, yazıcı süreci buffer dolduğunda bloke eder. Bu genellikle sorun değildir ama gerçek zamanlı izleme yapıyorsanız göz önünde bulundurulmalı.

Process Substitution ile Karşılaştırma

Bash’in process substitution özelliği (<() ve >()) de benzer şeyler yapabilir, ancak önemli farklar var:

# Process substitution ile (bash'e özgü)
tar -cf >(gzip -9 > /backup/yedek.tar.gz) /veri/

# FIFO ile (POSIX uyumlu, daha taşınabilir)
mkfifo /tmp/p
tar -cf /tmp/p /veri/ &
gzip -9 < /tmp/p > /backup/yedek.tar.gz
rm /tmp/p

Process substitution daha kısa ve okunabilir, ama bash’e özgü. Scriptiniz dash, sh veya başka bir POSIX kabuğunda çalışacaksa FIFO tercih edilmeli. Ayrıca FIFO, süreçlerin tamamen bağımsız lifecycle’lara sahip olduğu karmaşık senaryolarda daha iyi kontrol sunar.

Büyük Ölçekli Yedekleme: Veritabanı Dump + Sıkıştırma

PostgreSQL veya MySQL dump işlemlerinde FIFO kullanımı son derece yaygın ve etkilidir:

#!/bin/bash
# db_yedekle.sh - Geçici dosya olmadan veritabanı yedeği

DB_ADI="uretim_db"
YEDEK_DIZIN="/backup/db"
TARIH=$(date +%Y%m%d)
PIPE="/tmp/db_pipe_$$"

mkfifo "$PIPE"
trap "rm -f $PIPE" EXIT

# PostgreSQL dump -> FIFO -> paralel sıkıştırma
pg_dump -U postgres -Fc "$DB_ADI" > "$PIPE" &
DUMP_PID=$!

# FIFO'dan al, sıkıştır ve şifrele
pigz -9 < "$PIPE" | 
    openssl enc -aes-256-gcm -pbkdf2 -iter 100000 
    -pass file:/etc/backup/sifre.key 
    > "${YEDEK_DIZIN}/${DB_ADI}_${TARIH}.dump.gz.enc"

wait $DUMP_PID
if [ $? -eq 0 ]; then
    echo "DB yedeği başarılı: ${DB_ADI}_${TARIH}"
    # Son 7 günden eski yedekleri temizle
    find "$YEDEK_DIZIN" -name "*.dump.gz.enc" -mtime +7 -delete
fi

Bu yaklaşımla veritabanı dump’ı RAM’e ya da diske hiç yazılmadan, doğrudan sıkıştırılıp şifreleniyor. Büyük prod veritabanlarında bu, işlem süresini ve disk kullanımını dramatik biçimde düşürüyor.

FIFO Kullanımını İzleme ve Debug

FIFO ile çalışırken bazen pipeline’ın nerede takıldığını anlamak güçleşebilir. Birkaç pratik debug tekniği:

# lsof ile FIFO'ya hangi süreçlerin bağlı olduğunu gör
lsof /tmp/yedek_pipe

# FIFO'nun kernel içindeki durumunu kontrol et
cat /proc/$(pgrep tar)/fdinfo/1  # tar'ın stdout fd'si

# pv ile pipe üzerinden geçen veriyi izle (pipe viewer)
mkfifo /tmp/izlenen_pipe
tar -cf /tmp/izlenen_pipe /buyuk_veri/ &
pv < /tmp/izlenen_pipe | gzip -9 > /backup/cikti.tar.gz
rm /tmp/izlenen_pipe

pv (pipe viewer) aracı, FIFO üzerinden geçen veri hızını, tahmini tamamlanma süresini ve işlenen toplam veriyi gerçek zamanlı gösterir. Uzun süren yedekleme işlemlerinde ne kadarının tamamlandığını görmek için vazgeçilmez.

Sonuç

FIFO ve named pipe’lar, Linux sistem yönetiminin en az fark edilen ama en zarif araçlarından biri. Arşivleme ve sıkıştırma pipeline’larında kullanıldığında üç kritik avantaj sağlıyor: disk alanı tasarrufu, azaltılmış I/O yükü ve bağımsız süreçler arasında temiz veri akışı.

Pratik özeti şöyle çıkarabiliriz:

  • Tek komut satırında halledilebilen işlemler için anonim pipe (|) yeterli
  • Bağımsız süreçler veya farklı terminal oturumları arasında veri aktarımı için FIFO kullanın
  • Çok çekirdekli sistemlerde pigz ve FIFO kombinasyonu tek çekirdekli gzip‘e göre dramatik hız artışı sağlar
  • Her zaman trap ile temizlik mekanizması ekleyin, askıda kalan FIFO’lar sorun yaratır
  • set -o pipefail ile pipeline hatalarını mutlaka yakalayın
  • pv aracını uzun işlemlerin izlenmesi için pipeline’a ekleyin

Geçici dosya bağımlı eski alışkanlıklar, özellikle disk alanının kısıtlı olduğu ya da I/O’nun darboğaz oluşturduğu ortamlarda ciddi operasyonel maliyete dönüşüyor. FIFO tabanlı pipeline’lar bu maliyeti ortadan kaldırıyor ve scriptlerinizi daha okunabilir, daha güvenilir hale getiriyor. Bir sonraki yedekleme scriptini yazarken geçici dosya oluşturmadan önce bir dakika durup “Bunu bir FIFO ile yapabilir miyim?” diye sormaya değer.

Bir yanıt yazın

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