İçeriğe Atla
Mustafa Erbay
Teknoloji İnsan tarafından yazıldı Production Diaries · 9 dk okuma · görüntülenme Read in English
100%

İlk OOM: kcompactd %92 CPU, sshd Reset, Hard Reboot

VPS'imde RAM tükendi, swap doldu, sshd connection reset etti. Astro build OOM'u tetikleyince katmanlı pipeline savunmasını kurmaya karar verdim.

İlk OOM: kcompactd %92 CPU, sshd Reset, Hard Reboot — yaşanmış hikaye kapak görseli

“site açılmıyor” mesajıyla başladı

Sabah 08:00 sıralarında telefonuma bir mesaj geldi: “siteler düzeldi mi dostum? açılmıyor.”

mustafaerbay.com.tr açıyorum — 8 saniye timeout. Aynı VPS’teki diğer uygulamalar — aynısı. Bu ilk değil, ama bu kadar derin ilk.

Diagnostic akışı: SSH çalışıyor ama bekliyor

İlk SSH:

$ ssh vps
[5 saniye bekledi]
$ uptime
 05:27:24 up 9 days,  7:51,  3 users,
 load average: 52.51, 76.02, 70.66

Load 52, 76, 70. Sağlıklı bir sistemde 4 olur. Bu cehennem.

free -h:

               total        used        free      shared  buff/cache   available
Mem:           7.6Gi       7.5Gi       122Mi       147Mi       330Mi        76Mi
Swap:          4.0Gi       3.9Gi       106Mi

7.6 GB RAM’in tamamı kullanılıyor. 76 MB available. Swap dolu, 106 MB serbest. Sistem normalden 4-5 katı yavaş çalışıyor çünkü her memory allocation swap’a düşüyor.

Hangi process’ler bu fistirmayı yapıyor? ps aux --sort=-%cpu:

USER         PID %CPU %MEM    COMMAND
root          54 92.9  0.0    kcompactd0  ← BURADA
ubuntu    382248 24.4 32.3    node ... astro build --out-dir dist-new
root      383691 26.4  7.0    node ... next build
github-+  379827  4.4  0.9    Runner.Worker spawnclient

kcompactd0 %92 CPU. Bu benim için yeni bir tanışma. Linux memory subsystem’inin “memory compaction” daemon’u — kernel RAM fragmente, contiguous block bulamıyorum durumunda devreye giriyor, küçük free chunk’ları biraraya getirmeye çalışıyor. Onun %92 CPU yiyor olması, sistemin çoğu CPU’sunu memory aramaya harcadığı demek.

Ve sebebi de görüyorum: aynı anda Astro build (2.5 GB) ve Next.js build (615 MB) koşuyor. Toplam ~3 GB tek başına. Geri kalan 4 GB sistem servisi + container’lar + sshd. Toplam talep > 7.6 GB → swap → swap dolu → kcompactd panik.

Sites neden timeout?

free -h ile RAM 76 MB free olduğunu görmüştüm. sshd bağlandığında “fork(2)” yapıyor, child process’e response vermek için. fork RAM ister. RAM’de deli gibi swap thrashing var, fork bekliyor → connection reset by peer.

Curl benzer hikayeyle yarı kuruyor:

$ curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" --max-time 8 https://mustafaerbay.com.tr
000 8.006s

Nginx bağlandı (port 443 açık), proxy_pass’i Node app’e yapacak (127.0.0.1:3040), Node app cevap veremiyor (RAM yok). Timeout.

Kim yaptı bu Astro build’i?

$ ps -p 382248 -o pid,user,cmd
    PID USER     CMD
 382248 ubuntu   node /opt/mustafaerbay/node_modules/.bin/astro build --out-dir dist-new

ubuntu user, /opt/mustafaerbay/dist-new çıktı. Bu update.sh deploy script’ime ait. Yani ben tetikledim — git push yaptım, VPS deploy timer pull etti, build başladı.

Ne süredir koşuyor? 18+ dakika. Normal Astro build 4-5 dakika. Stuck. Memory pressure altında her step yavaşlıyor, asıl olan bitemiyor.

Çözüm yok, hard reset

gh run cancel denedim — ulaşmadı (sinyal RAM thrashing altında delivery edilmiyor). kill 382248 ssh’ım çoğu zaman tutmuyordu. OOM killer da yetişmiyordu çünkü kendi de memory ister, sistem o kadar şişti ki kernel yavaş çalışıyor.

Tek çare kaldı: hostingerime gir, hard reset bas. 90 saniye sonra geri geldi:

$ ssh vps 'uptime; free -h | head -2'
 05:38:07 up 0 min,  2 users,  load average: 2.74, 0.58, 0.19
               total        used        free      shared  buff/cache   available
Mem:           7.6Gi       1.4Gi       4.9Gi        83Mi       1.6Gi       6.1Gi

6.1 GB available. Tüm container’lar restart: unless-stopped ile auto-start oldu. Postgres’ler WAL ile recover etti. Sites 200 dönüyordu.

Şimdi: bunun bir daha olmaması için

İlk gece çalışmaya başladım. Tek refleks “build daha az kullansın” yetmez — bu defansif olur. Önleyici olmalıyım. Birkaç katman lazım.

1. Pre-flight resource guard (workflow)

- name: Pre-flight resource check
  id: preflight
  run: |
    AVAIL_GB=$(df -BG / | tail -1 | awk '{print $4}' | tr -d 'G')
    LOAD=$(awk '{print $1}' /proc/loadavg)
    LOAD_INT=${LOAD%.*}
    MEM_AVAIL_MB=$(awk '/MemAvailable/{print int($2/1024)}' /proc/meminfo)

    if [ "$AVAIL_GB" -lt 5 ] || [ "$LOAD_INT" -gt 8 ] || [ "$MEM_AVAIL_MB" -lt 1500 ]; then
      echo "skip=1" >> "$GITHUB_OUTPUT"
      echo "::warning::skipping — kaynaklar yetersiz"
    fi

Workflow başlamadan önce VPS’in nefes alıp almadığını kontrol et. Yoksa graceful skip → success exit, mail spam yok.

2. Polling-wait yerine sleep 360

Önceden workflow’da sleep 360 (6 dk) vardı, deploy bitmesini beklemek için. Sleep aktif RAM kullanmaz ama runner slot’unu işgal eder. Eğer build sırasında OOM olursa sleep step’i SIGKILL alır → workflow fail → mail.

Yeni:

for i in $(seq 1 108); do
  if curl -fsS -o /dev/null --max-time 5 "$URL"; then
    echo "Deploy ${i}. denemede algılandı"
    exit 0
  fi
  sleep 5
done

URL polling. Site live olur olmaz ilerle. Sleep yerine kısa intervaller — OOM-killable durumlar için resilient.

3. AI quirk auto-fixer

Önceki gün üç farklı AI quirk yüzünden cron’lar fail olmuştu. Hepsini “reject yerine fix” stratejisiyle tek bir normalizer’da topladım. Bunu daha önce yazmıştım, ama ilgili: fail-soft mantalitesi her tarafta.

4. Pipeline-health monitor

Bu en önemli olabilir. /var/lib/mustafaerbay/health-state file’ı tutuyor son durumu (healthy / degraded). Cron 4 saatte bir bakıyor son Bluesky paylaşımına. 4+ saat içinde paylaşım yoksa state-change = ilk DEGRADED maili. Sonra 4 saatte bir kontrol ediyor, paylaşım dönerse RECOVERED maili. Aynı state’te 100 cron koşsa bile mail yok.

Bu sabahki olayda 16 cron arka arkaya başarısız olmuştu, sadece 1 mail geldi. Klasik “her workflow run mail at” dünyasında 16 mail gelirdi.

Daha derin ders

Bu OOM’u yaşamamış olsam katmanlı savunmayı kurmazdım. Bir kere yaşamak gerekti — böyle olabilir dedirten somut deneyim. Şimdi her cron başında pre-flight, build wait yerine polling, AI çıktı normalizer, state-change alert.

Bunların hiçbiri OOM’u tek başına engellemez. Birlikte engellerler. Klasik Swiss cheese model:

[OOM gerçekleşiyor] →
  layer 1: pre-flight skip ediyor (kaynaklar zaten yetersiz görüldü)
  → layer 2: polling-wait OOM-resilient
  → layer 3: auto-fixer AI quirk'lere takılmıyor
  → layer 4: pipeline-health monitor sadece state-change'de uyarıyor
  → result: yarı saatte 1 cron skip, mail yok, sistem sağlıklı

Tek bir defans olsa bir gün delik bulurdu. Dört delikli peynir sıralı, hizalanmıyor → top geçemez.

Sonuç

Bu OOM’a hazırlıksız yakalandım. Ama post-mortem ile dört katmanlı bir pipeline reliability sistemi kurmak gibi düşününce iyi oldu demek lazım. Kötü gün değer üretebilir — eğer yazıya dökersen.

Bir sonraki cron 30 dakika sonra koşacak. Pre-flight kontrol ediyor olacak. RAM hâlâ 5 GB’tan az ise skip diyecek. Ben artık endişelenmiyorum çünkü bu sistemi gördüm — pipeline kendi başına devam ediyor.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Haftalık özet — AI değil, bizzat ben seçiyorum

Haftada bir mail: o haftanın en önemli yazısı, perde arkası notları, ve "bu hafta gerçekten kullandığım araç" bölümü. Az gürültü, çok sinyal.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar