Şimdi yükleniyor

Kubernetes v1.36 Memory QoS: Katmanlı Bellek Koruması Geldi

Kubernetes v1.36 Memory QoS: Katmanlı Bellek Koruması Geldi

Geçen hafta bir e-ticaret müşterimizin AKS cluster’ında garip bir şey öldü. Black Friday hazırlığı için kapasiteyi yokluyorduk, node’lardan biri inatla sistem-wide OOM kill yiyor, ama işin can sıkıcı tarafı şu: Pod’ların hiçbiri limit’ını aşmıyordu. Sebep neydi? Burstable Pod’ların toplam request’i node belleğinin neredeyse %85’ine dayanmıştı. Eski Memory QoS davranışı yüzünden bu bellek memory.min gibi kenara ayrılmıştı; yanı kernel’e resmen sıkışacak yer kalmamıştı.

Peki neden önemli? Çünkü v1.36 ile gelen yenilikler tam da bu tip senaryolara biraz olsun fren oluyor. Hani uzun süredir ortada dolaşan o Memory QoS meselesi var ya, 2021’den beri (v1.22) alpha’da oyalanıp duran, açınca “acaba neyi etkiliyor” diye insanı düşündüren feature gate; işte şimdi daha kullanılabilir bir hâle geliyor, en azından kağıt üstünde değil, pratikte de fena durmuyor diyebilirim.

Önce şu cgroup v2 meselesini bir hatırlayalım

Linux kernel tarafında bellek işi, cgroup v2 ile baya toparlandı. Kısa konu bu. Memory QoS’in omurgasını da üç parametre taşıyor; hani biri sert koruma, biri yumuşak koruma, biri de frene basma noktası gibi düşünebilirsiniz (ilk bakışta karışık geliyor ama aslında mantık oturuyor).

  • memory.min: Sert garanti. Kernel bu belleği asla geri almıyor. Sistem genelinde OOM patlarsa bile bu pod korunuyor, başkaları gidiyor.
  • memory.low: Yumuşak koruma. Normal baskıda korunuyor ama “ya sen ya sistem” noktasına gelince kernel bu alanı geri alabiliyor.
  • memory.high: Throttling sınırı. Bu eşiği aşınca kernel agresif bellek geri kazanımına giriyor — pod yavaşlıyor, ama OOM’a yuvarlanmıyor.

Bunu bilmek önemli. Çünkü v1.36’nın getirdiği “katmanlı koruma” dediğimiz şey, tam olarak bu üç parametreyi QoS sınıflarına eşlemekten ibaret (yanı işin sihri başka yerde değil).

İtiraf edeyim, Evet.

Peki neden?

Çünkü Kubernetes tarafında güzel görünen QoS sınıfları var diye iş bitmiyor; asıl mesele, node sıkıştığında hangi pod’un ne kadar dayanacağını kernel seviyesinde belirlemek. Tahmin eder mısınız? Az önce anlattığım eşleşme de bunu yapıyor, ama dur bir saniye — her ortamda aynı sonucu vermiyor, bazı yüklerde gayet iyi çalışırken bazılarında beklediğiniz kadar nazik davranmayabiliyor.

Ne yalan söyleyeyim, Neyse, çok dağıtmadan şunu söyleyeyim: cgroup v2’yi anlamadan Memory QoS’e bakarsanız tablo biraz eksik kalır. Yukarıda bahsettiğim o olay var ya, işte bütün oyun orada dönüyor.

v1.36’da Tam Olarak Ne Değişti?

En can alıcı fark şu: throttling ile rezervasyon artık ayrıldı. Önceden MemoryQoS feature gate’ını açınca işler biraz topyekûn başlıyordu; memory request’i olan her container otomatik olarak memory.min alıyordu. v1.27’de durum buydu ve açık konuşayım, production tarafında insanın içini rahatlatan bir tablo değildi.

Şimdi kubelet tarafında yeni bir config alanı var: memoryReservationPolicy. İki seçenek sunuyor, yanı olay aslında burada dallanıyor: (yanlış duymadınız)

None (varsayılan)

Bu modda sadece memory.high devreye giriyor, başka da bir şey yazılmıyor. Kubelet, memoryThrottlingFactor (varsayılan 0.9) üzerinden hesabı yapıyor; memory.min ve memory.low işe hiç dokunulmadan kalıyor. Yanı önce throttling’i bir deneyip, sonra workload’larınızı sakın sakın izleyebiliyorsunuz.

TieredReservation

Bak şimdi, işin asıl ilginç kısmı burada. Kubelet, Pod’un QoS sınıfına göre farklı koruma katmanları uyguluyor; yanı herkes aynı sepete girmiyor, ihtiyaç ve sınıfa göre ayrı davranıyor, bu da pratikte baya iş görüyor gibi dürüyor:

QoS Sınıfı Yazılan Parametre Davranış
Guaranteed memory.min Sert koruma — asla geri alınmaz
Burstable memory.low Yumuşak koruma — normal baskıda korunur
BestEffort Hiçbiri Tamamen geri alınabilir

512 MiB bellek isteyen bir Guaranteed Pod için cgroup’a şöyle bir şey yazılıyor:

$ cat /sys/fs/cgroup/kubepods.slice/kubepods-pod[uid].slice/memory.min
536870912

Aynı isteği Burstable Pod yaparsa, değer gidip aynı dosyaya değil memory.low‘a yazılıyor (yanlış duymadınız). Fark gerçekten ciddi; biri beton gibi sert dürüyor, diğeri işe baskı artınca biraz esneyen bir kalkan gibi davranıyor. Evet, tam mesele bu.

Eski Davranışla Karşılaştırma: Neden Önemli?

Yukarıda anlattığım e-ticaret müşterisinin hikayesine geri döneyim. 8 GiB RAM’li bir node düşünün; üstünde toplam 7 GiB request yapan Burstable Pod’lar var. Kâğıt üstünde idare eder gibi dürüyor, ama pratikte işler öyle yürümüyor.

Eski davranışta (v1.27), o 7 GiB’in tamamı memory.min olarak kilitleniyordu. Kernel, sistem daemon’ları, kubelet’in kendisi, hiçbir şey bu belleğe dokunamıyordu. Geriye 1 GiB kalıyor; DaemonSet’ler, container runtime, sistem servisleri… Sız ne dersiniz? Bu kadar dar alanda en ufak spike bile sistemi duvara toslatabiliyordu, bizde de olan tam olarak buydu.

Araya gireyim: v1.36’da TieredReservation ile iş biraz değişiyor. Aynı 7 GiB artık memory.low‘a yazılıyor. Normal koşullarda kernel yine bu belleği koruyor, yanı Pod’lar performans kaybı yaşamıyor. Ama sistem genelinde kilit bir baskı oluştuğunda kernel bu rahatlığı bozup belleğin bir kısmını geri alabiliyor; sonuçta sistem-wide OOM riski ciddi biçimde azalıyor. Açık konuşayım, farkı burada hissediyorsunuz.

Kısa bir not düşeyim buraya.

Sadece Guaranteed Pod’lar gerçekten memory.min kullanıyor artık. Bu da sert rezervasyon miktarını node genelinde baya düşürüyor. Bence bu, özelliğin GA’ya gidişindeki en kritik tasarım kararı.

Gözlemlenebilirlik: Sonunda Metrikler Var

Bu işin en can sıkıcı tarafı şuydu: ne olup bittiğini görmek neredeyse yok gibiydi. Cgroup dosyalarını cat‘leyip Excel’de elle izleyen müşterilerim bile öldü, evet gerçekten (bir bankacılık projesinde, Ankara’da yaşadım bunu). Bak şimdi, v1.36 ile kubelet’in /metrics endpoint’ine iki tane yeni alpha metrik eklenmiş:

  • kubelet_memory_qos_node_memory_min_bytes — node üzerindeki toplam memory.min rezervasyonu
  • kubelet_memory_qos_node_memory_low_bytes — node üzerindeki toplam memory.low rezervasyonu

Bu iki metriği Prometheus’a çekip Grafana’da node kapasitesiyle yan yana koyarsanız, “ben ne kadarını ayırdım, geriye ne kaldı” sorusuna finally değil ama baya yakın bir cevap alıyorsunuz. Hani eski durumda tahmin yürütüyorduk ya, işte o kısım biraz toparlanıyor. Az şey değil.

Peki neden?

Kernel Sürümü Uyarısı: Dikkat Edin

Bu kısmı geçmeyin, sonra can sıkıyor. memory.high davranışı kernel sürümüne göre değişiyor; eski 5.x çekirdeklerinde bu iş bazen fazla sert vuruyor, Pod neredeyse nefes alamaz hâle geliyor (özellikle de yük artınca), v1.36 kubelet de artık node’un kernel sürümüne bakıp log’a uyarı bırakıyor.

Şunu söyleyeyim, Pratik tarafta ben şöyle bakıyorum: Production’da Memory QoS’i açmadan önce kernel 5.15 ya da üstünü garanti edin, yoksa iş biraz şansa kalıyor. Ubuntu 22.04+ veya RHEL 9.x tarafında genelde sorun çıkmıyor, ama hâlâ Ubuntu 20.04 ile node döndürenler varsa (evet, Türkiye’de bunu epey görüyorum), önce OS upgrade’i çözmek daha akıllıca olur. Teams Agent Kurulumu Artık Tek Komutla Tamam yazımızda bu konuya da değinmiştik.

Türkiye’deki Kurumsal Yapıda Bu Ne Anlama Geliyor?

İnanın, Burası kritik. Müşterilerde gördüğüm tablo şu: Türkiye’de Kubernetes’e geçiş çoğu zaman biraz “lift and shift” kafasıyla ilerliyor. Yanı VM döneminden kalan alışkanlıklar sürüyor, request. Limit değerleri de ona göre şişiriliyor — hani “bir ihtimal lazım olur” diye. Sonuç da pek şaşırtmıyor; node’lar gereğinden fazla yük alıyor ama workload’lar yine de Burstable QoS tarafında kalıyor.

Durun, bir saniye. Bu konuyla ilgili GPT-5.5 ve Microsoft Foundry: Kurumsal AI Artık Ciddi yazımıza da göz atmanızı tavsiye ederim.

Garip gelecek ama, Bu profil, eski Memory QoS davranışıyla pek iyi anlaşmıyordu. Açtığınız anda node’lar sıkışmaya başlıyordu, hatta bazen nefes bile alamıyordu (evet, doğru duydunuz). v1.36 ile gelen TieredReservation işe tam bu noktada daha mantıklı dürüyor; Burstable workload’lar memory.low üzerinden esnek bir koruma alıyor, sistem de daha rahat toparlanıyor.

Size bir şey söyleyeyim, Bir de FinOps tarafı var tabiî. Doğru kullanıldığında Memory QoS, node utilization’ı %20-30 civarında artırabiliyor. Çünkü ortada artık “ya lazım olursa” diye kenarda bekletilen bellek yerine, kernel’in işi biraz daha akıllıca paylaştırdığı bir yapı var. Azure’da D-serisi node’ları düşününce TL hesabı da hemen kendini gösteriyor — mesela 10 node’lük bir cluster’da 2-3 node azaltmak, ay sonunda hiç fena olmayan bir tasarruf çıkarabiliyor. Hesabı sız yapın.

Pratik Uygulama: Nereden Başlamalı?

Şimdi işin pratik tarafına geçelim. Bu özelliği bugün yoklamak istiyorsanız, ben olsam önce lab ortamında denerim; production’a dalmak biraz acele olur, alpha bir özellik için hele hiç olmaz. Service Bus Batch İşlemede Mesaj Bazlı Settlement Devrimi yazımızda bu konuya da değinmiştik.

  1. Önce dev/staging cluster’ında deneyin. Alpha bir feature, production’a koşmayın.
  2. Kernel sürümünü doğrulayın — en az 5.15 hedefleyin.
  3. Cgroup v2 zorunlu. Hâlâ v1’deyseniz önce o işi halledin (containerd 1.7+ ve uygun systemd config gerekiyor).
  4. Feature gate’i açın: kubelet’e --feature-gates=MemoryQoS=true ekleyin.
  5. İlk olarak memoryReservationPolicy: None ile başlayın. Sadece throttling’i izleyin.
  6. Bir-iki hafta gözlem yapın. memory.high throttling’i pod’larınızı boğuyor mu? Latency artışı var mı?
  7. Sorun yoksa TieredReservation‘a geçin. Yeni metriklerle node kapasitesini izleyin.

Peki neden böyle başlıyoruz? Çünkü burada asıl mesele, özelliği açtım öldü demek değil; davranışı sakın sakın görmek (özellikle latency ve throttling tarafında), sonra da node kapasitesini yanlış okumadığınızdan emin olmak. Daha fazla bilgi için Gateway API v1.5: Altı Özellik Stable Oldu, Ne Değişiyor? yazımıza bakabilirsiniz.

💡 Bilgi: Eğer Kubernetes güvenlik tarafına ilgi duyuyorsanız, aynı sürümle gelen Kubernetes v1.36 User Namespaces GA: Root Artık Gerçek Root Değil yazımı da okumanızı öneririm. v1.36, sadece bellek değil pod izolasyonu açısından da önemli adımlar atıyor.

Neyse, biraz dağıldım ama konuya dönelim. Yukarıdaki yazıda anlattığım kullanıcı namespace değişikliğiyle bu MemoryQoS konusu yan yana düşünülünce tablo daha net oluyor; biri yetki sınırını sıkılaştırıyor, diğeri de belleği daha kontrollü kullanmaya zorluyor, yanı ikisi birlikte cluster davranışını baya etkiliyor (ben de ilk duyduğumda şaşırmıştım)

Evet.

Kısacası, küçükten başlayın ve ölçerek ilerleyin. Bir anda her şeyi açıp sonra “neden node nefes alamıyor” diye bakmak yerine, önce gözlem yapın; açık konuşayım, bu yaklaşım çoğu zaman daha az baş ağrıtır.

Küçük vs Büyük Ekipler İçin Tavsiyeler

Küçük ekip / Startup

Küçük bir detay: Açık konuşayım, bu özelliği şimdilik kenara koyun. Alpha feature’larla boğuşmak yerine düzgün resource request/limit yazmaya odaklanın; AKS’in default davranışı da çoğu zaman iş görüyor, hatta çoğu startup için ekstra bir şey kurmadan önce asıl mesele zaten orada yatıyor. Eğer node’larınız OOM yiyorsa, sebep büyük ihtimalle Memory QoS değil. Yanlış sizing’dır. Önce önü düzeltin. Bu konuyla ilgili Cosmos DB Azure RBAC Entegrasyonu: İki Dünya Birleşiyor yazımıza da göz atmanızı tavsiye ederim.

Enterprise / Büyük cluster operatörü

Burada iş biraz değişiyor. 50+ node’lük cluster’larda, multi-tenant workload’larda Memory QoS baya işe yarayabiliyor; özellikle de “noisy neighbor” derdi yaşayan platform ekipleri için bu konu masaya gelmeli, çünkü aynı node üzerinde birbirinin ayağına basan işler olunca standart ayarlar bazen idare eder ama yetmez. Ben kendi danışmanlık projelerimde 100+ node’lu cluster’larda PoC yapmaya başladım bile. İlk geri bildirimler fena değil — özellikle memory.low‘un Burstable workload’lar için yumuşak koruma sağlaması, ekiplerin gözüne girdi.

Eksik Tarafları da Konuşalım

Şimdi işin diğer yüzü. Bu özellik hâlâ alpha, ve açık konuşayım, beni biraz soğutan birkaç detay var.

Birincisi şu: Pod-level QoS ayarı yok (şaşırtıcı ama gerçek). Yanı namespace bazında ya da Pod annotation ile “bu workload’a memory.low yerine memory.min ver” diyemiyorsunuz; her şey gidip QoS sınıfına bağlanıyor, bu da pratikte biraz dar bir alan bırakıyor. Halbuki gerçek hayatta “Burstable ama kritik” dediğimiz işler çıkıyor, mesela bir order-processing servisi gibi.

İkincisi, swap tarafı hâlâ biraz karışık. v1.30 ile gelen swap desteği var ama Memory QoS bununla nasıl davranacak, dökümantasyonda bence yeterince net değil; test ortamında kurcaladığımda sonuçlar da tam tahmin ettiğim gibi çıkmadı, hatta birkaç yerde şaşırdım açıkçası.

Üçüncüsü işe daha net: Windows node tarafında yok. Linux-only bir feature olduğu için hibrit cluster çalıştıranlar açısından deneyim biraz yamalı dürüyor.

Sıkça Sorulan Sorular

Memory QoS’i production’da açayım mı?

Açıkçası, hâlâ alpha aşamasında olduğu için net bir “evet” diyemem. Ama dev/staging ortamında muhtemelen bir deneyin — bence çok şey öğreniyorsunuz o süreçte. Beta’ya geçince, yanı muhtemelen v1.38 ya da v1.39’da, production’a kontrollü şekilde alabilirsiniz. Acelesi yok. Throttling sorunu yaşamıyorsanız beklemek en mantıklısı.

cgroup v1 ile çalışıyor mu?

Burada, küçük bir detay: Hayır, çalışmıyor. Memory QoS tamamen cgroup v2’nın memory controller özelliklerine dayanıyor, yanı v1 ile işinizi göremezsiniz. Hâlâ cgroup v1 kullanıyorsanız önce o geçişi halletmeniz lazım. Neyse ki modern container runtime’lar, hani containerd 1.7+ veya CRI-O 1.25+ gibi, cgroup v2’yi zaten destekliyor.

Kısa bir not düşeyim buraya.

memory.high throttling Pod’umu yavaşlatır mı?

Evet, eşiği geçince yavaşlatıyor. Varsayılan memoryThrottlingFactor değeri 0.9, yanı limit’in %90’ına gelince throttling devreye giriyor. Mesela real-time ödeme sistemi gibi latency-sensitive bir şey çalıştırıyorsanız bu factor’ü 0.95’e çekmeyi düşünebilirsiniz. Ya da — tecrübeme göre daha temiz çözüm — o workload’ları direkt Guaranteed QoS’e taşıyın.

AKS, EKS, GKE’de bu özellik var mı?

v1.36 daha çok yeni ve managed servislerde alpha feature’lar genelde varsayılan olarak kapalı geliyor. AKS’te custom kubelet config ile açabilirsiniz ama açıkçası dikkatli olun — Microsoft’un desteği olmadan bir sorun çıkarsa zor durumda kalabilirsiniz. EKS ve GKE de aşağı yukarı aynı durumda.

Burstable bir Pod’a Guaranteed gibi sert koruma verebilir mıyım?

Aslında, Şu an v1.36’da bunu yapmanın bir yolu yok. Tek seçenek Pod’u Guaranteed QoS sınıfına taşımak, hani request ve limit değerlerini eşitlemek. Bu da aslında bellek esnekliğinizden vazgeçmek demek oluyor. Topluluk granular kontrol için RFC tartışıyor ama bence yakın zamanda bir şey gelmesini beklemeyin.

Kaynaklar ve İleri Okuma

Kubernetes v1.36: Tiered Memory Protection with Memory QoS — Resmî Blog

Kubernetes Pod QoS Sınıfları — Resmî Dokümantasyon

Yanı, Linux Kernel cgroup v2 Memory Controller Dokümantasyonu

Yanı, KEP-2570: Memory QoS Enhancement Proposal (GitHub)

İçeriği paylaş:

Aşkın KILIÇ

20+ yıl deneyimli Azure Solutions Architect. Microsoft sertifikalı bulut mimari ve DevOps danışmanı. Azure, yapay zekâ ve bulut teknolojileri üzerine Türkçe teknik içerikler üretiyor.

AZ-305AZ-104AZ-500AZ-400DP-203AI-102

Bu içerik işinize yaradı mı?

Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.

Haftalık Bülten

Her pazar özenle seçilmiş teknoloji yazıları doğrudan e-postanıza gelsin.

Yorum gönder

Microsoft Azure Çözüm Uzmanı | Bulut Bilişim, Yapay Zekâ, DevOps ve Kurumsal Güvenlik alanlarında 15+ yıl deneyim. Azure, Kubernetes, AI/ML ve modern altyapı mimarileri üzerine yazılar yazıyorum.

Haftalık Bülten

Azure, DevOps ve Yapay Zeka dünyasındaki en güncel içerikleri her hafta doğrudan e-postanıza alın.

Spam yok. İstediğiniz zaman iptal edebilirsiniz.
📱
Uygulamayı Yükle Ana ekrana ekle, çevrimdışı oku
Paylaş
İçindekiler
    ← Cosmos DB Azure RBAC Entegrasy...
    📩

    Gitmeden önce!

    Her pazar özenle seçilmiş teknoloji yazıları ve AI haberleri doğrudan e-postanıza gelsin. Ücretsiz, spam yok.

    🔒 Bilgileriniz güvende. İstediğiniz zaman ayrılabilirsiniz.

    📬 Haftalık bülten: Teknoloji + AI haberleri
    Beni Takip Et Yeni Azure / AI / DevOps yazıları LinkedIn ve X'te ilk burada.