Post

Modern Linux Gözlemlenebilirliği (Observability): Debugging'den Sistem Düşüncesine Geçiş

🇹🇷 Serinin finalinde, elinizdeki büyüteci bırakıp güvenlik kamerası odasına geçiyoruz. Debugging bir sorunu çözmektir, Observability ise soruyu sormadan cevabı bilmektir. Junior bir sistemciden Senior/Staff mühendis zihniyetine giden yol, USE Metodu, RED Metodu ve 'Unknown Unknowns' kavramı.

Modern Linux Gözlemlenebilirliği (Observability): Debugging'den Sistem Düşüncesine Geçiş

Linux sistem programlama ve “low-level debugging” (derinlemesine hata ayıklama) üzerine çıktığımız bu uzun, teknik ve yer yer dolambaçlı yolculuğun son durağına hoş geldiniz.

Bu seriye başladığımızda, elimizde sadece paslı bir anahtar olan strace vardı. Onunla dosyaların kapısını zorladık, izinleri kontrol ettik. Ağ kablolarının içine sızıp paketleri dinledik. Sonra mikroskobumuzu (ltrace) çıkarıp uygulamaların beynine, User Space fonksiyonlarına girdik. En son ise bir “nükleer tıp” uzmanı titizliğiyle, eBPF teknolojisini kullanarak canlı sisteme neşter vurmadan MR çektik.

📚 Teknik Sözlük: Syscall (Sistem Çağrısı)

Bir uygulamanın (User Space) donanımla konuşma yetkisi yoktur. Diske yazmak veya ağa bağlanmak istediğinde Kernel’a bir “Dilekçe” verir. İşte bu dilekçeye Syscall denir (örn: read(), write(), connect()). strace bu dilekçeleri okuyan memurdur.

Şimdi ise sizden, masadaki tüm o cerrahi aletleri (strace, tcpdump, perf, gdb) bir kenara bırakmanızı istiyorum. Eldivenlerinizi çıkarın. Geriye yaslanın. Çünkü artık bir Teknisyen gibi değil, bir Mimar gibi düşünme zamanı.

Artık olaylara mikroskobik düzeyde (tek bir syscall, tek bir paket) bakmayı bırakıp, makroskobik düzeyde (sistemin genel sağlığı ve davranışları) bakmayı öğreneceğiz. Bu yazıda, “Bu süreç neden öldü?” (Debugging) sorusundan, “Bu sistem gerçekten sağlıklı mı?” (Observability) sorusuna nasıl evrileceğimizi konuşacağız. Bir sorunu çözmek ile o sorunun neden var olduğunu anlamak arasındaki devasa uçuruma bakacağız.

Eğer kariyerinizde “Senior” veya “Staff” mühendis olma hedefiniz varsa, bu yazı teknik komutlardan çok, o komutları ne zaman, nasıl ve neden kullanacağınızla ilgili zihinsel bir devrim niteliğindedir.

📌 Bu Yazıda Ne Öğreneceksin?

Bu yazının sonunda:

  • Debugging (Dedektif) ve Observability (Mimar) arasındaki zihniyet farkını kavrayacak, reaktif yaklaşımdan proaktif mühendisliğe geçeceksiniz
  • Rastgele metrik bakmak yerine, USE (Altyapı) ve RED (Servis) metodolojileriyle darboğazları dakikalar içinde izole etmeyi öğreneceksiniz
  • Emektar Load Average‘ı neden çöpe atmanız gerektiğini ve Facebook’un geliştirdiği PSI (Pressure Stall Information) ile sistemdeki “gerçek acıyı” nasıl ölçeceğinizi göreceksiniz
  • Logs, Metrics ve Traces üçlüsünün Linux kernel’ındaki gerçek karşılıklarını keşfedecek ve High Cardinality tuzağına düşmeden doğru stratejiyi kurmayı öğreneceksiniz
  • “Unknown Unknowns” (Bilinmeyen Bilinmeyenler) kavramıyla tanışacak ve müşteri şikayet etmeden önce yaklaşan fırtınayı sezme yeteneği kazanacaksınız
  • Scheduler Latency ve Context Switch Overhead gibi görünmez performans katillerini eBPF ve sistem düşüncesiyle nasıl yakalayacağınızı gerçek bir vaka analiziyle deneyimleyeceksiniz

Kısacası; “Sorunu çözmek” ile “Sorunu anlamak” arasındaki o ince çizgiyi geçecek ve Linux sistemlerine bir Staff Engineer gözüyle bakmayı öğreneceksiniz.

🕵️‍♂️ 1. Temel Ayrım: Debugging vs Observability

Sektörde bu iki terim sıklıkla birbirine karıştırılır, hatta eş anlamlı gibi kullanılır. Ama aralarında felsefi ve pratik olarak gece ile gündüz kadar fark vardır.

Debugging (Hata Ayıklama)

Debugging, bir dedektiflik işidir. (Sherlock Holmes) Elinizde bir ceset (Crash / Core Dump) veya somut bir şikayet (Müşteri Ticket’ı) vardır. Olay gerçekleşmiştir. Fail bellidir ya da aranmaktadır. Siz olay yerine gidersiniz, parmak izi ararsınız (grep ERROR), tanıkları sorgularsınız (strace), suçluyu bulup cezalandırırsınız (bugfix veya kill).

  • Doğası: Reaktiftir (Tepkiseldir). Olay olduktan sonra başlar.
  • Soru Bellidir: “Neden çöktü?”, “Neden yavaşladı?”, “Neden hata verdi?” (Known Unknowns - Bilinen Bilinmeyenler).
  • Kapsamı Dardır: Genelde tek bir süreç, tek bir sunucu veya tek bir fonksiyon odaklıdır.

Observability (Gözlemlenebilirlik)

Observability, bir şehir planlamacısı veya Matrix’in Mimarı olmaktır. Olay henüz gerçekleşmemiştir veya gerçekleşiyorsa bile siz tek bir sokağa değil, şehrin tümüne hakimsinizdir. Dedektif gibi tek bir ipucunun peşinde değil, şehrin tüm kamera, trafik, elektrik ve su şebekesi verilerinin aktığı dev ekranların başındasınızdır.

  • Doğası: Proaktiftir (Öngörülüdür). Sorun çıkmadan önce veya sorun anında bütünü gösterir.
  • Soru Belirsizdir: “Sistemde şu an, şu saniyede garip giden ne var?” (“Unknown Unknowns” - Bilinmeyen Bilinmeyenler).
  • Kapsamı Geniştir: Tüm sistemi (Kernel, Disk, Ağ, Uygulama, Dağıtık Servisler) canlı bir organizma, bir bütün olarak ele alır.
graph TD
    subgraph Debugging ["Debugging (Reaktif)"]
        A["Olay Çıktı"] --> B{"Faili Bul"}
        B --> C["Düzelt"]
        C --> D["Bekle"]
        D -.-> A
        style Debugging stroke:#f44336,stroke-width:2px
    end
graph TD
    subgraph Observability ["Observability (Proaktif)"]
        X["Sistemi İzle"] --> Y{"Anormallik Var mı?"}
        Y -- Hayır --> X
        Y -- Evet --> Z["Sebebini Anla"]
        Z --> W["Sistemi İyileştir"]
        W --> X
        style Observability stroke:#4caf50,stroke-width:2px
    end

💡 Analoji:

Debugging, arabanız bozulup dumanlar çıkardığında kaputu açıp “Hangi kablo yandı?” diye bakmaktır. Monitoring, arabanın panelindeki “Motor Arıza Lambası”nın yanmasıdır. Size sadece “Bir sorun var” der. Observability, arabanızda giderken ön panelde anlık motor sıcaklığını, lastik basıncını, yağ viskozitesini ve devir sayısını sürekli görmektir. Duman çıkmadan 10 dakika önce “Motor sıcaklığı normalin %5 üzerine çıktı ve yağ basıncı düşüyor, 5 km sonra motor şişebilir” diyebilmektir.

🧱 2. Süreç Odaklılıktan Sistem Odaklılığına

Kariyerinin başındaki bir sistemci (Junior/Mid), doğal olarak Süreç (Process) odaklıdır. Eğitimi ve tecrübesi ona bunu öğretmiştir:

  • “Apache servisi çalışmıyor, loglarına bak.”
  • “MySQL çok RAM yiyor, config dosyasını incele.”
  • “Python scriptim hata verdi, kodunu debug et.”

Bu bakış açısı, elinizde strace ve gdb varken işe yarar. Tekil sorunları harika çözersiniz. Ama modern dünyada (Microservices, Kubernetes, Distributed Cloud Architectures), sorunlar nadiren tek bir süreçte başlar ve biter.

Kelebek Etkisi (The Butterfly Effect)

Bir e-ticaret sitesinde ödeme sayfasının (%1 ihtimalle) 5 saniye geciktiğini (Latency Spike) düşünün.

  1. Süreç Odaklı Debugging: Ödeme servisine (Payment Service) bakarsınız. CPU %10. Kod hatası yok. Log temiz. “Sorun yok” dersiniz. Ama müşteri hala bekliyor.
  2. Sistem Odaklı Observability: Staff Engineer, sisteme kuş bakışı bakar ve şunu görür: “Evet, ödeme servisi (Process) sağlıklı. Ama bu servisin çalıştığı sunucuda (Node), tamamen alakasız bir ‘Log Backup’ işlemi çalışıyor. Bu işlem diski o kadar meşgul ediyor ki (iowait), Kernel’ın I/O kuyruğu şişmiş. Ödeme servisi CPU beklemiyor, diske 1 KB log yazabilmek için Disk I/O Slot’u bekliyor.”

İşte bu, top komutundaki %wa (I/O Wait) değerini veya perf çıktısındaki kernel fonksiyonlarını (Block Layer) okuyabilme becerisidir. Tek bir ağaca değil, ormana (Ekosisteme, Node’un kendisine, Kernel’ın Scheduler’ına, Resource Contention’a) bakmaktır. “Noisy Neighbor” (Gürültülü Komşu) problemini ancak sistem odaklı düşünerek çözebilirsiniz.

🔬 3. Metodolojiler: USE ve RED

Peki, yüzlerce sunucu ve binlerce metrik arasında kaybolmadan doğru yere nasıl bakacağız? Rastgele top veya htop açmak amatörlüktür. Profesyonellerin metodolojileri vardır.

A. USE Metodu (Utilization, Saturation, Errors)

Netflix performans gurusu Brendan Gregg tarafından geliştirilen bu metod, Altyapı (Infrastructure) analizi için kullanılır. Bir sisteme (CPU, Disk, RAM, Ağ) yaklaştığınızda şu 3 soruyu sorarsınız:

  1. Utilization (Kullanım): Kaynak ne kadar meşgul? (Örn: CPU %90). %100 utilization her zaman kötü değildir, verimli kullanıldığını da gösterebilir.
  2. Saturation (Doygunluk/Sıkışıklık): Sırada bekleyen var mı? İşte kilit nokta budur. CPU %100 olabilir ama kuyrukta bekleyen yoksa işler yürüyordur. Ama CPU %50 iken, “Load Average” 20 ise (yani işlemci boşta olsa bile 20 süreç çalışmak için sıra bekliyorsa), sistem kilitlenmiştir.
  3. Errors (Hatalar): Donanım veya sürücü seviyesinde fiziksel hata var mı? (Örn: Disk errors, Network packet drops).

📚 Teknik Sözlük: Saturation (Doygunluk)

Bir kaynağın %100 kullanılması değil, o kaynak için sırada bekleyenlerin (Queue) oluşmasıdır. Bir restoranda tüm masaların dolu olması “Utilization %100”dür. Kapıda insanların kuyrukta beklemesi “Saturation”dır. Performans sorunu kuyrukta başlar.

Metrik Tipi Soru Linux Komut Karşılığı (CLI) Prometheus Karşılığı (Node Exporter)
Utilization Ne kadar meşgul? top (%Cpu), free -m node_cpu_seconds_total
Saturation Sırada bekleyen var mı? vmstat 1 (r sütunu), /proc/pressure (PSI) node_pressure_cpu_waiting_seconds_total
Errors Fiziksel hata var mı? dmesg, netstat -i (TX-ERR) node_network_receive_errs_total

🛑 Load Average Devri Bitti: PSI (Pressure Stall Information)

Yıllarca uptime komutundaki “Load Average” değerlerine baktık. Ama “Load: 5.0” ne demek? 5 süreç CPU mu bekliyor, yoksa Disk I/O mu? Yoksa sadece uninterruptible sleep modundalar mı? Load Average muğlaktır.

Linux 4.20+ ile gelen PSI (Pressure Stall Information) ise nettir. Facebook (Meta) mühendisleri tarafından geliştirilmiştir. /proc/pressure/cpu, io, memory dosyaları size “Sistemin yüzde kaçı kaynak bekleyerek zaman kaybediyor?” sorusunun kesin cevabını verir.

1
2
3
$ cat /proc/pressure/cpu
some avg10=2.45 avg60=0.12 avg300=0.01 total=856214
# Analiz: Son 10 saniyede, süreçlerin %2.45'i "Ben hazırım" dediği halde CPU bulamadı.

🔥 Modern USE Metodu:

Artık “Utilization”a bakıp tahmin yürütmek yerine, doğrudan Saturation‘ı PSI ile ölçüyoruz. Eğer avg10 > 0 ise, sistemde kesinlikle bir darboğaz vardır.

🛒 Analoji: Süpermarket Kasası

  • Utilization: Kasiyerin barkod okutma hızıdır. Kasiyer hiç durmadan çalışabilir (%100 CPU Utilization). Bu kötü değildir, verimlidir.
  • Saturation (PSI): Kasada bekleyen müşteri kuyruğudur. Kasiyer %100 çalışsa bile kuyruk yoksa herkes mutludur. Ama PSI artarsa (kuyruk uzarsa), en arkadaki müşterinin ödeme yapması (Latency) uzar.
  • Özet: CPU’nun %100 olması değil, PSI’ın 0’dan büyük olması sorundur.

B. RED Metodu (Rate, Errors, Duration)

Tom Wilkie tarafından geliştirilen bu metod ise Servisler (Services / Microservices) için kullanılır.

  1. Rate (Hız): Saniyede kaç istek geliyor? (RPS - Requests Per Second). Trafik artışı var mı?
  2. Errors (Hatalar): İsteklerin yüzde kaçı 5xx hatasıyla dönüyor?
  3. Duration (Süre): İsteklerin cevaplanması ne kadar sürüyor? (Latency). Özellikle 99. yüzdelik dilim (P99) nedir?

📚 Teknik Sözlük: Throughput vs Latency

  • Throughput (Debi): Otobandan 1 saatte kaç araç geçtiği. (Sunucu kapasitesi).
  • Latency (Gecikme): Bir aracın A şehrinden B şehrine varış süresi. (Hız).
  • Throughput yüksek olsa bile (çok araç geçiyor), trafik sıkışıksa Latency kötü olabilir (yavaş gidiyorlar).

📚 Teknik Sözlük: P99 (Yüzde 99)

“Ortalama” (Average) yalandır. Bill Gates bir bara girerse, bardakilerin “ortalama” geliri milyar dolar olur. P99 ise şudur: İsteklerin en yavaş %1’ini at, geri kalan %99’un en yavaşı kaç saniye? Gerçek kullanıcı deneyimini P99 (veya P95) gösterir. Ortalama sadece sizi kandırır.

Bir sistemci olarak, altyapıya USE, üzerindeki servislere RED metoduyla yaklaşırsanız, sorunun kaynağını dakikalar içinde izole edebilirsiniz.

🛠️ 4. Üç Sütun (Three Pillars) ve Linux Karşılıkları

Modern dünyada Observability denince akla Logs, Metrics, Traces gelir. Bunlar genelde pahalı SaaS ürünleriyle (Datadog, New Relic) özdeşleşir. Ama özünde bunlar Linux Kernel’ından çıkan basit verilerdir.

A. Logs (Kayıtlar) - “Ne Oldu?”

Bir olay gerçekleşir ve (genelde metin olarak) diske yazılır.

  • High Level: ELK Stack (Elasticsearch), Splunk, Graylog.
  • Low Level: journalctl -xe, /var/log/syslog, /var/log/dmesg, Uygulama logları (tail -f).
  • Risk: Loglar pahalıdır. Her DEBUG logu diske I/O yükü bindirir, CPU harcar, ağ trafiği yaratır. Loglar sadece “bilinen (kodlanmış) hataları” gösterir. Yazılımcı if (error) log("Hata") yazmadıysa, o hatayı loglarda asla göremezsiniz.

Modern Standart: Structured Logging (systemd-journald)

Linux’ta artık metin tabanlı log dosyaları (/var/log/syslog) yerini Binary Structured Logs‘a bırakıyor. systemd-journald, logları metadata (hangi servis, hangi pid, hangi uid) ile birlikte binary formatta saklar.

Eski (Text): grep "Error" /var/log/syslog (Yavaş, regex cehennemi) Yeni (Journal):

1
journalctl -p 3 -u nginx --since "1 hour ago" -o json-pretty

Bu komut size Nginx servisinin son 1 saatteki hatalarını (Priority 3) tertemiz bir JSON objesi olarak verir. Log parslamakla uğraşmazsınız.

⚠️ Kritik İpucu: Journald Persistence Varsayılan olarak (Ubuntu vb.) Journald logları RAM’de (/run/log/journal) tutar ve reboot atınca silinir. Prodüksiyon ortamında /etc/systemd/journald.conf dosyasına girip Storage=persistent ayarını yapmazsanız, sunucu kapandığında tüm delilleriniz yok olur.

B. Metrics (Metrikler) - “Şu an Durum Ne?”

Zaman içinde değişen sayılardır (Time-Series Data). Depolaması çok ucuzdur.

📚 Teknik Sözlük: Time-Series Data (Zaman Serisi)

İlişkisel Veritabanı (SQL) gibi “Son durum”u değil, “Zaman içindeki değişimi” tutar. UPDATE yoktur, sadece sürekli sona ekleme (APPEND) vardır. Örn: Saat 10:00 CPU %50. Saat 10:01 CPU %60. Eski veri silinmez, tarihçesi tutulur.

  • High Level: Prometheus, Grafana, VictoriaMetrics.
  • Low Level: /proc dosya sistemi.
    • /proc/meminfo: RAM kullanımı.
    • /proc/stat: CPU sayaçları.
    • /sys/class/net/eth0/statistics: Ağ kartı paket sayaçları.
  • Modern eBPF araçları, bu metrikleri Kernel’dan (syscall’lardan) minimum maliyetle çekip Prometheus formatına dönüştürür.

⚠️ Kritik Uyarı: High Cardinality (Yüksek Kardinalite)

Metrik dünyasının en büyük tuzağıdır. Metriklerinize User_ID, IP_Address veya Session_ID gibi sonsuz çeşitlilikte etiketler (Labels) eklerseniz, Prometheus veritabanınız (TSDB) şişer ve patlar. Metrikler “genel gidişatı” (Trend) görmek içindir. Tekil kullanıcı takibi için Log veya Trace kullanılır.

  • http_requests_total{status="500"} (Kardinalite Düşük - Güvenli)
  • http_requests_total{user_id="12345"} (Kardinalite Yüksek - TEHLİKELİ)

💡 Analoji (Kütüphane Kataloğu):

Kitapları “Türlerine Göre” (Roman, Bilim, Tarih) raflara dizerseniz (Low Cardinality), aradığınızı hemen bulursunuz. Ama her kitabı “İçindeki rastgele bir cümleye göre” (User ID) raflara dizerseniz (High Cardinality), kütüphane çöplüğe döner ve kimse hiçbir şey bulamaz.

graph TD
    subgraph LowCardinality ["Low Cardinality (Düzenli)"]
        Label1["Label: Roman"] --> Book1["Kitap A"]
        Label1 --> Book2["Kitap B"]
        Label2["Label: Bilim"] --> Book3["Kitap C"]
    end
    
    subgraph HighCardinality ["High Cardinality (Kaos)"]
        LabelA["Label: Cümle 1"] --> BookX["Kitap X"]
        LabelB["Label: Cümle 2"] --> BookY["Kitap Y"]
        LabelC["Label: Cümle 3"] --> BookZ["Kitap Z"]
        Note["⚠️ Binlerce Benzersiz Label!"]
    end
    style LowCardinality stroke:#4caf50,stroke-width:2px
    style HighCardinality stroke:#f44336,stroke-width:2px

🎯 Hedefsiz Metrik Gürültüdür: SLO & SLI “CPU %80 oldu” tek başına bir sorun değildir. Belki batch job çalışıyordur. Profesyonel gözlemlenebilirlik SLO (Service Level Objective) ile başlar.

  • SLI (Indicator - Gösterge): Arabanın Hız Göstergesi (Örn: Şu an 120 km/s ile gidiyorum).
  • SLO (Objective - Hedef): Hız Sınırı Tabelası (Örn: Bu yolda 110 km/s’yi asla geçmemelisin). Sadece hıza bakmak yetmez, tabelaya (Hedefe) uyup uymadığınıza bakmalısınız. Alarmı CPU’ya değil, SLO’nun yanma hızına (Burn Rate) kurmalısınız.

C. Traces (İzler) - “Nereye Gitti?”

Bir isteğin sistemdeki veya sistemler arası yaşam döngüsü.

  • High Level: Jaeger, Zipkin, OpenTelemetry (Distributed Tracing).
  • Low Level: strace (System Call Tracing), tcpdump (Network Packet Tracing), perf (CPU Profiling).
  • Trace’ler, “Neden yavaş?” sorusunun cevabını verir. “İstek geldi, 2 saniye DNS’te bekledi, 50ms veritabanında bekledi, 3 saniye de diskin dönmesini bekledi” gibi detaylı haritayı çıkarır.
  • Correlation ID (Trace ID): Dağıtık sistemlerin harcıdır. Kullanıcı “Satın Al” butonuna bastığında bir UUID üretilir (örn: x-request-id: abc-123). Bu ID, Load Balancer -> Web Server -> API Gateway -> Database arasında taşınır. Loglarda bu ID’yi arattığınızda, o isteğin tüm yaşam döngüsünü görürsünüz.

    Not: İsim Benzerliği Karmaşası Linux Kernel dünyasındaki “Tracing” (ftrace, strace) ile Microservices dünyasındaki “Tracing” (Distributed Tracing) farklı şeylerdir.

    • Kernel Tracing: Tek bir makinedeki fonksiyon çağrılarının takibidir (Derinlik).
    • Distributed Tracing: Servisler arası yolculuğun takibidir (Genişlik).

🚀 Modern Düya: OpenTelemetry (OTel)

Eskiden her dil için ayrı ajan (Java Agent, Python Library) gerekirdi. OpenTelemetry, endüstri standardı haline geldi. Uygulamanızdan Log, Metric ve Trace verisini tek bir formatta toplar ve Kernel seviyesindeki eBPF verileriyle birleştirir. “Modern Linux Gözlemlenebilirliği”, Kernel’dan gelen eBPF verisi ile Uygulamadan gelen OTel verisinin birleştiği yerdir.

💸 Teknik Kısıt: Sampling (Örnekleme) Şarttır

Saniyede 10.000 istek alan bir sistemde “Her isteği trace edeceğim” derseniz, network ve disk maliyetinden batarsınız. Mutlaka Sampling stratejisi (Örn: Trafiğin %1’i veya sadece Hatalı İstekler - Tail Sampling) uygulamalısınız.

Analoji (Güvenlik Kamerası):

Bir AVM’de 7/24 her saniyeyi Full HD kaydetmek (100% Tracing) diskleri doldurur. Sadece “Hareket Sensörü” çalıştığında veya “Alarm Çaldığında” kaydetmek (Tail Sampling) ise hem ucuzdur hem de sadece olayları yakalar.

🔌 Kutsal Kase Problemi: Context Propagation

eBPF kernel seviyesindedir (TCP paketleri, Syscall). OpenTelemetry uygulama seviyesindedir (HTTP Header). Uygulamadaki Trace-ID: abc-123 bilgisinin, Kernel’daki write() syscall’ı ile otomatik eşleşmesi (Context Propagation) hala mühendisliğin en zorlu problemlerinden biridir.

💡 Analoji (Havalimanı Bavulu):

  • Uygulama (Check-in): Bavula “Trace ID” etiketini yapıştırır.
  • Kernel (Bagaj Taşıyıcı): Bavulu uçağa taşır ama üzerindeki etiketi okumaz. Sadece “ağırlığına” (Byte size) bakar. Sorun şudur: Bagaj kaybolduğunda (Kernel’da paket kaybolduğunda), Kernel o bavulun kime ait olduğunu etikete bakarak değil, sadece ağırlığına bakarak anlamaya çalışır. OTel ile eBPF’i birleştirmek, kernel’a o etiketi okumayı öğretmektir.
graph LR
    subgraph AppSpace ["User Space (Uygulama)"]
        Packet["HTTP İsteği (Trace-ID: 123)"]
    end
    
    subgraph KernelSpace ["Kernel Space (eBPF)"]
        Syscall["write() Syscall"]
        Note["❌ Trace-ID Görünmüyor!"]
    end
    
    Packet -->|Sistem Çağrısı| Syscall
    Syscall --- Note
    
    style AppSpace stroke:#2196f3,stroke-width:2px,stroke-dasharray: 5 5
    style KernelSpace stroke:#f44336,stroke-width:2px,stroke-dasharray: 5 5
graph TD
    subgraph Pillars ["Observability Üçlüsü"]
        L["Logs: 'Hata Mesajı'"] --- M["Metrics: 'CPU %90'"]
        M --- T["Traces: 'Hangi Fonksiyon?'"]
        T --- L
    end
    style Pillars stroke:#2196f3,stroke-width:2px

🌉 5. Kayıp Halka: Köprü Araçları (Ad-Hoc Observability)

Serinin başındaki strace (mikro cerrahi) ile buradaki Prometheus (uydu görüntüsü) arasında devasa bir boşluk var. Bu boşluğu BCC (BPF Compiler Collection) ve bpftrace araçlarıyla dolduruyoruz. Bunlar, sunucuya SSH ile girdiğinizde “Şu an ne oluyor?” sorusuna anlık cevap veren araçlardır.

🛡️ Neden Güvenli? (Safety first)

Eskiden Kernel’a modül yüklemek Rus Ruleti gibiydi; hatalı bir C kodu tüm sunucuyu (“Kernel Panic”) çökertirdi. eBPF ise bir Sandbox (Kum havuzu) içinde çalışır. Yazdığınız kod önce “Verifier” tarafından taranır. Eğer kodunuz sonsuz döngüye giriyorsa veya güvenli olmayan bir belleğe erişiyorsa, Kernel bu kodu reddeder ve çalıştırmaz. Bu yüzden prodüksiyonda bpftrace çalıştırmak güvenlidir.

  • execsnoop: Sistemde o an çalışan kısa ömürlü tüm komutları gösterir. (strace ile yakalayamayacağınız kadar hızlı süreçleri yakalar).
  • biolatency: Disk gecikmelerini histogram (dağılım grafiği) olarak gösterir. “Ortalama latency iyi ama %1’lik bir kesim 1 saniye bekliyor mu?” sorusunu cevaplar.
  • opensnoop: Kim hangi dosyayı açıyor? (Config dosyamı kim kilitledi? sorusu için birebir).

🛠️ Örnek One-Liner (bpftrace):

Sistemde hangi süreçlerin en çok disk yazdığını anlık görmek için:

1
bpftrace -e 'tracepoint:block:block_rq_issue { @[comm] = count(); }'
1
bpftrace -e 'tracepoint:block:block_rq_issue { @[comm] = count(); }'

Bu araçlar, size Prometheus’un veremediği “Anlık Detayı” (High Resolution) verir.

⚠️ Ad-Hoc vs Continuous (Süreklilik) Bu komutlar siz terminal başındayken (Interactive) çalışır. Eğer bu derin Kernel metriklerini sürekli Prometheus’a basmak ve Dashboard yapmak istiyorsanız, ebpf_exporter (Cloudflare) gibi araçları CI/CD pipeline’ınıza eklemelisiniz.

🧠 6. “Unknown Unknowns” (Bilinmeyen Bilinmeyenler)

Debugging, “Bilinen Bilinmeyenleri” (Known Unknowns) çözmektir: “Web sunucusu yavaş (Bu biliniyor), ama nedenini bilmiyorum (Bu bilinmiyor).”

Observability ise “Bilinmeyen Bilinmeyenleri” (Unknown Unknowns) keşfetmektir. Siz ofiste kahvenizi içerken, hiçbir müşteri şikayeti yokken, hiçbir alarm çalmazken dashboard’a bakıp şunu diyebilmelisiniz: “Bir dakika… Neden her Salı saat 14:00’te Kernel’ın TCP Retransmission sayacı %0.5 artıyor? Müşteri fark etmiyor, latency artmıyor ama burada gizli bir ağ paket kaybı var.”

İşte bu, Staff Engineer bakış açısıdır. Yangın çıkmasını beklemez. Duman dedektörünün pilini kontrol eder. Kabloların ısınmasını fark eder. Kriz gelmeden krizi önler.

quadrantChart
    title Bilgi Matrisi
    x-axis "Bilinmiyor" --> "Biliniyor"
    y-axis "Bilinmiyor" --> "Biliniyor"
    quadrant-1 "Facts (Biliyorum)"
    quadrant-2 "Known Unknowns (Debugging)"
    quadrant-3 "Unknown Unknowns (Observability)"
    quadrant-4 "Intuition (Sezi)"
    "CPU %90": [0.8, 0.8]
    "Neden Yavaş?": [0.2, 0.8]
    "Gizli Paket Kaybı": [0.2, 0.2]

🧩 7. Vaka Analizi: Görünmez Duvara Toslamak

Gerçek bir hikaye ile parçaları birleştirelim. Bir ödeme sistemi API’si, rastgele zamanlarda (haftada 1-2 kez) “Timeout” (Zaman Aşımı) hatası veriyor. Loglarda (“Logs”) hiçbir hata yok. Exception yok. Metrics tarafında CPU %40, RAM %60. Gayet normal. Senior SRE ekibi “Debugging” modundan “Observability” moduna geçiyor.

  1. Şüpheli: Uygulama kodu mu?
    • strace (Sampling) ile bakıyorlar. Timeout anında uygulama poll çağrısında bekliyor. Yani uygulama “Ben hazırım, bana sıra gelsin” diyor. Suçlu kod değil.
  2. Şüpheli: Sistem kaynakları mı?
    • Prometheus (Metrics) verilerine detaylı bakılıyor. Timeout anlarında sunucudaki “Context Switch” sayısının fırladığı görülüyor (Saturation ilkesi).
  3. Teşhis (Derin Dalış - eBPF):
    • runqlen (BCC aracı) veya promql ile Kernel’ın CPU kuyruğu (Scheduler Queue Length) izleniyor.
    • SRE ekibi, vmstat 1 çıktısına baktığında dehşet verici bir şey görüyor:
1
2
3
procs -----------memory----------
r  b   swpd   free   buff  cache
25 0      0 120500  12000 450000 ...
1
2
3
4
5
*   **r (Running): 25!** CPU boşta (%40) görünse de, işlemciye girmek için sırada bekleyen 25 tane süreç var.
*   Prometheus sorgusu teyit ediyor: `rate(node_context_switches_total[5m])` saniyede 500'den 15.000'e fırlamış!
*   Görülüyor ki, tam o timeout anlarında sistemde binlerce minik, kısa ömürlü Cron job (Monitor scriptleri, yedekleme ajanları) aynı anda çalışıyor. 4.  **Sonuç (Quantifiable Impact):**
*   Ödeme uygulaması CPU'da çalışmak istiyor ama sırada (Run Queue) o kadar çok minik süreç var ki, Kernel sıra ona gelene kadar 50 milisaniye (Scheduling Latency) geçiyor.
*   Uygulamanın timeout süresi çok düşük olduğu için bu gecikme hataya dönüşüyor.

📚 Teknik Sözlük: Scheduler Latency ve Context Switch Maliyeti

Koddaki function_A() süresi değildir. Sürecin “Ben hazırım!” (Runnable) dediği an ile, CPU’nun “Tamam sıra sende, buyur” (Running) dediği an arasında geçen “Bekleme Süresi”dir.

🏃‍♂️ Analoji: Masayı Topla/Kur Maliyeti

“Context Switch” bedava değildir. İşlemci her görev değiştirdiğinde, o anki işin tüm defterlerini, kalemlerini (Register, Cache) kaldırıp, yeni işin malzemelerini masaya koymalıdır. Saniyede 15.000 kere masa toplayıp kurarsanız, aslında hiç iş yapamazsınız. CPU %40 görünür ama o %40’ın çoğu “masa toplamakla” (Kernel Overhead) geçer.

graph LR
    subgraph HappyPath ["Normal Durum"]
        A1["Task A Çalısıyor"] -->|Switch| B1["Task B Çalışıyor"]
    end

    subgraph OverheadHell ["Yüksek Context Switch"]
        A2["Task A"] -->|Stop| Save["💾 Masayı Topla (Overhead)"]
        Save --> Load["📂 Masayı Kur (Overhead)"]
        Load -->|Start| B2["Task B"]
    end
    
    style HappyPath stroke:#4caf50,stroke-width:2px
    style OverheadHell stroke:#f44336,stroke-width:2px

Çözüm: Sorun, kaynaktan ziyade “Kaynak Paylaşımı” (Resource Scheduling) sorunuydu. Linux Kernel’a (Scheduler) ödeme servisinin torpilli olduğunu anlatmamız gerekiyordu. Bunu systemd ve cgroups v2 kullanarak, “Production Mühendisliği”ne yaraşır şekilde çözdük:

1
2
3
4
5
6
# /etc/systemd/system/payment-api.service.d/override.conf
[Service]
# Varsayılan değer 100'dür. 1000 yaparak bu servise 10 kat öncelik verdik.
CPUWeight=1000
# Disk I/O önceliğini de artırdık.
IOWeight=1000

Not: Eski cgroups v1’de bu CPUShares idi, v2 ile CPUWeight oldu.

⚖️ Nasıl Çalışır? (Piyango Bileti Mantığı)

CPUWeight, servise “Özel Rezervasyon” (Örn: %50 CPU) yapmaz. Sadece Kavga Anında (Contention) kimin kazanacağını belirler.

  • Diğer servislerde 100 bilet var.
  • Bizim serviste 1000 bilet var.
  • CPU için sıra kavgası çıkarsa, Scheduler torbadan rastgele bilet çeker. Bizim kazanma şansımız 10 kat daha fazladır. Ama ortada kavga yoksa, kimsenin hakkını yemeyiz.

📚 Teknik Sözlük: Resource Contention (Kaynak Çekişmesi)

İki çocuğun tek bir oyuncak için kavga etmesidir. Bilgisayarda da CPU tek bir oyuncaktır. 100 program aynı anda çalışmak isterse, Kernel araya girip “Sırayla!” demek zorundadır. Bu kavga sırasında geçen boşa zamana “Overhead” denir.

📉 Etki Analizi:

Bu 4 satırlık konfigürasyon değişikliğinden sonra;

  • vmstat Running Queue (r): 25 -> 2 seviyesine düştü.
  • Context Switch Rate: 15.000/s -> 1.200/s (Ödeme servisi artık CPU için kavga etmiyor).
  • API P99 Latency: 5 saniyeden -> 200 ms‘ye çivilendi (Jitter yok oldu).

Görsel Kanıt:

xychart-beta
    title "Latency vs Context Switch İlişkisi"
    x-axis ["09:00", "09:05", "09:10", "09:15", "09:20"]
    y-axis "Değer Skalası" 0 --> 16000
    line [150, 200, 4800, 250, 200]
    bar [1000, 1200, 15000, 1100, 1000]

(Çizgi: Latency, Sütun: Context Switch Sayısı. Korelasyonu görüyor musunuz?)

İşte mühendislik budur. “Sanırım düzeldi” demek değil, sayılarla ve konfigürasyonla konuşmaktır.

Bu sorunu tail -f error.log yaparak veya Java kodunu debug ederek ASLA bulamazdınız. Sisteme, Kernel Scheduler’a ve Scheduler Latency kavramına hakim olarak buldunuz.

graph BT
    L1["Donanım / Kernel"]
    L2["Sistem Metrikleri (USE)"]
    L3["Uygulama / Servisler (RED)"]
    L4["Kullanıcı Deneyimi / İş Değeri"]
    
    L1 --> L2
    L2 --> L3
    L3 --> L4
    
    style L1 stroke:#607d8b,stroke-width:2px
    style L4 stroke:#ff9800,stroke-width:2px

👋 8. Son Söz: Linux Senin Takım Arkadaşın

Bu blog serisini buraya kadar okuduysanız, tebrik ederim. Artık Linux terminaline baktığınızda sadece yanıp sönen bir imleç veya siyah bir ekran görmüyorsunuz. Arka planda dönen devasa dişlileri, akan nehirleri (Streams), bekleyen dosya tanımlayıcılarını (FD), birbirine fısıldayan sinyalleri (Signals) ve her şeyi kaydeden o muazzam muhasebeciyi (Kernel) görüyorsunuz.

Linux, korkulacak, ezberlenecek komutlardan oluşan bir kara kutu değildir. Verdiği o soğuk hatalar (ENOENT, EACCES, EPIPE, OOM Killed) sizi engellemek için değil, size yol göstermek için oradadır. Hata mesajları, Kernel’ın “Bak burada bir şeyler ters gidiyor” deme şeklidir.

Artık:

  • strace ile o fısıltıları duyabilirsiniz.
  • ltrace ile kelimeleri anlayabilirsiniz.
  • perf ve eBPF ile o çığlık atılmadan önce hissedebilirsiniz.
  • Ve Observability zihniyetiyle, tüm bu seslerden anlamlı bir senfoni çıkarabilirsiniz.

Sistem mühendisliği (veya SRE/DevOps), sadece araçları bilmek değildir. Araçları kullanarak, kaosun içinde bir düzen (Pattern) bulma sanatıdır. Verinin içindeki hikayeyi okuma sanatıdır.

Yolculuğunuz burada bitmiyor. Aslında yeni başlıyor. Artık Root yetkisine sadece dosya sisteminde (sudo) değil, zihinsel olarak da sahipsiniz.

Kazasız belasız deploy’lar, yüksek uptime’lar, düşük latency’ler ve bol “Insight”lı günler dilerim. Hoşçakalın.

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