/proc Dosya Sisteminden Sistem Bilgilerini Kaydetme ve Analiz Etme
Sistem yöneticiliğinde en çok ihmal edilen konulardan biri, çalışan bir sistemin anlık durumunu kayıt altına almaktır. Bir şeyler ters gittiğinde “keşke o anki durumu kaydetmiş olsaydım” diye düşünmüşsünüzdür mutlaka. /proc dosya sistemi, Linux çekirdeğinin size sunduğu canlı bir penceredir ve bu pencereyi doğru kullanmayı öğrendiğinizde, sorun giderme süreçleriniz tamamen değişir.
/proc Dosya Sistemi Nedir, Neden Bu Kadar Önemlidir
/proc aslında diskte fiziksel olarak var olmayan, sanal bir dosya sistemidir. Çekirdek, bu dizin altındaki dosyaları sizin için anlık olarak üretir. cat /proc/meminfo çalıştırdığınızda, bir diskten okuma yapmıyorsunuz; çekirdek o anda bellek durumunu size metin formatında sunuyor.
Bu yapının güzelliği şuradan geliyor: Normal araçlarla (top, free, ps gibi) göremeyeceğiniz düşük seviyeli bilgilere doğrudan erişebilirsiniz. Üstelik bu bilgileri kolayca dosyaya yazabilir, karşılaştırabilir ve arşivleyebilirsiniz.
Bir production sisteminde ciddi bir performans sorunu yaşadığınızı düşünün. Ekip üyeleri monitörün başında beklerken siz /proc altından sistematik veri topluyorsunuz. Bu verileri ilerleyen günlerde analiz etmek, size hem sorunun kökenini bulmayı hem de benzer durumları önceden tespit etmeyi sağlıyor.
Temel /proc Dosyalarını Tanımak
Sistemi yedeklemeye başlamadan önce hangi dosyaların ne anlama geldiğini bilmek gerekiyor.
CPU Bilgileri:
cat /proc/cpuinfo
Her işlemci çekirdeği için ayrı bir blok çıktı verir. processor, model name, cpu MHz, cache size, flags gibi alanlar içerir. CPU flags özellikle sanallaştırma ve güvenlik özellikleri (AES-NI, VMX, SME gibi) için kritiktir.
Bellek Durumu:
cat /proc/meminfo
MemTotal, MemFree, MemAvailable, Buffers, Cached, SwapTotal, SwapFree satırları en çok kullandığım kısımlar. MemAvailable değerinin MemFree‘den farklı olduğunu ve gerçek kullanılabilir belleği daha doğru gösterdiğini unutmayın.
Çalışan Süreçler:
Her sürecin /proc/[PID]/ altında kendi dizini var. Bu dizin içinde:
/proc/[PID]/status: Sürecin özet durumu/proc/[PID]/cmdline: Sürecin nasıl başlatıldığı/proc/[PID]/fd/: Açık dosya tanımlayıcıları/proc/[PID]/maps: Bellek haritası/proc/[PID]/net/tcp: TCP bağlantıları/proc/[PID]/limits: Kaynak sınırları
Ağ İstatistikleri:
cat /proc/net/dev
cat /proc/net/sockstat
cat /proc/net/tcp
Sistematik Snapshot Alma
Şimdi işin pratik kısmına geçelim. Bir sistem snapshot’ı almak için kullandığım temel script yapısı şu şekilde:
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
SNAPSHOT_DIR="/var/log/system-snapshots/${TIMESTAMP}"
mkdir -p "${SNAPSHOT_DIR}"
echo "[+] Snapshot başlatılıyor: ${TIMESTAMP}"
# CPU bilgileri
cp /proc/cpuinfo "${SNAPSHOT_DIR}/cpuinfo.txt"
cp /proc/loadavg "${SNAPSHOT_DIR}/loadavg.txt"
cp /proc/stat "${SNAPSHOT_DIR}/stat.txt"
# Bellek
cp /proc/meminfo "${SNAPSHOT_DIR}/meminfo.txt"
cp /proc/slabinfo "${SNAPSHOT_DIR}/slabinfo.txt" 2>/dev/null
cp /proc/vmstat "${SNAPSHOT_DIR}/vmstat.txt"
cp /proc/buddyinfo "${SNAPSHOT_DIR}/buddyinfo.txt"
# Ağ
cp /proc/net/dev "${SNAPSHOT_DIR}/net_dev.txt"
cp /proc/net/sockstat "${SNAPSHOT_DIR}/sockstat.txt"
cp /proc/net/tcp "${SNAPSHOT_DIR}/net_tcp.txt"
cp /proc/net/udp "${SNAPSHOT_DIR}/net_udp.txt"
cp /proc/net/if_inet6 "${SNAPSHOT_DIR}/net_ipv6.txt" 2>/dev/null
# Disk I/O
cp /proc/diskstats "${SNAPSHOT_DIR}/diskstats.txt"
cp /proc/mounts "${SNAPSHOT_DIR}/mounts.txt"
cp /proc/swaps "${SNAPSHOT_DIR}/swaps.txt"
# Sistem bilgileri
cp /proc/version "${SNAPSHOT_DIR}/version.txt"
cp /proc/cmdline "${SNAPSHOT_DIR}/kernel_cmdline.txt"
cp /proc/uptime "${SNAPSHOT_DIR}/uptime.txt"
cp /proc/sys/kernel/hostname "${SNAPSHOT_DIR}/hostname.txt"
# Süreç listesi snapshot'ı
ls /proc | grep '^[0-9]' | while read pid; do
if [ -d "/proc/${pid}" ]; then
proc_dir="${SNAPSHOT_DIR}/processes/${pid}"
mkdir -p "${proc_dir}"
for f in status cmdline io limits; do
[ -f "/proc/${pid}/${f}" ] &&
cat "/proc/${pid}/${f}" 2>/dev/null > "${proc_dir}/${f}.txt"
done
fi
done
# Sıkıştır
tar -czf "/var/log/system-snapshots/${TIMESTAMP}.tar.gz"
-C "/var/log/system-snapshots" "${TIMESTAMP}"
&& rm -rf "${SNAPSHOT_DIR}"
echo "[+] Snapshot tamamlandı: ${TIMESTAMP}.tar.gz"
Bu scripti cron’a eklediğinizde düzenli aralıklarla sistem durumunu kayıt altına alırsınız:
# Her saat başı snapshot al
0 * * * * /usr/local/bin/proc-snapshot.sh >> /var/log/proc-snapshot.log 2>&1
Kritik Anlarda Hızlı Analiz
Bir sistem yavaşladığında veya bir şeyler ters gittiğinde ilk yapmanız gereken şey mevcut durumu kaydetmek, sonra analiz etmektir. Hızlı bir triage için:
#!/bin/bash
# Hızlı durum tespiti - sorun anında çalıştırılır
echo "=== $(date) ==="
echo "--- LOAD AVERAGE ---"
cat /proc/loadavg
echo "--- MEMORY ---"
awk '/MemTotal|MemAvailable|SwapTotal|SwapFree/ {printf "%-20s %d MBn", $1, $2/1024}' /proc/meminfo
echo "--- TOP 10 PROCESS (RSS) ---"
for pid in $(ls /proc | grep '^[0-9]'); do
if [ -f "/proc/${pid}/status" ]; then
rss=$(awk '/VmRSS/ {print $2}' /proc/${pid}/status 2>/dev/null)
name=$(awk '/^Name:/ {print $2}' /proc/${pid}/status 2>/dev/null)
[ -n "$rss" ] && echo "$rss $name $pid"
fi
done | sort -rn | head -10 | awk '{printf "PID: %-8s %-20s %d MBn", $3, $2, $1/1024}'
echo "--- TCP CONNECTIONS ---"
awk 'NR>1 {split($3,a,":");
printf "Local: %d.%d.%d.%d:%dn",
strtonum("0x"substr(a[1],7,2)),
strtonum("0x"substr(a[1],5,2)),
strtonum("0x"substr(a[1],3,2)),
strtonum("0x"substr(a[1],1,2)),
strtonum("0x"a[2])}' /proc/net/tcp | head -20
echo "--- DISK I/O (son 1 sn) ---"
cat /proc/diskstats | awk '{if ($3 ~ /^(sd|nvme|vd)/ && $3 !~ /[0-9]$/)
print $3, "reads:", $4, "writes:", $8}'
Snapshot’ları Karşılaştırarak Sorun Tespiti
İki snapshot arasındaki farkı bulmak, zamanla ne değiştiğini görmek için son derece değerlidir. Örneğin hafta boyunca toplanan memory snapshot’larını karşılaştırmak:
#!/bin/bash
# İki bellek snapshot'ını karşılaştır
SNAP1=$1
SNAP2=$2
if [ -z "$SNAP1" ] || [ -z "$SNAP2" ]; then
echo "Kullanim: $0 <snapshot1.tar.gz> <snapshot2.tar.gz>"
exit 1
fi
TMP1=$(mktemp -d)
TMP2=$(mktemp -d)
tar -xzf "$SNAP1" -C "$TMP1" --wildcards "*/meminfo.txt" 2>/dev/null
tar -xzf "$SNAP2" -C "$TMP2" --wildcards "*/meminfo.txt" 2>/dev/null
MEM1=$(find "$TMP1" -name "meminfo.txt" | head -1)
MEM2=$(find "$TMP2" -name "meminfo.txt" | head -1)
echo "=== BELLEK KARSILASTIRMASI ==="
echo "Snapshot 1: $(basename $SNAP1)"
echo "Snapshot 2: $(basename $SNAP2)"
echo ""
for metric in MemTotal MemAvailable MemFree Buffers Cached SwapFree; do
val1=$(awk -v m="$metric:" '$1==m {print $2}' "$MEM1")
val2=$(awk -v m="$metric:" '$1==m {print $2}' "$MEM2")
diff=$((val2 - val1))
sign=""
[ $diff -gt 0 ] && sign="+"
printf "%-20s %8d KB -> %8d KB (%s%d KB)n"
"$metric" "$val1" "$val2" "$sign" "$diff"
done
rm -rf "$TMP1" "$TMP2"
Bu scripti çalıştırdığınızda şuna benzer bir çıktı görürsünüz:
=== BELLEK KARSILASTIRMASI ===
Snapshot 1: 20240915_080000.tar.gz
Snapshot 2: 20240915_200000.tar.gz
MemTotal 16384000 KB -> 16384000 KB (+0 KB)
MemAvailable 8234560 KB -> 3102144 KB (-5132416 KB)
SwapFree 2097148 KB -> 524288 KB (-1572860 KB)
Bu çıktı size açıkça 12 saatte 5GB belleğin tükendiğini ve swap kullanımının ciddi ölçüde arttığını gösteriyor. Memory leak araştırması için mükemmel bir başlangıç noktası.
/proc/[PID] Derinlemesine Analiz
Belirli bir sürecin davranışını izlemek gerektiğinde süreç dizini altındaki dosyalar altın değerindedir.
#!/bin/bash
# Belirli bir süreci detaylı analiz et
PID=$1
[ -z "$PID" ] && { echo "PID gerekli"; exit 1; }
[ ! -d "/proc/$PID" ] && { echo "Süreç bulunamadı: $PID"; exit 1; }
echo "=== SÜREÇ ANALİZİ: PID $PID ==="
echo "--- Komut ---"
tr '' ' ' < /proc/$PID/cmdline; echo
echo "--- Durum ---"
cat /proc/$PID/status
echo "--- Kaynak Limitleri ---"
cat /proc/$PID/limits
echo "--- I/O İstatistikleri ---"
cat /proc/$PID/io 2>/dev/null || echo "I/O bilgisi erişilemez (root gerekebilir)"
echo "--- Açık Dosya Sayısı ---"
ls /proc/$PID/fd 2>/dev/null | wc -l
echo "--- Bellek Haritası Özeti ---"
awk '{print $6}' /proc/$PID/maps 2>/dev/null |
grep -v '^$' | sort | uniq -c | sort -rn | head -15
echo "--- Ağ Soketleri ---"
ls -la /proc/$PID/fd 2>/dev/null | grep socket | wc -l
echo "adet socket açık"
Kernel Parametrelerini Kaydetme ve Geri Yükleme
/proc/sys altındaki parametreler çalışan sistemi etkiler ve bazı durumlarda hangisinin değiştirildiğini bilmek kritik önem taşır.
#!/bin/bash
# Tüm sysctl değerlerini kaydet
OUTPUT_FILE="/var/backup/sysctl-$(date +%Y%m%d_%H%M%S).conf"
echo "# Sistem: $(cat /proc/sys/kernel/hostname)" > "$OUTPUT_FILE"
echo "# Tarih: $(date)" >> "$OUTPUT_FILE"
echo "# Kernel: $(cat /proc/version | cut -d' ' -f1-3)" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
# /proc/sys altındaki tüm okunabilir parametreleri kaydet
find /proc/sys -type f -readable 2>/dev/null | while read param; do
key=$(echo "$param" | sed 's|/proc/sys/||;s|/|.|g')
value=$(cat "$param" 2>/dev/null | tr 'n' ' ' | sed 's/ $//')
# Sadece tek satır, makul uzunluktaki değerleri al
if [ ${#value} -lt 256 ] && [ -n "$value" ]; then
echo "${key} = ${value}"
fi
done >> "$OUTPUT_FILE"
echo "Sysctl snapshot kaydedildi: $OUTPUT_FILE"
echo "Toplam parametre: $(grep -c '=' "$OUTPUT_FILE")"
# İki snapshot arasındaki farkı bulmak için:
# diff sysctl-onceki.conf sysctl-sonraki.conf | grep '^[<>]'
Gerçek Dünya Senaryosu: Memory Leak Takibi
Bir web sunucusunda uygulama hafıza tüketiminin neden arttığını bulmaya çalıştığımı hatırlıyorum. Java tabanlı bir uygulama vardı ve her gece yeniden başlatılmasına rağmen başlatmadan birkaç saat sonra bellek tükeniyordu. Şu scripti kullanarak 30 dakikalık aralıklarla veri topladım:
#!/bin/bash
# Memory leak takip scripti - belirli bir PID için
TARGET_PID=$1
LOG_FILE="/var/log/memleak-${TARGET_PID}-$(date +%Y%m%d).log"
[ -z "$TARGET_PID" ] && { echo "PID gerekli"; exit 1; }
echo "Takip başlatılıyor: PID $TARGET_PID" | tee "$LOG_FILE"
echo "Log: $LOG_FILE"
while [ -d "/proc/$TARGET_PID" ]; do
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# VmRSS: Fiziksel RAM kullanımı
# VmVSZ: Sanal bellek
# VmSwap: Swap kullanımı
RSS=$(awk '/VmRSS/ {print $2}' /proc/$TARGET_PID/status 2>/dev/null)
VSZ=$(awk '/VmSize/ {print $2}' /proc/$TARGET_PID/status 2>/dev/null)
SWAP=$(awk '/VmSwap/ {print $2}' /proc/$TARGET_PID/status 2>/dev/null)
THREADS=$(awk '/Threads/ {print $2}' /proc/$TARGET_PID/status 2>/dev/null)
FD_COUNT=$(ls /proc/$TARGET_PID/fd 2>/dev/null | wc -l)
echo "$TIMESTAMP RSS=${RSS}KB VSZ=${VSZ}KB SWAP=${SWAP}KB THREADS=$THREADS FD=$FD_COUNT"
| tee -a "$LOG_FILE"
sleep 1800 # 30 dakika
done
echo "Süreç sonlandı veya PID değişti."
Bu veriyi topladıktan sonra basit bir awk komutuyla trendi görebilirsiniz:
# RSS değişim trendini göster
awk '{for(i=1;i<=NF;i++) if($i~/RSS=/) {split($i,a,"="); print $1, $2, a[2]+0}}'
/var/log/memleak-*.log |
awk 'NR==1{prev=$3} {diff=$3-prev; printf "%s %s RSS:%d KB Artis:%+d KBn", $1,$2,$3,diff; prev=$3}'
Bu analizin sonucunda hangi thread’lerin ve hangi dosya tanımlayıcıların biriktiğini gördük. Sorun, uygulama konfigürasyonunda bir connection pool leak’iydi ve /proc verileri olmadan bunu tespit etmek çok daha uzun sürerdi.
Snapshot Arşivi Yönetimi
Snapshot’lar hızlı birikir ve disk alanını tüketir. Arşiv yönetimi için basit bir temizlik scripti:
#!/bin/bash
# Eski snapshot'ları temizle, önemli olanları arşivle
SNAPSHOT_BASE="/var/log/system-snapshots"
ARCHIVE_BASE="/var/archive/system-snapshots"
KEEP_DAYS=7
ARCHIVE_DAYS=30
mkdir -p "$ARCHIVE_BASE"
# 7 günden eski snapshot'ları arşive taşı
find "$SNAPSHOT_BASE" -name "*.tar.gz" -mtime +${KEEP_DAYS} | while read snap; do
fname=$(basename "$snap")
echo "Arşive taşınıyor: $fname"
mv "$snap" "${ARCHIVE_BASE}/${fname}"
done
# 30 günden eski arşivleri sil
find "$ARCHIVE_BASE" -name "*.tar.gz" -mtime +${ARCHIVE_DAYS} -exec rm -f {} ;
echo "Mevcut snapshot'lar:"
ls -lh "$SNAPSHOT_BASE"/*.tar.gz 2>/dev/null | tail -10
echo "Arşiv boyutu: $(du -sh "$ARCHIVE_BASE" | cut -f1)"
Analiz İçin Veriyi Anlamlı Hale Getirmek
Ham /proc verisi bazen okunması güç formatlar içerir. Özellikle /proc/net/tcp dosyası hex formatında IP adresleri ve portlar içerir. Bunu insanın okuyabileceği formata çevirmek için:
#!/bin/bash
# /proc/net/tcp dosyasını okunabilir formata çevir
# Bir snapshot arşivinden veya canlı sistemden çalışır
parse_tcp() {
local input=$1
echo "Proto Local Address Foreign Address State"
awk 'NR>1 {
split($2, local, ":");
split($3, remote, ":");
# Little-endian hex IP çözümle
lport = strtonum("0x" local[2]);
rport = strtonum("0x" remote[2]);
# Durum kodları
states[1]="ESTABLISHED"; states[2]="SYN_SENT";
states[3]="SYN_RECV"; states[4]="FIN_WAIT1";
states[5]="FIN_WAIT2"; states[6]="TIME_WAIT";
states[7]="CLOSE"; states[8]="CLOSE_WAIT";
states[9]="LAST_ACK"; states[10]="LISTEN";
states[11]="CLOSING";
state_num = strtonum("0x" $4);
state = states[state_num];
printf "tcp %-25s %-25s %sn",
"...:" lport,
"...:" rport,
state
}' "$input"
}
if [ -n "$1" ]; then
parse_tcp "$1"
else
parse_tcp /proc/net/tcp
fi
Sonuç
/proc dosya sistemi, Linux sistem yöneticiliğinin belki de en az takdir edilen araçlarından biridir. Üçüncü parti araçlar kurmanıza gerek kalmadan, sadece cat, awk ve bash ile production sistemlerin derinliklerinde neler olduğunu görebilirsiniz.
Burada anlattığım yaklaşımların özü şu: Önce kaydet, sonra analiz et. Bir şeyler ters gittiği anda zaten vaktiniz olmayacak. Periyodik snapshot alma alışkanlığı edinin, bu snapshot’ları anlamlı bir dizin yapısında saklayın ve sorun çıktığında elinizde zaman serisi veriniz olsun.
Paylaştığım scriptler başlangıç noktası. Kendi ortamınıza göre özelleştirin; hangi uygulamalar kritik, hangi metriklere odaklanmanız gerekiyor, retention politikanız ne olmalı gibi soruları cevaplayarak büyütün. Bir SSD’nin dolmasına izin vermeden snapshot rotasyonunu da ihmal etmeyin.
Son bir not: Bu scriptleri production’a almadan önce test ortamında deneyin. Özellikle tüm PID dizinlerini tarayan script’ler yüksek süreç sayılı sistemlerde beklenmedik yük yaratabilir. Sampling aralıklarını ve tarama derinliğini ortamınıza göre ayarlayın.
