Post

strace'ten eBPF'e Evrim: Canlı Sistemi Neşter Vurmadan İzlemek (MRI Teknolojisi)

Production ortamındaki bir veritabanını strace ile durdurmak bir intihar görevi olabilir. Peki, sistemi hiç yavaşlatmadan, kernel'ın her bir sinir ucunu nasıl dinleriz? Linux gözlemlenebilirliğinin (Observability) modern çağı eBPF'e, Kprobes ve Tracepoints dünyasına hoş geldiniz.

strace'ten eBPF'e Evrim: Canlı Sistemi Neşter Vurmadan İzlemek (MRI Teknolojisi)

Bu blog serisinin ilk yazısında, strace aracını “sistem yöneticisinin X-Ray cihazı” olarak tanıtmış, ancak sonuna kocaman, kırmızı bir uyarı levhası asmıştık: “Dikkat: Production ortamında kullanmak tehlikeli olabilir.”

Hatırlayalım: strace (ve temeli olan ptrace mekanizması), izlediği programı her bir sistem çağrısında (Syscall) durdurur, veriyi kopyalar ve tekrar çalıştırır. Saniyede 100.000 işlem yapan yoğun bir PostgreSQL sunucusuna strace ile bağlanmak, otobanda giden bir Ferrari’yi her 10 metrede bir durdurup “Ehliyet ruhsat lütfen” demeye benzer. Araba gitmeye devam eder belki ama artık hızı saatte 10 km’ye düşmüştür. Latency (Gecikme) tavan yapar, müşteriler isyan eder.

Peki, Ferrari’yi hiç durdurmadan, motorun iç sıcaklığını, pistonların devrini ve yakıt enjeksiyon milisaniyelerini canlı canlı nasıl izleriz? Hastanın karnını yarmadan (cerrahi müdahale yapmadan), iç organlarının 3 boyutlu haritasını nasıl çıkarırız?

Cevap: eBPF (Extended Berkeley Packet Filter).

Eğer strace bir neşter veya keşif amaçlı ameliyat ise; eBPF, Linux çekirdeğinin MRI (Manyetik Rezonans) cihazıdır. Sistemi durdurmaz. Kesip biçmez. Sadece manyetik alanlarla (Probe’lar) içeriyi tarar, veriyi toplar ve size sunar. Hasta (Production Sunucusu) hiçbir şey hissetmez.

Bu yazıda, “Debugger” zihniyetinden çıkıp “Observability” (Gözlemlenebilirlik) çağına adım atacağız. Kernel’ın içine güvenli sensörler yerleştirmeyi, kprobe ve tracepoint kavramlarını ve Linux’un süper gücü eBPF’i öğreneceğiz.

🧱 1. Zihniyet Devrimi: Context Switch vs In-Kernel VM

strace‘in neden yavaş olduğunu teknik olarak anlamadan eBPF’in değerini anlayamayız.

Eski Dünya: ptrace ve Context Switch Cehennemi

Bir program read() çağrısı yaptığında ve strace onu izliyorsa şu olur:

  1. Program: read() çağırır.
  2. Kernel: Programı durdurur (TRAP).
  3. Context Switch: CPU, programdan strace sürecine geçer.
  4. strace: Veriyi okur, ekrana basar.
  5. Context Switch: CPU, strace‘ten tekrar Kernel’a geçer.
  6. Kernel: Programı tekrar çalıştırır.

Bu “dur-kalk” işlemi (Context Switch), işlemci için çok pahalı bir operasyondur. Bellek haritaları (TLB) temizlenir, önbellekler (Cache) soğur.

Yeni Dünya: eBPF ve Sandbox

eBPF yaklaşımı ise tamamen farklıdır. strace gibi dışarıdan bir ajan (Userspace Process) kullanmak yerine, Kernel’ın içine minik bir programcık (Bytecode) göndeririz.

  1. Biz (User space), C veya Python ile küçük bir script yazarız: “Her read çağrıldığında sadece byte sayısını topla.”
  2. Bu script derlenir ve Kernel’a yüklenir.
  3. Verifier (Doğrulayıcı): Kernel, bu kodun güvenli olup olmadığını, sonsuz döngüye girip girmeyeceğini kontrol eder. Güvenliyse kabul eder.
  4. JIT (Just-In-Time) Compiler: Bu kod, işlemcinin anlayacağı makine diline çevrilir.
  5. Çalışma Anı: Program read() çağırdığında, Kernel dışarı çıkmadan, kendi içinde bu minik kodu çalıştırır. Veriyi toplar (Map’e yazar) ve devam eder.

Sonuç: Sıfır Context Switch. Sıfır duraklama. İnanılmaz hız. eBPF, Linux Kernel’ını programlanabilir hale getirir. Kernel’ı yeniden derlemeden, sisteme reset atmadan, canlı yayında Kernel’ın mantığını değiştirebilir veya izleyebilirsiniz.

🧬 2. Sinir Uçlarına Dokunmak: Hooks, Probes ve Tracepoints

eBPF programcıkları havada asılı durmaz. Kernel’daki olaylara (Event) bağlanmaları gerekir. Buna Hooking denir. Tıpkı bir olta iğnesini akıntıya bırakmak gibi. Üç temel olta türümüz vardır:

A. Kprobes (Kernel Probes) - “Dinamik Ajanlar”

Kernel’daki herhangi bir fonksiyonu izleyebilirsiniz. do_sys_open, tcp_sendmsg, vfs_read… Kernel’ın kaynak kodunda gördüğünüz hemen her fonksiyonun başına (kprobe) veya sonuna (kretprobe) bir eBPF sensörü takabilirsiniz.

  • Avantajı: Sonsuz esneklik. Her şeyi izleyebilirsiniz.
  • Dezavantajı: Kernel sürümüne bağımlıdır. Linux 5.4’te adı tcp_sendmsg olan fonksiyon, 5.10’da tcp_sendmsg_locked olabilir. Scriptiniz çalışmayabilir (Unstable API).

B. Tracepoints - “Resmi Duraklar”

Kernel geliştiricileri, kodun içine “Buraya birileri bakmak isteyebilir” diye özel, sabit duraklar koymuştur. sched:sched_switch (Process değişimi), net:netif_receive_skb (Paket gelişi) gibi.

  • Avantajı: Çok kararlıdır (Stable API). Kernel sürümü değişse bile tracepoint isimleri genelde değişmez. Production için en güvenlisi budur.
  • Dezavantajı: Her yerde yoktur. Sadece Kernel geliştiricilerinin koyduğu yerleri izleyebilirsiniz.

C. Uprobes (User Probes) - “Uygulamanın İçine Sızmak”

eBPF sadece Kernel’ı değil, User Space’teki uygulamaları da izleyebilir! MySQL’in içindeki dispatch_command fonksiyonunu veya kendi yazdığınız Go/C++ programındaki hesapla() fonksiyonunu izleyebilirsiniz. GDB gibi ama durdurmadan.

🛠️ 3. Alet Çantası: BCC ve bpftrace

eBPF Assembly (Bytecode) yazmak çok zordur. Kimse (Kernel hackerları hariç) bunu elle yazmaz. Bize yüksek seviyeli araçlar lazım.

BCC (BPF Compiler Collection)

Python ile yazılmış, Linux’un İsviçre çakısıdır. İçinde onlarca hazır, production-ready script gelir.

  • execsnoop: Kim hangi komutu çalıştırıyor?
  • opensnoop: Kim hangi dosyayı açıyor?
  • biolatency: Disk gecikmeleri histogramı.
  • tcplife: TCP bağlantılarının ömrü ve kapanış nedenleri.

bpftrace

Python yazmak bile zor geliyorsa, awk benzeri tek satırlık komutlar (One-Liners) için bpftrace kullanılır. Anlık saptamalar için muazzamdır.

🕵️‍♂️ 4. Vaka Analizi 1: “Disk Yavaş mı Yoksa Program mı Tembel?”

MySQL sunucusu yavaş. Disk I/O’dan şüpheleniyorsunuz. iostat size diskin doluluk oranını (%util) verir ama gecikmenin (latency) ne kadar olduğunu söylemez. Ortalama bir değer verir. strace açsanız sunucu daha da yavaşlayacak.

Çözüm: biosnoop (BCC aracı). Bu araç, Kernel’ın Block I/O katmanına (disk sürücüsü ile dosya sistemi arasına) kanca atar.

1
sudo biosnoop

Çıktı akar:

1
2
3
TIME(s)     COMM           PID    DISK    T  SECTOR    BYTES   LAT(ms)
0.000000    mysqld         1234   sda     R  2048      4096    0.15
0.000400    mysqld         1234   sda     W  4096      8192    12.50

Sağdaki LAT(ms) sütunu, o spesifik I/O işleminin kaç milisaniye sürdüğünü gösterir. Eğer burada sürekli 0.1ms görüyorsanız disk harikadır. Ama arada 100ms’ler görüyorsanız, diskiniz (veya kiraladığınız EBS volume) can çekişiyordur. Bunu strace ile yapsaydınız, o 0.1ms’lik işlem, ptrace overhead’i yüzünden 0.5ms görünecek ve ölçümünüzü sapırttıracaktı. eBPF ile ölçüm, olayı değiştirmez (Heisenberg mutlu).

🕵️‍♂️ 5. Vaka Analizi 2: “TCP Bağlantıları Neden Kopuyor?”

Uygulamanız arada bir “Connection Reset” hatası alıyor. Ama tcpdump açtığınızda o hatayı bir türlü yakalayamıyorsunuz çünkü log dosyaları GB’larca veriyle doluyor. Bize “Sadece kapanan bağlantıları” gösterecek akıllı bir filtre lazım.

Çözüm: tcplife.

1
sudo tcplife

Çıktı:

1
2
PID   COMM       LADDR           LPORT RADDR           RPORT TX_KB RX_KB MS
8542  curl       10.0.0.5        4562  192.168.1.10    80    1     15    25.40

Bu araç, Kernel’ın TCP durum makinesini (State Machine) izler. Bir bağlantı ESTABLISHED durumundan CLOSED durumuna geçtiği an (Kernel içinde), o anı yakalar ve özet bilgiyi (Ne kadar veri gitti, ne kadar sürdü) ekrana basar. Sıfır ek yük ile tüm TCP trafiğinin bir muhasebesini tutarsınız.

🕵️‍♂️ 6. Vaka Analizi 3: “Dosyayı Kim Siliyor?”

Bir log dosyası aniden yok oluyor. rm komutu history’de yok. Kimin sildiğini bulamıyorsunuz. auditd kurabilirsiniz ama ayarlaması zahmetli.

Çözüm: opensnoop veya tek satırlık bpftrace.

1
2
# unlink (dosya silme) syscall'ını izle ve yapanı yaz
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_unlink { printf("%s (%d) siliyor: %s\n", comm, pid, str(args->pathname)); }'

Bu komutu çalıştırıp bekleyin. Dosya silindiği an ekrana düşecektir: logrotate (4521) siliyor: /var/log/myapp.log.1

Faili meçhul cinayet aydınlandı. Logrotate konfigürasyonu hatalıymış.

🛡️ Güvenlik ve Riskler: Kernel Panic Geçirir miyiz?

Linux çekirdeğinin içine kod yüklemek kulağa korkutucu gelir. “Ya hatalı bir kod yazarsam ve Kernel çökerse?” Linux geliştiricileri bunu düşündü. eBPF’in kalbinde Verifier (Doğrulayıcı) vardır.

Verifier şunları kontrol eder:

  1. Sonsuz Döngü Yok: Kodunuz mutlaka bitmelidir. (Aslında modern Kernel’larda sınırlı döngülere izin verilir ama çok sıkı denetlenir).
  2. Bellek Güvenliği: Rastgele bir Kernel belleğini okuyamazsınız. Sadece izin verilen bağlamı (Context) okuyabilirsiniz.
  3. Crash Koruması: Null pointer hatası yaratacak işlemler engellenir.

Eğer yazdığınız (veya BCC ile gelen) script bu kurallara uymuyorsa, Kernel “Ben bunu yüklemem” der ve reject eder. Bu sayede eBPF, Kernel Modülü (LKM) yüklemekten çok daha güvenlidir. Kernel Modülü, hatasında tüm sistemi (Kernel Panic) çökertebilir. eBPF ise en fazla kendi hata verip çalışmaz.

👋 Son Söz: Sisteminizi “Dinleyin”

strace, bir sorunu anlamak için sistemi “dürtmek”ti. eBPF ise sistemi “duymak”tır.

Artık Linux kernel’ı kapalı bir kutu değil. İçinde ne olup bittiğini, paketlerin neden düştüğünü, diskin neden yavaşladığını, hangi process’in hangi dosyaya dokunduğunu mikrosaniye hassasiyetinde, sistemi yormadan izleyebilirsiniz.

Bu blog serisinde, en temel dosya izinlerinden başladık, ağ katmanlarına çıktık, User Space kütüphanelerine daldık ve şimdi Kernel’ın en modern teknolojisiyle zirveye ulaştık.

Artık elinizde bir neşter (strace), bir mikroskop (ltrace) ve bir MRI cihazı (eBPF) var. Hangi hastaya hangisini uygulayacağınız, sizin mühendislik yeteneğinize kalmış.

Sistemi izleyin, ama izlerken değiştirmeyin. Gözlemlenebilirlik (Observability) bir araç değil, bir kültürdür.

Sorunsuz Kernel’lar, temiz trace’ler dilerim.

This post is licensed under CC BY 4.0 by the author.