SystemTap ile Linux Çekirdeğinde Dinamik İzleme Noktaları Oluşturma ve Süreç Davranışını Analiz Etme

Üretim ortamında bir süreç neden bu kadar yavaş? Kernel hangi sistem çağrısında takılıyor? Bir uygulama hangi dosyalara erişiyor, hangi ağ operasyonlarını yapıyor? Bu soruların cevabını bulmak için genellikle strace, ltrace ya da perf’e başvururuz. Ama bu araçların göremediği şeyleri görmek istediğinizde, kernel içine dinamik olarak probe noktaları eklemeniz gerektiğinde, işte o zaman SystemTap devreye girer.

SystemTap, Linux çekirdeğinin hemen her noktasına izleme kodu yerleştirmenizi sağlayan güçlü bir altyapıdır. Scriptlerinizi önce C koduna derler, ardından kernel modülü olarak yükler ve çalıştırır. Bu yaklaşım hem esneklik hem de performans açısından ciddi avantajlar sunar. Kernel yeniden derlemenize gerek yok, sistemi durdurmanıza gerek yok, sadece script yazıp çalıştırıyorsunuz.

Kurulum ve Ön Hazırlık

SystemTap’in doğru çalışabilmesi için birkaç kritik gereksinim var. Bu gereksinimleri atlamak, saatlerce hata ayıklamayla uğraşmanıza yol açabilir.

# RHEL/CentOS/Rocky Linux için
sudo dnf install systemtap systemtap-runtime

# Ubuntu/Debian için
sudo apt-get install systemtap systemtap-runtime

# Kernel debug sembolleri - bu kritik!
# RHEL tabanlı sistemlerde
sudo dnf install kernel-debuginfo kernel-debuginfo-common kernel-devel

# Ubuntu'da
sudo apt-get install linux-image-$(uname -r)-dbgsym

Kurulumdan sonra hızlı bir sağlık testi yapın:

# Basit bir test - kernel versiyonunu yazdıran probe
sudo stap -e 'probe begin { printf("Kernel: %sn", uname.release); exit(); }'

Eğer bu komut hata veriyorsa, debug sembollerinin kernel versiyonunuzla tam eşleştiğinden emin olun. Benim en çok zaman kaybettiğim nokta buydu: sistem güncellemesi sonrası kernel güncellenmiş ama debuginfo paketi eski versiyona işaret ediyordu.

SystemTap Script Anatomisi

Bir SystemTap scripti probe tanımları ve handler’lardan oluşur. Syntax ilk bakışta biraz garip gelebilir ama mantığını kavradıktan sonra oldukça sezgisel.

# stap_ornek.stp
probe kernel.function("sys_open") {
    printf("Dosya açıldı: %s, PID: %dn", 
           kernel_string($filename), 
           pid())
}

probe end {
    printf("İzleme tamamlandı.n")
}

Probe noktaları şu formatlarda olabilir:

  • kernel.function(“fonksiyon_adı”): Kernel fonksiyonu girişi
  • kernel.function(“fonksiyon_adı”).return: Kernel fonksiyonu çıkışı
  • kernel.statement(“fonksiyon@dosya:satır”): Belirli bir kod satırı
  • process(“uygulama”).function(“fonksiyon”): Kullanıcı alanı uygulaması
  • syscall.open: Sistem çağrısı probe’ları (hazır tapset’ler)
  • timer.ms(100): Zamanlayıcı tabanlı probe’lar
  • begin / end: Script başlangıç ve bitişi

Gerçek Dünya Senaryosu 1: Hangi Süreç Hangi Dosyalara Erişiyor?

Bir müşteri sisteminde, disk I/O kullanımının neden bu kadar yüksek olduğunu bulmaya çalışıyorduk. Klasik araçlar genel bir tablo veriyordu ama hangi uygulamanın hangi dosyalara bu kadar sık eriştiğini net göremiyorduk.

# dosya_erisim.stp
# Belirli bir PID için dosya erişimlerini izle

global dosya_sayaci

probe syscall.open {
    if (pid() == target()) {
        dosya_sayaci[filename]++
        printf("[%s] Açıldı: %sn", execname(), filename)
    }
}

probe syscall.read {
    if (pid() == target()) {
        printf("[READ] PID:%d, fd:%d, boyut:%dn", 
               pid(), fd, count)
    }
}

probe end {
    printf("n--- Dosya Erişim Özeti ---n")
    foreach (dosya in dosya_sayaci-) {
        printf("%5d kez: %sn", dosya_sayaci[dosya], dosya)
    }
}

Bu scripti belirli bir PID için çalıştırmak:

sudo stap dosya_erisim.stp -x 12345

Script çalıştığında ortaya çıkan tablo şaşırtıcıydı: uygulama her istek geldiğinde bir konfigürasyon dosyasını baştan okuyordu. Saniyede yüzlerce kez. Cache mekanizması tamamen devre dışıydı. Bu tespit bir satır kod değişikliğiyle çözüldü ve disk I/O yükü dramatik şekilde düştü.

Gerçek Dünya Senaryosu 2: Sistem Çağrısı Gecikmelerini Ölçmek

Üretim ortamında periyodik latency spike’ları yaşıyordunuz diyelim. Bunların neden kaynaklandığını bulmak için sistem çağrısı gecikmelerini ölçmek gerekiyor.

# syscall_latency.stp
# Yavaş sistem çağrılarını tespit et

global zamanlar
global esik_us = 1000  # 1ms üzeri gecikmeleri yakala

probe syscall.* {
    zamanlar[tid()] = gettimeofday_us()
}

probe syscall.*.return {
    if (zamanlar[tid()]) {
        gecikme = gettimeofday_us() - zamanlar[tid()]
        delete zamanlar[tid()]
        
        if (gecikme > esik_us) {
            printf("YAVAŞ SİSTEM ÇAĞRISI: %s, PID:%d, İşlem:%s, Gecikme:%d usn",
                   name, pid(), execname(), gecikme)
        }
    }
}
# Tüm sistemde çalıştır, 60 saniye boyunca
sudo stap syscall_latency.stp -T 60

Bu scriptle latency spike’larının tam olarak hangi sistem çağrısından kaynaklandığını belirledik. Beklentimizin aksine problem I/O’da değil, bir mutex kilidinde aşırı bekleme yaşanan futex çağrısındaydı.

Gerçek Dünya Senaryosu 3: Ağ Bağlantı Analizi

Hangi süreç hangi IP adreslerine bağlanıyor? Güvenlik perspektifinden ya da debugging amacıyla bu bilgi çok değerli olabilir.

# ag_baglantilar.stp
# TCP bağlantılarını izle

probe kernel.function("tcp_connect") {
    sock = $sk
    printf("TCP BAĞLANTI: %s (PID:%d) -> Hedef port: %dn",
           execname(),
           pid(),
           __tcp_skb_cb_seq($sk))
}

probe kernel.function("tcp_close") {
    printf("TCP KAPANDI: %s (PID:%d)n",
           execname(),
           pid())
}

probe begin {
    printf("Ağ izleme başladı...n")
}

Daha kapsamlı ağ izleme için SystemTap’in hazır tapset’lerinden yararlanabiliriz:

# Hazır network tapset kullanan örnek
# nettop.stp benzeri bir script

global gonderilen, alinan

probe netdev.transmit {
    gonderilen[execname()] += length
}

probe netdev.receive {
    alinan[dev_name] += length
}

probe timer.s(5) {
    printf("n=== Ağ İstatistikleri (son 5 saniye) ===n")
    foreach (islem in gonderilen-) {
        printf("Gönderen: %-20s %10d byten", 
               islem, gonderilen[islem])
    }
    delete gonderilen
    delete alinan
}

Kullanıcı Alanı Uygulamalarını İzlemek

SystemTap sadece kernel space ile sınırlı değil. Kullanıcı alanı uygulamalarını, hatta paylaşılan kütüphaneleri de izleyebilirsiniz.

# uygulama_izle.stp
# Belirli bir binary'nin fonksiyon çağrılarını izle

probe process("/usr/bin/nginx").function("ngx_http_process_request") {
    printf("Nginx istek işliyor: PID=%d, TID=%dn", pid(), tid())
}

probe process("/usr/bin/nginx").function("ngx_http_finalize_request") {
    printf("Nginx istek tamamlandı: PID=%dn", pid())
}

Python ya da Java gibi dinamik diller için durum biraz farklı. Bu dillerin interpreter’larını probe etmeniz gerekir:

# Python uygulamasını izle
# Python'un C runtime'ına probe ekle

probe process("/usr/bin/python3").function("PyEval_EvalFrameEx") {
    printf("Python frame değerlendi: PID=%dn", pid())
}

SystemTap Aggregate ve İstatistik Fonksiyonları

SystemTap’in güçlü yanlarından biri istatistiksel veri toplama mekanizması. Aggregate’ler sayesinde histogram, ortalama ve dağılım verilerini kolayca toplayabilirsiniz.

# sistem_cagri_istatistik.stp
# Sistem çağrısı sürelerinin histogramını çıkar

global sureler

probe syscall.read {
    sureler[execname()] <<< gettimeofday_us()
}

probe timer.s(10) {
    foreach (islem in sureler) {
        printf("n%s için read() istatistikleri:n", islem)
        printf("  Çağrı sayısı: %dn", @count(sureler[islem]))
        printf("  Minimum: %d usn", @min(sureler[islem]))
        printf("  Maximum: %d usn", @max(sureler[islem]))
        printf("  Ortalama: %d usn", @avg(sureler[islem]))
        print(@hist_log(sureler[islem]))
    }
    delete sureler
}

Bu çıktı size read() sistem çağrısının logaritmik histogramını verir. Latency dağılımını görselleştirmek açısından inanılmaz faydalıdır.

Guru Mode ve Kernel Yapılarına Erişim

Standart SystemTap modu güvenlik kısıtlamaları uygular. Daha derin kernel yapılarına erişmek için guru mode kullanabilirsiniz:

# guru_ornek.stp
# Guru mode ile doğrudan kernel yapılarına eriş
# -g parametresiyle çalıştırılmalı

probe kernel.function("__do_page_fault") {
    regs = $regs
    printf("Page fault: address=0x%lx, PID=%d, İşlem=%sn",
           $address, pid(), execname())
}

probe kernel.function("do_exit") {
    printf("Süreç sonlandı: PID=%d, İşlem=%s, Kod=%dn",
           pid(), execname(), $code)
}
sudo stap -g guru_ornek.stp

Uyarı: Guru mode ile hatalı yazılmış bir script sistemi çökertebilir. Test ortamında mutlaka deneyin.

Performans Optimizasyonu için Pratik İpuçları

SystemTap scriptleri kernel içinde çalıştığı için verimsiz kodlar sistem performansını olumsuz etkileyebilir. Bazı kritik noktalar:

  • Mümkün olduğunca filtrele: Global veri toplamak yerine sadece ilgilendiğiniz PID veya işlem adına odaklanın
  • printf yerine log kullanın: Yoğun ortamlarda printf yavaşlatabilir, log() daha verimlidir
  • Büyük global array’lerden kaçının: Sınırsız büyüyen array’ler bellek sorunlarına yol açar
  • -b parametresini kullanın: Buffer boyutunu artırmak veri kaybını önler
# Verimli filtreleme örneği
probe syscall.write {
    # Önce filtrele, sonra işle
    if (execname() != "nginx") next
    if (fd < 3) next  # stdin/stdout/stderr'ı atla
    
    printf("nginx write: fd=%d, count=%dn", fd, count)
}
# Performans odaklı çalıştırma seçenekleri
sudo stap -b 8192         # 8MB buffer
          -s 64            # 64MB segment
          script.stp

Tapset Kütüphaneleri ve Hazır Modüller

SystemTap’in /usr/share/systemtap/tapset/ dizininde onlarca hazır tapset bulunur. Bu tapset’ler sık kullanılan probe noktaları için yüksek seviyeli soyutlamalar sağlar.

# Mevcut tapset'leri listele
ls /usr/share/systemtap/tapset/

# Kullanışlı örnekler genellikle şurada bulunur
ls /usr/share/doc/systemtap/examples/

Hazır tapset kullanımı scripti hem okunabilir hem de taşınabilir kılar:

# tapset kullanan örnek - process.stp
# process tapset'ini kullanarak daha temiz kod

probe process.begin {
    printf("Yeni süreç: %s (PID=%d, PPID=%d)n",
           execname(), pid(), ppid())
}

probe process.end {
    printf("Süreç bitti: %s (PID=%d, çıkış kodu=%d)n",
           execname(), pid(), $return)
}

probe process.exec {
    printf("Exec çağrısı: %s yeni program çalıştırıyorn", 
           execname())
}

Bu scriptle sistemde anlık olarak hangi süreçlerin başlayıp bittiğini gerçek zamanlı takip edebilirsiniz. Güvenlik denetimleri için oldukça pratik bir senaryo.

Hata Ayıklama ve Sorun Giderme

SystemTap ile çalışırken karşılaşılan yaygın sorunlar ve çözümleri:

  • “couldn’t find module” hatası: Kernel debuginfo paketlerini kontrol edin, uname -r ile kernel versiyonunuzu doğrulayın
  • “semantic error” hataları: Değişken tiplerine dikkat edin, kernel pointer’ları için $ kullanın
  • Çok fazla çıktı: -T ile süre sınırı koyun ya da daha agresif filtreler ekleyin
  • Script çok yavaş derleniyor: Normal, ilk çalıştırmada kernel modülü derleniyor
# Verbose derleme çıktısı için
sudo stap -v script.stp

# Sadece parse et, çalıştırma
sudo stap -p1 script.stp

# C koda çevir ama derleme
sudo stap -p3 script.stp > script.c

SystemTap’in ürettiği C kodunu incelemek, hem aracı daha iyi anlamanızı sağlar hem de hata ayıklamada yardımcı olur.

Sonuç

SystemTap, deneyimli bir sistem yöneticisinin araç kutusunda bulunması gereken nadir araçlardan biri. Öğrenme eğrisi var, kurulum bazen sinir bozucu olabiliyor, ama bir kez alıştığınızda başka hiçbir araçla bu kadar derine inemeyeceğinizi fark ediyorsunuz.

Pratik olarak şunu söyleyebilirim: üretim ortamında “neden bu kadar yavaş?” sorusunun cevabını bulmak için harcadığım zamanın ciddi bir kısmı, SystemTap kullanmaya başladıktan sonra dramatik biçimde azaldı. Saatler yerine dakikalar. Bir uygulama neden belirli anlarda yavaşlıyor, kernel hangi kilit mekanizmasında bekleme yapıyor, hangi sistem çağrısı bottleneck yaratıyor… Bunların hepsini canlı sistemde, hiçbir şeyi durdurmadan görebilmek paha biçilmez.

Başlangıç için man stap ve /usr/share/doc/systemtap/examples/ dizinindeki örnekleri inceleyin. Topluluğun hazırladığı stapprobes, tapset:: man sayfaları da referans olarak oldukça işe yarıyor. Kernel fonksiyon isimlerini bulmak için ise stap -L 'kernel.function("open*")' gibi listing sorgularını kullanın.

Sysadmin işinde en değerli beceri, kara kutuları şeffaf hale getirebilmek. SystemTap tam da bunu yapıyor.

Bir yanıt yazın

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