Arşiv İşlemlerinde stdin ve stdout Kullanımı: Dosyasız Sıkıştırma ile Bellek Üzerinde Veri Akışı

Dosyaları diske yazmadan sıkıştırmak, sıkıştırılmış veriyi doğrudan ağa göndermek ya da bir pipeline içinde onlarca gigabyte’lık veriyi tek satır komutla işlemek… Bunları ilk öğrendiğimde “neden bunu daha önce kimse anlatmadı?” diye düşünmüştüm. Linux’un en güçlü yanlarından biri olan stdin/stdout yönlendirmesi, arşiv işlemlerinde alışılagelmişin çok ötesinde bir esneklik sunuyor. Bu yazıda, dosyasız sıkıştırma yaklaşımını, bellek üzerinde veri akışını ve bunların gerçek prodüksiyon senaryolarında nasıl kullanıldığını ele alacağız.

Temel Kavram: Neden Dosyasız Arşivleme?

Klasik yaklaşımda şöyle bir senaryo düşünelim: 50 GB’lık bir log dizinini başka bir sunucuya taşımanız gerekiyor. Geleneksel yöntemle önce tar ile sıkıştırırsınız, geçici bir .tar.gz dosyası oluşur, sonra scp ile gönderirsiniz, karşı tarafta açarsınız. Bu süreçte hem kaynak hem hedef diskte en az 50 GB geçici alan kullanmış olursunuz.

Oysa stdin/stdout pipeline’ı kullandığınızda veri hiçbir zaman diske yazılmaz. Doğrudan bellekten akan veri, sıkıştırılır, ağa gönderilir ve karşı tarafta açılır. Disk üzerinde tek bir byte geçici alan tüketilmez.

Bu yaklaşımın avantajları:

  • Disk alanı tasarrufu: Geçici dosya oluşturulmaz, kaynak ve hedef disklerde ek alan gerekmez
  • Hız: I/O operasyonu azaldığı için genel işlem süresi düşer
  • Atomiklik: İşlem ya tamamen başarılı olur ya da hiç tamamlanmaz, yarım kalan dosya sorunu yaşanmaz
  • Esneklik: Pipeline’a istediğiniz kadar araç ekleyebilirsiniz

tar Komutunun stdin/stdout Moduna Geçişi

tar komutunun standart çıktıya yazması için - karakterini hedef dosya olarak kullanırız. Bu basit ama son derece güçlü bir konvansiyondur.

# Dizini stdout'a tar arşivi olarak yaz
tar cf - /var/log/nginx/

# Stdout'tan okunan arşivi aç
tar xf - -C /tmp/restore/

Buradaki - işareti “dosya yerine stdin/stdout kullan” anlamına gelir. c arşiv oluştur, f - ise hedef olarak standart çıktıyı kullan demektir.

Şimdi bu ikisini birleştirelim ve araya sıkıştırma ekleyelim:

# /var/log/nginx dizinini sıkıştırıp stdout'a yaz, gzip ile sıkıştır
tar cf - /var/log/nginx/ | gzip -9 > yedek.tar.gz

# Ya da doğrudan tar'ın z flag'i ile
tar czf - /var/log/nginx/ > yedek.tar.gz

İkinci örnekte z flag’i gzip sıkıştırmasını doğrudan tar içinde çalıştırır. Ancak biz pipeline yaklaşımını tercih edeceğiz çünkü bu bize sıkıştırma aşamasını daha ince kontrol etme imkanı tanır.

Uzak Sunucuya Dosyasız Kopyalama

İşte gerçek güç burada ortaya çıkıyor. SSH üzerinden uzak bir sunucuya, hiç geçici dosya oluşturmadan dizin kopyalayabilirsiniz:

# Yerel dizini uzak sunucuya sıkıştırarak gönder
tar czf - /var/www/html/ | ssh kullanici@hedef-sunucu "tar xzf - -C /var/www/html/"

# Daha performanslı bir yaklaşım: pigz ile paralel sıkıştırma
tar cf - /var/www/html/ | pigz -p 4 | ssh kullanici@hedef-sunucu "pigz -d | tar xf - -C /var/www/html/"

Bu komut çalıştığında:

  1. tar yerel dizini okur ve ham arşivi stdout’a yazar
  2. gzip bu veriyi stdin’den alıp sıkıştırır ve stdout’a yazar
  3. SSH bu sıkıştırılmış veriyi ağ üzerinden karşı tarafa aktarır
  4. Uzak taraftaki tar bu veriyi stdin’den alır ve açar

Tüm bu adımlar eş zamanlı yürür. Pipeline mantığı sayesinde ikinci adım birincinin bitmesini beklemez, veriler akar.

Disk alanı kritik olan durumlarda, örneğin bir container ortamında ya da küçük instance’larda bu yaklaşım hayat kurtarır. Ben bunu ilk kez bir production veritabanı migration’ında kullandığımda, 80 GB’lık veri için geçici disk alanım yoktu ve bu yöntem o gece beni kurtardı.

pv ile Veri Akışını İzlemek

Pipeline’ın ne hızla aktığını, ne kadar veri geçtiğini ve tahmini süreyi görmek isterseniz pv (pipe viewer) aracı paha biçilmezdir:

# pv ile ilerleme takibi
tar cf - /var/log/ | pv | gzip -9 | ssh kullanici@hedef "cat > /backup/log-yedek.tar.gz"

# Toplam boyut biliniyorsa daha detaylı çıktı
tar cf - /var/log/ | pv -s $(du -sb /var/log/ | awk '{print $1}') | gzip -9 > yedek.tar.gz

pv çıktısı şöyle görünür: 1.23GiB 0:02:15 [8.87MiB/s] [=> ] 45% Hem mevcut hız, hem geçen süre, hem de ilerleme çubuğu tek satırda.

Veritabanı Yedekleri ile Dosyasız Pipeline

Veritabanı yedekleme senaryolarında bu yaklaşım özellikle etkilidir. MySQL dump’ını sıkıştırıp uzak depoya göndermek:

# MySQL dump -> sıkıştırma -> uzak depolama
mysqldump -u root -p --all-databases | gzip -6 | ssh backup-server "cat > /backup/mysql-$(date +%Y%m%d).sql.gz"

# Daha gelişmiş: dump al, sıkıştır, şifrele, gönder
mysqldump -u root -p production_db | 
  gzip -9 | 
  openssl enc -aes-256-cbc -salt -pass pass:$SIFRE | 
  ssh backup@backup-server "cat > /backup/prod-db-$(date +%Y%m%d-%H%M).sql.gz.enc"

İkinci örnekte pipeline’a şifreleme de ekledik. Veri sırayla işleniyor: dump, sıkıştırma, şifreleme, uzak depolama. Ve hiçbir aşamada disk kullanılmıyor.

PostgreSQL için benzer yaklaşım:

# pg_dump stdout çıktısını direkt sıkıştır
pg_dump -Fc veritabani_adi | 
  pv -N "DB Dump" | 
  ssh backup-server "cat > /backup/pgdump-$(date +%Y%m%d).dump"

-Fc flag’i pg_dump‘ın custom format kullanmasını sağlar ve bu format zaten dahili sıkıştırma destekliyor. Ek gzip gerekmez.

stdin’den Arşiv Açmak: Pratik Senaryolar

Uzak bir kaynaktan doğrudan arşiv açmak için curl ya da wget çıktısını tar’a besleyebilirsiniz:

# Uzak tar.gz dosyasını indirmeden direkt aç
curl -sL https://example.com/release-v2.tar.gz | tar xzf - -C /opt/uygulama/

# wget ile benzer yaklaşım
wget -qO- https://releases.hashicorp.com/terraform/1.6.0/terraform_1.6.0_linux_amd64.zip | 
  funzip > /usr/local/bin/terraform && chmod +x /usr/local/bin/terraform

Bu yaklaşım özellikle deployment scriptlerinde yaygın kullanılır. İndirme ve açma işlemi eş zamanlı gerçekleşir, geçici dosya oluşturulmaz.

Ansible playbook’larında ya da cloud-init scriptlerinde sık kullandığım bir pattern:

# Tarball'ı belirli bir kullanıcı olarak aç
curl -sL https://example.com/app.tar.gz | 
  sudo -u appuser tar xzf - -C /home/appuser/app/ --strip-components=1

--strip-components=1 flag’i arşivdeki ilk dizin seviyesini atar, direkt içerikleri hedef dizine koyar. Bu özellikle GitHub release arşivlerinde çok işe yarar, genellikle proje-v1.0.0/ gibi bir üst dizin içerirler.

bzip2 ve xz ile Daha Yüksek Sıkıştırma Oranı

gzip hızlı ama sıkıştırma oranı orta düzeydedir. Daha iyi sıkıştırma için bzip2 veya xz kullanılabilir, pipeline mantığı aynı kalır:

# bzip2 ile sıkıştırarak uzak sunucuya gönder
tar cf - /home/kullanici/ | bzip2 -9 | ssh backup "cat > /backup/home.tar.bz2"

# xz ile en yüksek sıkıştırma (yavaş ama küçük çıktı)
tar cf - /opt/büyük-uygulama/ | xz -T0 -9 | ssh backup "cat > /backup/uygulama.tar.xz"

# Paralel xz: çok çekirdekli sistemlerde hız için
tar cf - /veri/ | xz -T0 | pv > /backup/veri.tar.xz

xz -T0 komutu mevcut tüm CPU çekirdeklerini kullanır. Büyük arşivlerde ciddi hız farkı yaratır.

Sıkıştırma araçlarının genel karakteristikleri:

  • gzip: Hızlı, orta sıkıştırma, her yerde mevcut, ağ transferinde iyi denge
  • bzip2: gzip’ten yavaş, biraz daha iyi sıkıştırma, büyük dosyalarda avantajlı
  • xz: En yüksek sıkıştırma, en yavaş, disk alanı kritikse tercih edilir
  • lz4: Çok hızlı, düşük sıkıştırma, gerçek zamanlı streaming için ideal
  • zstd: Modern, hız ve sıkıştırma dengesi mükemmel, giderek yaygınlaşıyor

zstd ile Modern Yaklaşım

Facebook’un geliştirdiği zstd (Zstandard), son yıllarda ciddi popülarite kazandı. Hem sıkıştırma oranı hem hız açısından gzip’i geride bırakıyor:

# zstd ile sıkıştırma
tar cf - /veri/kritik/ | zstd -T0 -15 | ssh backup "zstd -d | tar xf - -C /restore/"

# Çok yüksek hız, makul sıkıştırma
tar cf - /var/log/ | zstd -T0 --fast=1 > /tmp/log-hizli.tar.zst

# pv ile takip ederek uzak aktarım
tar cf - /opt/ | pv -N kaynak | zstd -T0 -10 | pv -N sikilm | 
  ssh hedef "zstd -d | tar xf - -C /opt/"

Bu örnekte pv‘yi iki kere kullandık: bir kez ham veri hızını, bir kez de sıkıştırılmış veri hızını görmek için. Sıkıştırma oranını gerçek zamanlı hesaplayabilirsiniz.

/dev/stdin ve Process Substitution

Bazı araçlar dosya adı bekler ve stdin kabul etmez. Bu durumda bash’in process substitution özelliği devreye girer:

# diff ile iki uzak dosyayı karşılaştır (indirmeden)
diff <(ssh sunucu1 "cat /etc/nginx/nginx.conf") 
     <(ssh sunucu2 "cat /etc/nginx/nginx.conf")

# İki farklı sunucudan tar arşivlerinin içeriğini karşılaştır
diff <(ssh sunucu1 "tar tzf /backup/gunluk.tar.gz" | sort) 
     <(ssh sunucu2 "tar tzf /backup/gunluk.tar.gz" | sort)

<(komut) sözdizimi bash’te bir named pipe oluşturur ve komutu dosyaymış gibi sunabilmek için /dev/fd/ altında geçici bir referans yaratır. Fiziksel dosya oluşturulmaz.

Benzer şekilde tee komutu ile bir pipeline’ı birden fazla hedefe yönlendirebilirsiniz:

# Aynı veriyi hem yerel diske hem uzak sunucuya gönder
tar czf - /kritik-veri/ | tee /backup/yerel.tar.gz | 
  ssh offsite-backup "cat > /offsite/uzak.tar.gz"

# Ya da iki farklı sıkıştırma formatında sakla
tar cf - /veri/ | tee >(gzip -9 > /backup/veri.tar.gz) | bzip2 -9 > /backup/veri.tar.bz2

Pratik Senaryo: Canlı Sistem Klonlama

Bir sunucunun tüm root filesystem’ini çalışır durumdayken klonlamak gerçek bir senaryo. Tabii bu mükemmel bir yöntem değil (bazı dosyalar değişecektir) ama çoğu zaman yeterince iyi çalışır:

# Root filesystem'i uzak sunucuya klonla (dikkatli kullanın!)
tar cf - 
  --exclude=/proc 
  --exclude=/sys 
  --exclude=/dev 
  --exclude=/run 
  --exclude=/tmp 
  --exclude=/mnt 
  --one-file-system 
  / | 
  pv -s $(df --output=used -B1 / | tail -1) | 
  ssh hedef-sunucu "tar xf - -C /mnt/yeni-disk/"

--one-file-system flag’i kritiktir: tar’ın mount point sınırlarını aşmamasını sağlar, aksi halde /proc ve /sys gibi sanal dosya sistemleri de dahil edilir.

Arşiv İçeriğini Bellek Üzerinde İşlemek

Bir arşiv içindeki belirli dosyaları açmadan okumak ya da işlemek için:

# Arşiv içindeki tek bir dosyayı diske yazmadan oku
tar xzf arsiv.tar.gz --to-stdout config/uygulama.conf | grep "database"

# Uzak arşivdeki dosyayı indirmeden içinde ara
ssh uzak-sunucu "cat /backup/arsiv.tar.gz" | 
  tar xzf - --to-stdout logs/error.log | 
  grep -i "CRITICAL" | 
  tail -50

--to-stdout (ya da kısa hali -O) flag’i tar’ın çıkardığı dosyayı diske yazmak yerine stdout’a yazmasını sağlar. Büyük arşivlerdeki küçük dosyalara hızlıca erişmek için mükemmel.

Netcat ile Ağ Üzerinde Ham Aktarım

SSH overhead’i olmadan, yerel ağda maksimum hızda veri aktarmak için netcat kullanabilirsiniz:

# Hedef sunucuda önce dinlemeye başla
nc -l 9999 | tar xzf - -C /hedef/dizin/

# Kaynak sunucuda gönder
tar czf - /kaynak/dizin/ | nc hedef-sunucu-ip 9999

Bu yöntemde şifreleme yoktur, sadece güvenli iç ağlarda kullanın. Bant genişliği SSH şifrelemesi olmadığı için çok daha verimli kullanılır, özellikle 10 GbE ağlarda fark belirgindir.

Hata Yönetimi: Pipeline’da Exit Code Takibi

Pipeline’larda bir sorun var: varsayılan olarak bash, pipeline’ın yalnızca son komutunun exit code’unu döndürür. Ara komutlarda hata olsa bile fark etmezsiniz:

# Yanlış yaklaşım: tar hata verse bile script devam eder
tar czf - /veri/ | ssh backup "cat > /backup/yedek.tar.gz"
echo "Durum: $?"  # Bu sadece ssh'ın çıkış kodunu gösterir

# Doğru yaklaşım: pipefail ile tüm pipeline takip edilir
set -o pipefail

tar czf - /veri/ | ssh backup "cat > /backup/yedek.tar.gz"
if [ $? -ne 0 ]; then
  echo "HATA: Yedekleme başarısız!" >&2
  exit 1
fi

# Ya da PIPESTATUS dizisi ile her komutun durumunu kontrol et
tar czf - /veri/ | gzip -9 | ssh backup "cat > /backup/yedek.tar.gz"
echo "tar: ${PIPESTATUS[0]}, gzip: ${PIPESTATUS[1]}, ssh: ${PIPESTATUS[2]}"

Production yedekleme scriptlerinde set -o pipefail neredeyse zorunludur. Bu olmadan sessiz hatalar yaşanabilir ve yedek olduğunu sandığınız dosya aslında bozuk ya da eksik olabilir.

Sonuç

stdin/stdout üzerinden arşivleme ve sıkıştırma, Linux sistem yönetiminin en zarif çözümlerinden birini oluşturuyor. Dosyasız yaklaşım sadece disk alanı tasarrufu sağlamıyor; aynı zamanda daha hızlı, daha güvenilir ve daha esnek bir operasyon modeli sunuyor.

Özellikle şu senaryolarda bu yöntemi aktif olarak kullanmanızı öneririm: büyük veri setlerinin sunucular arası transferi, disk alanının kritik olduğu container ortamları, veritabanı yedeklemelerini şifreleyerek offsite depolama ve deployment pipeline’larında paket kurulumu.

pv, tee, pipefail ve process substitution gibi araçları ve teknikleri bu iş akışına entegre ettiğinizde, karmaşık veri akışlarını tek satır komutlarla yönetebilir hale geliyorsunuz. Bu da hem operasyonel verimliliği artırıyor hem de scriptlerin okunabilirliğini ve bakımını kolaylaştırıyor.

Kendi yedekleme rutinlerinizi gözden geçirin: kaç tane gereksiz geçici dosya yaratıyorsunuz, kaç GB disk alanı savurganlıkla kullanıyorsunuz? Çoğu durumda cevap sizi şaşırtacak.

Bir yanıt yazın

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