Linux’ta Dosya Kilitleme Sorunlarını Tespit Etme ve Çözme

Bir production sunucusunda ani bir yavaşlama yaşandığını düşünün. Uygulamanız log dosyasına yazamıyor, veritabanı yedekleme scripti takılı kalmış, bir kullanıcı dosyayı silemeyor ama neden bilmiyor. Bu senaryoların hepsinin arkasında genellikle tek bir suçlu vardır: dosya kilitleme sorunları. Linux’ta dosya kilitleri çoğu zaman sessiz sedasız iş yapar, ama bir şeyler yanlış gittiğinde sistemi felç edebilir. Bu yazıda dosya kilitlerini nasıl tespit edeceğinizi, hangi araçların işinize yarayacağını ve gerçek dünya senaryolarında nasıl çözüm üreteceğinizi adım adım ele alacağız.

Dosya Kilitleme Nedir ve Neden Önemlidir?

Linux’ta dosya kilitleme, birden fazla prosesin aynı anda aynı dosyaya erişmesini düzenlemek için kullanılan bir mekanizmadır. Advisory lock ve mandatory lock olmak üzere iki temel türü vardır. Advisory lock’lar en yaygın olanıdır; prosesler birbirine saygı göstererek kilidi kontrol eder. Mandatory lock’lar ise çekirdek seviyesinde zorlanır, ancak Linux’ta bu tür kilitler pratikte çok nadir kullanılır.

Bir dosya kilitlendiğinde şu durumlar ortaya çıkabilir:

  • Başka bir proses dosyayı açmaya ya da değiştirmeye çalışırken askıda kalabilir
  • Bir script beklenmedik şekilde donabilir
  • Uygulama hata logları “Resource temporarily unavailable” veya “file is locked” gibi mesajlar verebilir
  • Disk I/O anormal yükselip sistemi yavaşlatabilir

Sorunun kaynağını bulmak için elimizde güçlü araçlar var. Şimdi bunları tek tek inceleyelim.

lsof: Açık Dosyaları Listelemek İçin Temel Araç

lsof (list open files) komutu, bir sysadmin’in en sık başvurduğu araçlardan biridir. Linux’ta “her şey bir dosyadır” felsefesi göz önünde bulundurulduğunda, lsof aslında açık olan soketleri, pipe’ları, device’ları ve evet, kilitli dosyaları da listeler.

Belirli Bir Dosyayı Hangi Proses Kullanıyor?

lsof /var/log/nginx/access.log

Bu komut çıktısı şuna benzer bir şey gösterir:

COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx    1234     root    5w   REG    8,1  1048576  9876 /var/log/nginx/access.log
nginx    1235   nobody    5w   REG    8,1  1048576  9876 /var/log/nginx/access.log

Buradaki FD sütunu özellikle önemlidir:

  • r: Okuma için açık
  • w: Yazma için açık
  • u: Hem okuma hem yazma için açık
  • lr: Read lock uygulanmış
  • lw: Write lock uygulanmış

Belirli Bir Dizindeki Tüm Açık Dosyalar

Bir dizinin tamamında hangi dosyaların kullanıldığını görmek istiyorsanız:

lsof +D /var/www/html

Bu komut özellikle “dizini silemiyorum ama neden bilmiyorum” durumlarında hayat kurtarır. +D parametresi alt dizinleri de recursive olarak tarar.

Silinmiş Ama Hala Açık Dosyaları Bulmak

Bu senaryo çok klasiktir: Bir log dosyasını sildинiz ama disk dolmaya devam ediyor. Çünkü dosya silinmiş görünse de bir proses onu hala açık tutuyor.

lsof | grep deleted

Ya da daha spesifik olarak:

lsof | grep '(deleted)'

Eğer büyük boyutlu silinmiş dosyaları bulmak istiyorsanız:

lsof | grep deleted | awk '{print $7, $1, $2}' | sort -rn | head -20

Bu komut, boyutlarına göre sıralanmış şekilde silinmiş ama hala açık tutulan dosyaları listeler. Disk dolma krizlerinde bu komut gerçekten can kurtarır.

fuser: Dosyayı Kim Kullanıyor?

fuser komutu, lsof‘a kıyasla daha az bilinir ama çok daha hızlı ve öz bir çıktı sunar. Özellikle “bu dosyayı kullanan prosesleri öldür” gibi acil senaryolarda tercih edilir.

fuser /var/lock/app.lock

Çıktı sadece PID numaralarını gösterir:

/var/lock/app.lock: 2341

Daha ayrıntılı bilgi için -v parametresi kullanın:

fuser -v /var/lock/app.lock
                     USER        PID ACCESS COMMAND
/var/lock/app.lock:  root       2341 F....  myapp

ACCESS sütunundaki harflerin anlamları:

  • c: Mevcut dizin (current directory)
  • e: Çalıştırılabilir dosya (executable)
  • f: Açık dosya (open file)
  • F: Yazma için açık dosya (open file for writing)
  • r: Root dizin
  • m: mmap ile eşlenmiş dosya veya shared library

fuser ile Prosesi Doğrudan Sonlandırmak

Bir dosyayı kullanan tüm prosesleri tek komutla sonlandırmak için:

fuser -k /var/lock/myapp.lock

Bu komut SIGKILL sinyali gönderir. Daha nazik bir yaklaşım için önce SIGTERM deneyin:

fuser -k -TERM /var/lock/myapp.lock

Dikkat: Production ortamında fuser -k kullanmadan önce hangi prosesi öldüreceğinizden emin olun. Yanlış prosesi öldürmek daha büyük sorunlara yol açabilir.

/proc Dosya Sistemi ile Manuel İnceleme

Bazen araçlar kurulu olmayabilir ya da daha düşük seviyeli bir inceleme yapmak isteyebilirsiniz. /proc dosya sistemi bu noktada devreye girer.

Belirli bir prosesin açık dosyalarını görmek için:

ls -la /proc/2341/fd/

Bu komut, PID 2341’in açık tuttuğu tüm dosya tanımlayıcılarını sembolik link olarak gösterir. Hangi fiziksel dosyalara işaret ettiklerini görmek için:

ls -la /proc/2341/fd/ | grep -v "^total"

Bir prosesin dosya kilidi durumunu kontrol etmek için:

cat /proc/locks

Bu dosya oldukça bilgi yoğun bir çıktı verir:

1: POSIX  ADVISORY  WRITE 2341 08:01:9876 0 EOF
2: POSIX  ADVISORY  READ  1234 08:01:5432 0 EOF

Buradaki alanları okuma rehberi:

  • POSIX / FLOCK: Kilit türü
  • ADVISORY / MANDATORY: Kilit modu
  • READ / WRITE: Kilit erişim türü
  • 2341: Kilidi tutan prosesin PID’i
  • 08:01:9876: Cihaz major:minor ve inode numarası

Bu inode numarasından dosyayı bulmak için:

find / -inum 9876 2>/dev/null

Gerçek Dünya Senaryosu 1: Veritabanı Yedekleme Scripti Askıda

Diyelim ki her gece çalışan MySQL yedekleme scriptiniz sabah 3’te başlaması gerekirken hala çalışıyor. Sabah işe geldiğinizde sisteminizin yavaş olduğunu fark ediyorsunuz.

Önce durumu tespit edelim:

# Mysqldump ile ilgili tüm açık dosyaları bul
lsof -c mysqldump

# Ya da daha spesifik olarak mysqldump prosesini bul
ps aux | grep mysqldump
# PID: 4521 diyelim

# Bu prosesin açık dosya tanımlayıcılarını say
ls /proc/4521/fd | wc -l

# Hangi dosyaları açık tuttuğunu gör
lsof -p 4521

Eğer mysqldump bir dosyayı kilitlemişse ve başka bir proses bekliyorsa, bekleme durumunu şöyle görebilirsiniz:

# D durumundaki (uninterruptible sleep) prosesleri bul
ps aux | awk '$8 == "D" {print}'

D durumundaki prosesler genellikle I/O bekliyordur ve bu durum kilit bekleme senaryolarında sıkça görülür.

Gerçek Dünya Senaryosu 2: NFS Üzerinde Kilitlenme

NFS mount’larında dosya kilitleme sorunları çok daha karmaşık bir hal alır. NFS lock daemon’u olan lockd devreye girer ve ağ üzerinden kilit yönetimi yapılır.

# NFS kilit durumunu kontrol et
cat /proc/locks | grep -i nfs

# NFS ile ilgili servislerin durumunu kontrol et
systemctl status nfs-server
systemctl status rpc-statd
systemctl status rpcbind

# NFS mount'larını listele
mount | grep nfs

# NFS üzerindeki açık dosyaları göster
lsof | grep nfs

NFS kilitlenme sorunlarında çoğu zaman rpc.statd daemon’unun yeniden başlatılması çözüm olur:

systemctl restart rpc-statd

Eğer sorun devam ediyorsa mount’u zorla yeniden bağlayın:

umount -f -l /mnt/nfs_share
mount /mnt/nfs_share

inotifywait ile Dosya Erişimini Gerçek Zamanlı İzlemek

Sorun anlık olarak tekrarlıyorsa ve tam olarak hangi prosesin ne zaman dosyaya eriştiğini görmek istiyorsanız, inotifywait mükemmel bir araçtır.

# inotify-tools paketini kur (Debian/Ubuntu)
apt-get install inotify-tools

# Belirli bir dosyayı izle
inotifywait -m /var/lock/app.lock

# Belirli olayları filtrele
inotifywait -m -e open,close,modify,lock /var/log/myapp.log

Bir dizini recursive olarak izlemek için:

inotifywait -m -r /var/www/html 2>&1 | tee /tmp/file_access.log

Bu komut çalışırken başka bir terminal açıp uygulamanızı tetikleyin. Hangi dosyalara hangi sırayla erişildiğini gerçek zamanlı olarak göreceksiniz. Kilitlenme noktasını bulmak çok daha kolaylaşır.

strace ile Proses Seviyesinde Kilit Analizi

Daha derin bir analiz için strace kullanabilirsiniz. Bu araç, bir prosesin yaptığı tüm sistem çağrılarını yakalar. Dosya kilitleme için fcntl ve flock sistem çağrıları kritiktir.

# Çalışan bir prosesi izle (PID: 2341)
strace -p 2341 -e trace=fcntl,flock,open,close 2>&1 | head -50

# Yeni bir programı başlatırken izle
strace -e trace=fcntl,flock ./myapp 2>&1 | grep -E "flock|fcntl"

fcntl çıktısında F_SETLK veya F_SETLKW göreceksiniz. W harfi “wait” anlamına gelir, yani proses kilidi almak için bekliyor demektir. Bu tam olarak tıkandığı noktadır.

Python veya Bash Script Kilitlenmelerini Çözme

Çok sık karşılaşılan bir senaryo: Kendi yazdığınız script bir lock dosyası oluşturuyor ama beklenmedik şekilde sonlandığından lock dosyasını temizlemiyor.

Lock dosyasını kullanan tipik bir bash script örneği ve güvenli kullanımı:

#!/bin/bash

LOCKFILE="/var/lock/myscript.lock"

# Trap ile script sonlandığında lock'u temizle
cleanup() {
    rm -f "$LOCKFILE"
    echo "Lock dosyasi temizlendi."
}
trap cleanup EXIT INT TERM

# Lock kontrolü
if [ -f "$LOCKFILE" ]; then
    # Lock dosyasindaki PID'i oku
    LOCK_PID=$(cat "$LOCKFILE")
    
    # Bu PID hala calisiyor mu?
    if kill -0 "$LOCK_PID" 2>/dev/null; then
        echo "Script zaten caliyor (PID: $LOCK_PID). Cikiliyor."
        exit 1
    else
        echo "Eski lock dosyasi bulundu (PID: $LOCK_PID artik calismıyor). Temizleniyor."
        rm -f "$LOCKFILE"
    fi
fi

# Lock dosyasini olustur
echo $$ > "$LOCKFILE"

echo "Script basliyor (PID: $$)..."
# Asil is burada yapilir
sleep 30
echo "Script tamamlandi."

Bu script, ölü proseslerin bıraktığı lock dosyalarını otomatik olarak temizler. flock komutunu kullanarak daha sağlam bir yöntem de mevcut:

#!/bin/bash

LOCKFILE="/var/lock/myscript.lock"

# flock ile atomic lock alma
exec 200>"$LOCKFILE"
flock -n 200 || { echo "Script zaten caliyor. Cikiliyor."; exit 1; }

echo $$ >&200

echo "Script calisiyor..."
sleep 30
echo "Tamamlandi."

flock -n parametresi non-blocking modda çalışır; kilidi alamazsa beklemek yerine hemen çıkar. -w parametresiyle timeout ekleyebilirsiniz:

flock -w 10 200 || { echo "10 saniye icinde lock alinamadi."; exit 1; }

Kilit Sorunlarını Önlemek İçin İzleme Scripti

Production ortamında kilit sorunlarını proaktif olarak izlemek için basit bir monitoring scripti:

#!/bin/bash

# /proc/locks dosyasindaki kilit sayisini izle
LOCK_COUNT=$(wc -l < /proc/locks)
THRESHOLD=100

if [ "$LOCK_COUNT" -gt "$THRESHOLD" ]; then
    echo "UYARI: Sistem genelinde $LOCK_COUNT aktif dosya kilidi var!"
    echo "En cok kilit tutan prosesler:"
    
    # PID'leri cek ve proses isimlerini goster
    awk '{print $5}' /proc/locks | sort | uniq -c | sort -rn | head -10 | while read count pid; do
        if [ -d "/proc/$pid" ]; then
            pname=$(cat /proc/$pid/comm 2>/dev/null || echo "bilinmiyor")
            echo "  PID $pid ($pname): $count kilit"
        fi
    done
fi

# Uzun suredir bekleyen prosesleri bul
echo ""
echo "D durumundaki (I/O bekleyen) prosesler:"
ps aux | awk '$8 == "D" {printf "  PID: %s, Komut: %sn", $2, $11}'

Bu scripti cron’a ekleyerek düzenli aralıklarla çalıştırabilir ve sorunları önceden fark edebilirsiniz:

*/5 * * * * /usr/local/bin/check_locks.sh >> /var/log/lock_monitor.log 2>&1

Sık Karşılaşılan Hata Mesajları ve Anlamları

Uygulamalarınızdan veya sistem loglarından gelen hata mesajlarını doğru yorumlamak, sorunun kaynağına hızlı ulaşmanızı sağlar:

  • “Resource temporarily unavailable”: Genellikle EAGAIN hatasına karşılık gelir. Non-blocking I/O veya kilit denemesinin başarısız olduğunu gösterir.
  • “Device or resource busy”: EBUSY hatası. Dosya veya cihaz başka bir proses tarafından kullanılıyor.
  • “File exists”: Lock dosyası zaten mevcut, önceki proses temizlememiş.
  • “Too many open files”: EMFILE hatası. Prosesin dosya tanımlayıcı limiti aşılmış. ulimit -n ile mevcut limiti, lsof -p PID | wc -l ile prosesin açık dosya sayısını kontrol edin.

Dosya tanımlayıcı limitini geçici olarak artırmak için:

ulimit -n 65536

Kalıcı değişiklik için /etc/security/limits.conf dosyasını düzenleyin:

echo "* soft nofile 65536" >> /etc/security/limits.conf
echo "* hard nofile 65536" >> /etc/security/limits.conf

Sonuç

Dosya kilitleme sorunları, sysadmin hayatının kaçınılmaz bir parçasıdır. Önemli olan paniklemeden sistematik bir yaklaşım sergilemektir. Önce lsof ya da fuser ile hangi prosesin sorunu yarattığını tespit edin, ardından /proc/locks ile kilit detaylarına bakın. Eğer sorun tekrarlıyorsa inotifywait veya strace ile daha derin bir analiz yapın.

Production ortamında proaktif olmak her zaman reaktif davranmaktan iyidir. Lock monitoring scriptlerini cron’a ekleyin, uygulamalarınızın lock dosyası yönetimini trap ve flock kullanarak sağlam bir zemine oturtun. NFS ortamlarında ise lock daemon’larının durumunu düzenli olarak kontrol etmeyi ihmal etmeyin.

Bu araçları ve teknikleri düzenli olarak pratik yaparak öğrenmenizi tavsiye ederim. Test ortamında kasıtlı olarak kilitlenme senaryoları yaratın ve çözüm sürecinizi pratik edin. Gerçek bir kriz anında sakin kafayla doğru adımları atmak için önceden hazırlanmış olmak paha biçilmezdir.

Yorum yapın