systemd ile işlem CPU ve bellek sınırı nasıl konur?
systemd unit dosyasında MemoryMax ve CPUQuota kullanarak kaynak kısıtlaması yapın. Servis Section başlığı eksikse systemd hatası alırsınız. OOM kill durumlarını inceleyin.
systemd drop-in dosyası ile işlem bellek ve CPU sınırlandırması
Bir Linux VPS üzerinde çalışan bir sürecin bellek ve CPU kullanımını, süreci çalıştıran unit dosyasına birkaç satır ekleyerek sınırlandırabilirsiniz. MemoryMax=, bellek üzerindeki kesin üst sınırdır. CPUQuota= ise işlemci süresi üzerindeki üst sınırdır. Her iki kısıtlama da, systemd'nin sunucudaki her servisi izlemek için halihazırda kullandığı çekirdek özelliği olan cgroup v2 (control groups, version 2) tarafından uygulanır.
sudo systemctl edit myapp.serviceBu komut, açıklama satırları içeren bir drop-in dosyası açar. Bu satırların üzerine aşağıdakileri ekleyin:
[Service]
MemoryHigh=512M
MemoryMax=768M
MemorySwapMax=0
CPUQuota=80%
TasksMax=128sudo systemctl daemon-reload
sudo systemctl restart myapp.service
systemctl show myapp.service -p MemoryHigh -p MemoryMax -p CPUQuotaPerSecUSec -p TasksMaxsystemctl show, girdiğiniz değerleri çekirdeğin kendi birimleri olan MemoryMax=805306368 ve CPUQuotaPerSecUSec=800ms cinsinden geri yansıtmalıdır. Eğer MemoryMax=infinity çıktısını alıyorsanız, drop-in dosyası yüklenmemiş demektir. Dosyanın /etc/systemd/system/myapp.service.d/override.conf yoluna kaydedildiğinden ve [Service] başlığı ile başladığından emin olun; çünkü üzerinde bir bölüm başlığı bulunmayan ayar satırları, systemd'nin Assignment outside of section. Ignoring. hatasını günlüğe kaydetmesine ve servisin hiçbir sınırlandırma olmadan başlamasına neden olur.
Bu kılavuzun geri kalanı, bu sayıların nasıl seçileceğini ve ayarlandıktan sonra nelerin hala hatalı gidebileceğini açıklamaktadır.
Kontrolsüz bir sürecin dolmadığı halde VPS'i neden dondurduğu
Bellek sınırına takılan bir süreç yaklaşık bir saniye içinde sonlanır ve servis yeniden başlatılır. Bu iyi senaryodur. Kötü senaryo ise hiçbir şeyin ölmediği durumdur: makine ping taleplerine yanıt verir, SSH bağlantıyı kabul eder ancak kabuk istemi (shell prompt) asla gelmez. Makine çalışır ve meşguldür ancak yapılan işlerin hiçbiri faydalı değildir.
Bunun mekanizması belirgin olmadığı için aşağıda açıklanmıştır. Boş bellek azaldığında, çekirdek yeni sayfalar dağıtmak yerine mevcut sayfaları geri kazanmaya çalışır. Geri kazanılması en kolay sayfalar dosya tabanlı olanlardır ve sayfa önbelleği (page cache), çalışan her şeyin yürütülebilir kodunu tutar. Bu nedenle çekirdek sshd metin sayfalarını tahliye eder ve sshd bir sonraki komutu çalıştırdığında, bu baytları depolama biriminden geri okuması gereken bir sayfa hatası (page fault) oluşur. Her süreç, çalışmak yerine diskten veri bekler hale gelir. Aynı sayfalar sürekli çıkar ve geri gelir; bu döngüye thrashing denir.
İki durum, bu sorunu bir dizüstü bilgisayara kıyasla VPS üzerinde daha kötü hale getirir. Depolama birimi genellikle ağa bağlıdır veya paylaşımlıdır, bu nedenle her hata yerel bir NVMe cihazına göre daha fazla milisaniye kaybettirir. Ayrıca çekirdek zamanı değil, başarısızlığı ölçer: geri kazanım süreci ne kadar yavaş olursa olsun bir sayfa döndürdüğü sürece, çekirdek ilerleme kaydedildiğine inanır ve out of memory (OOM) killer mekanizmasını çalıştırmaz. Bir makine, herhangi bir şey sonlandırılmadan önce bu durumda dakikalarca kalabilir.
Bunun gerçekleştiğini izleyebilirsiniz. Çekirdek, Linux 4.20 ve sonraki sürümlerde pressure stall information (PSI) verilerini dışa aktarır:
cat /proc/pressure/memory
cat /proc/pressure/iosome avg10=63.72 avg60=41.02 avg300=12.33 total=13729481
full avg10=48.15 avg60=30.44 avg300=8.90 total=9114233Önemli olan full satırıdır. full avg10=48.15, son on saniye içinde makinedeki her çalıştırılabilir görevin %48 oranında bellek işlemleri için beklediğini ve dolayısıyla hiçbir şeyin çalışmadığını ifade eder. Sağlıklı bir sunucuda full değeri sıfıra yakındır. 10'un üzerindeki değerler insan tarafından yavaş hissedilir, 40 ve üzeri ise insanların donmuş olarak tanımladığı durumdur.
Bu durum, bir sınırın tek başına bir garanti olmamasının da nedenidir. MemoryHigh= altında tutulan bir birim sonlandırılmak yerine kısıtlanır (throttled); bu nedenle canlı kalır, yavaş çalışır ve systemd açısından başarısız olmadığı için hiçbir şey onu yeniden başlatmaz. Swap yapmasına izin verilen sınırlı bir birim, o birime fatura edilen ancak paylaşımlı bir cihaz tarafından karşılanan okuma ve yazma işlemleri oluşturur; bu da makinedeki diğer tüm servisler için /proc/pressure/io değerini yükseltebilir. Sınırlar, kıtlığın bedelini kimin ödeyeceğine karar verir ancak kapasite yaratamazlar.
VPS'nizin cgroup v2 çalıştırdığını doğrulayın
stat -fc %T /sys/fs/cgroupcgroup2fs, aşağıda belirtilen tüm ayarların gerektirdiği birleşik hiyerarşidir. tmpfs, sunucunun eski v1 düzeniyle başlatıldığı anlamına gelir; bu durumda MemoryHigh= ve MemorySwapMax= mevcut değildir ve birim bazlı OOM davranışı farklılık gösterir. Ubuntu 22.04 ve sonraki sürümler ile Debian 11 ve sonraki sürümler varsayılan olarak v2 kullanır. Eski bir imaj veya systemd.unified_cgroup_hierarchy=0 parametresiyle başlatılan bir çekirdek v2 kullanmaz.
cgroup v2 üzerinde systemd, her birim için bellek takibini varsayılan olarak etkinleştirir, bu nedenle veriler halihazırda mevcuttur:
systemd-cgtop -mBu komut, cgroup'ları bellek kullanımına göre sıralayarak listeler; sunucu yanıt verebildiği sürece "bu sunucuyu ne tüketiyor" sorusuna yanıt bulmanın en hızlı yolu budur. Sunucu yeniyse, yeni bir VPS'teki ilk on dakika rehberindeki hesap ve güvenlik duvarı işlemleri bu adımdan önce gelmelidir.
MemoryHigh kısıtlaması yavaşlatır, MemoryMax ise sonlandırır.
Bu iki bellek ayarı arasındaki fark, bir hata durumunun nasıl görüneceğini belirler.
MemoryHigh=yumuşak bir sınırdır. Bu değer aşıldığında çekirdek, ilgili cgroup içindeki bellekleri agresif bir şekilde geri kazanır ve bellek tahsislerini kasıtlı olarak yavaşlatır. Kullanım bu değerin üzerine çıkabilir ve hiçbir süreç sonlandırılmaz.MemoryMax=katı bir sınırdır. Bu sınır dahilinde bir bellek tahsisi karşılanamadığında, OOM killer ilgili cgroup içinde çalışır ve o birime ait süreçlerden birini sonlandırır.
İkinci durum, tam olarak güvenmediğiniz her şey için MemoryMax= değerini ayarlamanızın asıl nedenidir. Bir sınır olmadığında, bellek yetersizliği tüm sunucuyu etkileyen bir sorun haline gelir ve global OOM killer kurbanını oom_score değerine göre seçer; bu da genellikle en büyük sürecin seçilmesi anlamına gelir. En büyük süreç genellikle sızıntı yapan betik değil, veritabanınızdır. Bir sınır olduğunda ise sonlandırma işlemi, soruna neden olan birimin içinde gerçekleşir.
Her iki ayarı da kullanın ve MemoryHigh= değerini MemoryMax= değerinin yaklaşık yüzde 20 ila 30 altında tutun. Bu boşluk bir uyarı bölgesidir: yavaş bir sızıntı High değerini aşar ve servis yavaşlaması olarak kendini gösterir; ani bir bellek artışı ise doğrudan Max değerini geçer ve servis sonlanır.
Yüzde değerleri, kurulu fiziksel belleğe göre hesaplanır; bu nedenle 4 GB'lık bir planda MemoryMax=25% değeri 1 GB'a denk gelir ve planı yükselttiğinizde sunucunun dörtte biri oranında kalmaya devam eder. MemorySwapMax=0 ayarı, ilgili birimi tamamen swap kullanımından uzak tutar; bu da uzun süreli bir yavaşlama yerine hızlı ve belirgin bir sonlandırma sağlar.
Bazı servisler, bellek ihtiyacını ölçmek yerine önceden belirlemenize olanak tanır: bir Ollama birimi, KV önbelleğini verdiğiniz bağlam penceresine (context window) göre boyutlandırır; bu nedenle bir üst sınır belirlemeden önce num_ctx değerini artırmanın RAM maliyeti konusunu inceleyin.
Bir sınır ayarı, yanında bir yeniden başlatma politikası gerektirir; aksi takdirde sonlandırma işlemi sizi durmuş bir servis ile baş başa bırakır.
[Unit]
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Restart=on-failure
RestartSec=5sStartLimit* ayarı [Unit] bölümüne, Restart= ayarı ise [Service] bölümüne aittir. Herhangi birini yanlış bölüme eklerseniz systemd bu ayarı yok sayar. Beş dakika içinde beş yeniden başlatma, anlık bir sorundan ziyade bir sızıntıya işaret eder; bu nedenle systemd bu noktadan sonra pes eder ve birimi başarısız (failed) durumda bırakır. Sorunu gizleyen bir çökme döngüsü yerine, daha sonra incelemek istediğiniz durum budur.
CPUQuota ile CPU sınırlandırma veya CPUWeight ile paylaşım
CPUQuota=, tek bir CPU üzerindeki kullanılabilir sürenin bir yüzdesini alır. CPUQuota=50%, bir çekirdeğin yarısıdır. CPUQuota=200%, iki çekirdeğe eşdeğerdir ve birim, bu gücü istediği kadar iş parçacığına (thread) yayabilir. 2 vCPU'lu bir planda, CPUQuota=200% tüm makineyi temsil eder.
CPUWeight=, çoğu servis için daha iyi bir varsayılan değerdir. 1 ile 10000 arasında değişen göreceli bir paydır ve çekirdek (kernel) varsayılanı 100'dür. Yalnızca bir kaynak çekişmesi olduğunda devreye girer: CPUWeight=20 değerindeki bir yedekleme işi, yük altında 100 değerindeki bir web sunucusuna öncelik verir, ancak sunucu boşta olduğunda tüm makineyi kullanmaya devam eder. Katı bir kota ise bu boş kapasitenin heba olmasına neden olur.
Bir CPU sınırının size ne kazandırdığı konusunda gerçekçi olun. CPU yoğunluklu bir süreç nadiren Linux'u dondurur, çünkü zamanlayıcı (scheduler) herkese işlem süresi tanımaya devam eder. Bir sunucuyu çökerten şey bellektir. Bir derleme işlemi veya aksi takdirde bir saat boyunca tam kapasite çalışacak bir aracı gibi, öngörülebilir bir tavan değerine ihtiyaç duyduğunuzda CPUQuota= seçeneğine başvurun. Bu tür bir iş yükünün boyutlandırılması ayrı bir konudur ve bir kodlama aracısı VPS'inin ne kadar RAM ve CPU'ya ihtiyaç duyduğu başlığında ele alınmıştır.
Eğer süreçlerinizden hiçbiri yoğun işlem yapmadığı halde CPU meşgul görünüyorsa, bunun nedeni hipervizörün diğer tarafında olabilir. Bu durum gürültülü komşudan kaynaklanan CPU steal time sorunudur ve belirleyeceğiniz hiçbir kota bunu değiştirmeyecektir.
TasksMax, fork döngülerini durdurur
TasksMax=, bir birimin barındırabileceği süreç ve iş parçacığı sayısıdır. İş parçacıkları da sayıma dahil edildiğinden, Java veya Go tabanlı bir servis, süreç listesinin önerdiğinden daha fazla alana ihtiyaç duyar. Bu, döngü içinde fork yapan bir betiğe karşı en düşük maliyetli korumadır; çünkü fork işlemi, sunucunun süreç kimlikleri (PID) tükenmek yerine birim içinde başarısız olur.
TasksMax=128Bir birim sınıra ulaştığında, çekirdek cgroup adını belirten bir satırı günlüğe kaydeder:
cgroup: fork rejected by pids controller in /system.slice/myapp.serviceProgramın kendisi genellikle fork: retry: Resource temporarily unavailable hatası verir. Yöneticinin varsayılan olarak ne uyguladığını systemctl show -p DefaultTasksMax ile kontrol edin.
systemd-run ile tek seferlik işleri sınırlandırma
Bunun için bir unit dosyasına ihtiyacınız yoktur. systemd-run, tek bir komut etrafında geçici bir yapı oluşturur.
sudo systemd-run --scope -p MemoryMax=1G -p MemorySwapMax=0 -p CPUQuota=50% -p TasksMax=64 ./import-data.sh--scope, Running scope as unit: run-r7c1a....scope yazdırdıktan sonra komutu terminalinizde çalıştırır. Çıktı ekranınızda kalır ve komut sonlandığında sınırlar ortadan kalkar. systemd.resource-control içindeki her özellik -p sonrasında kullanılabilir.
Uzun süren bir iş için --scope parametresini kaldırın ve bir isim verin. Bu durumda iş, arka planda geçici bir servis olarak çalışır ve kayıtları journal içine yazar:
sudo systemd-run --unit=nightly-import -p MemoryMax=1G -p CPUWeight=20 ./import-data.sh
journalctl -u nightly-import -fAynı seçenekler root olmadığınızda --user ile de çalışır; ancak kullanıcı yöneticiniz yalnızca kendisine devredilen denetleyicilere sahiptir, bu nedenle bir özellik orada reddedilebilir. Böyle bir durumda komutu sudo ile çalıştırın. Bir iş kalıcı hale geldiğinde, ayarlar hiçbir değişiklik yapılmadan gerçek bir unit dosyasına taşınır: bkz. bir betiği systemd servisi ve zamanlayıcısı olarak çalıştırma.
Swap sorusuna dürüst bir yanıt
Swap, sistem çökmesini engellemek yerine çöküşün biçimini değiştirir.
Swap alanı yoksa, bellek sızıntısı sınıra ulaştığında süreç saniyeler içinde sonlanır. Kesinti gürültülü, kısa süreli ve sonrasında günlük kayıtlarında (journal) kolayca okunabilir durumdadır. Swap kullanıldığında ise çekirdek, nadiren kullanılan anonim sayfaları diske yazar ve zaman kazanır. Eğer süreç bir noktada dengelenecekse, swap sizi kurtarır. Ancak süreç kontrolden çıkmışsa, swap beş saniyelik bir kesintiyi yirmi dakikalık bir donmaya dönüştürür. Donma durumu daha kötüdür; çünkü ölü bir süreç size çalışan bir kabuk (shell) bırakırken, sürekli disk takaslayan (thrashing) bir sistem hiçbir yanıt vermez.
swapon --show
free -hKüçük bir VPS üzerinde uygulanabilir orta yol şudur: Bir kez ayrılan ve bir daha dokunulmayan sayfalar için mütevazı bir swap dosyası tutun ve kaybetmeyi göze alabileceğiniz birimler için MemorySwapMax=0 değerini ayarlayın. Önemli servisler swap alanını kullanmaya devam eder. Öngörülemeyen servisler ise sınıra hızla çarpar ve yeniden başlatılır.
vm.swappiness değerini düşürmek zayıf bir yöntemdir ve nedenini bilmek gerekir. Bu işlem yalnızca sayfa önbelleğinin (page cache) boşaltılması ile anonim sayfaların swap alanına taşınması arasındaki dengeyi değiştirir; her iki durum da daha sonra bir disk okuma maliyeti doğurur. Bu ayar, sistemin disk takaslayıp takaslamayacağını değil, hangi sayfaların takaslanacağını belirler.
Erken bir OOM daemon'ı, sistem kilitlenmeden önce müdahale eder
Çekirdek, bellek geri kazanımının tamamen başarısız olmasını bekler; küçük bir VPS üzerinde bu bekleme süresi, makineyi kaybettiğiniz tam o aralıktır. İki kullanıcı alanı daemon'ı, belleği kendileri izleyip daha erken sonlandırarak bu sorunu kapatır.
earlyoom, kullanılabilir belleği ve boş takas alanını izler; her ikisi de bir eşik değerin altına düştüğünde en yüksek puana sahip süreci sonlandırır.
sudo apt install earlyoom
systemctl status earlyoomDebian ve Ubuntu paketleri, kurulum sırasında servisi başlatır. Seçenekleri /etc/default/earlyoom içinde yer alır:
EARLYOOM_ARGS="-m 5,2 -s 5,2 --avoid '^(sshd|systemd)$' --prefer '^(node|python3)$'"-m PERCENT, kullanılabilir bellek minimumunu; -s PERCENT ise boş takas alanı minimumunu ayarlar; her ikisi de varsayılan olarak yüzde 10'dur. Her çiftteki ikinci sayı SIGKILL noktasıdır: earlyoom, ilk değerin altına düştüğünüzde SIGTERM gönderir, ardından ilkinin yarısı olarak varsayılan ikinci değerin altına düştüğünüzde SIGKILL gönderir. Değişiklikleri sudo systemctl restart earlyoom ile uygulayın ve hangi sürecin sonlandırıldığını ve bu sürecin ne kadar bellek tuttuğunu görmek için journalctl -u earlyoom dosyasını okuyun.
systemd-oomd diğer seçenektir. Kılavuz sayfası onu "çekirdek alanında bir OOM oluşmadan önce izleme yapmak ve düzeltici eylemde bulunmak için cgroups-v2 ve pressure stall information (PSI) kullanan bir sistem servisi" olarak tanımlar. Tekil süreçler yerine tüm cgroup'lar üzerinde işlem yapar, bu nedenle başıboş bir alt süreç yerine bir birimi sonlandırır. Birimler ManagedOOMMemoryPressure=kill veya ManagedOOMSwap=kill ile dahil olur ve eşik değerleri /etc/systemd/oomd.conf içinde yer alır.
systemctl status systemd-oomd
oomctloomctl, o anda nelerin izlendiğini yazdırır; ayar birim bazında isteğe bağlı (opt-in) olduğundan, sunucu imajlarında genellikle hiçbir şey izlenmez. Bir daemon seçin ve orada durun. Her ikisini de çalıştırmak, iki aracın bir kurban seçmek için yarışması anlamına gelir ve herhangi bir sonlandırmanın nedenini yeniden yapılandırmak zorlaşır.
Hangi birim sorumluydu?
Çekirdek ile başlayın, çünkü gerçekleştirdiği her sonlandırma işlemini kaydeder.
journalctl -k --grep "Killed process" --since "2 hours ago"Global OOM killer tarafından yapılan bir sonlandırma şu şekilde görünür:
Out of memory: Killed process 4127 (node) total-vm:2731084kB, anon-rss:1874232kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:4212kB oom_score_adj:0anon-rss, sürecin öldüğü sırada RAM'de tuttuğu bellek miktarıdır, burada yaklaşık 1.8 GB. Köşeli parantez içindeki isme şüpheyle yaklaşın. Bu, çekirdeğin seçtiği kurbandır; çekirdek genellikle en büyük süreci seçer, ancak bu süreç her zaman bellek yetersizliğine neden olan süreç değildir.
Bir cgroup limitinden kaynaklanan sonlandırmanın ön eki farklıdır ve üzerinde yazılı olan rapor, kendi sınırına ulaşan cgroup'u belirtir:
Memory cgroup out of memory: Killed process 8811 (python3) total-vm:1044320kB, anon-rss:769112kB, file-rss:0kB, shmem-rss:0kB, UID:998 pgtables:1720kB oom_score_adj:0Bu ön ek, teşhisin büyük bir kısmını oluşturur. Memory cgroup out of memory, bir birimin kendisine atadığınız MemoryMax= değerine ulaştığı ve sunucunun geri kalanının sorunsuz olduğu anlamına gelir. Yalın bir Out of memory ise makinenin genelinde bellek tükendiğini gösterir; bu da limitlerinizin eksik olduğu veya toplamda çok cömert ayarlandığı anlamına gelir.
Ardından systemd'ye ne gördüğünü sorun:
systemctl status myapp.service
journalctl -u myapp.service -n 50myapp.service: A process of this unit has been killed by the OOM killer.
myapp.service: Main process exited, code=killed, status=9/KILL
myapp.service: Failed with result 'oom-kill'.systemctl status, aynı durumu Active: failed (Result: oom-kill) olarak tek satırda ifade eder.
Cgroup sayaçları üçüncü kaynaktır ve hiçbir log satırı üretmeyen "throttling" (yavaşlatma) durumunu kaydeden tek yerdir:
cat /sys/fs/cgroup/system.slice/myapp.service/memory.events
cat /sys/fs/cgroup/system.slice/myapp.service/memory.peaklow 0
high 4213
max 118
oom 12
oom_kill 12high, birimin kaç kez MemoryHigh= sınırının üzerine itildiğini ve yavaşlatıldığını sayar. max, donanımsal sınıra (hard cap) ne sıklıkla ulaşıldığını, oom_kill ise kaç sürecin fiilen sonlandırıldığını gösterir. Yüksek bir high değeri ve sıfır oom_kill 0, daha önce bahsedilen sessiz durumu ifade eder: servis çalışmaktadır, hızı ciddi oranda düşmüştür ancak kimseye bir hata rapor etmemiştir. memory.peak (Linux 5.19 ve üzeri), cgroup'un ulaştığı en yüksek kullanım miktarını tutar; MemoryMax= değerini belirlemek için bu sayı baz alınmalıdır. Birim yeniden başlatıldığında systemd cgroup'u tekrar oluşturduğu için her iki dosya da sıfırlanır.
Tüm bunların altında bir ön koşul yatar. Eğer /var/log/journal mevcut değilse, journal RAM üzerinde tutulur ve sunucuyu kurtarmak için yaptığınız yeniden başlatma işleminden sonra tüm kayıtlar silinir.
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --list-bootsjournalctl --list-boots değerinin mevcut boot'tan daha fazlasını göstermesi, geçmiş kayıtların artık kalıcı olduğunu belirtir; bu sayede journalctl -k -b -1, çöken boot işlemine ait çekirdek mesajlarını size gösterebilir.
Küçük bir VPS için başlangıç noktası
2 GB kapasiteli bir planda, çekirdek ve sayfa önbelleği (page cache) için 300 ila 400 MB boşluk bırakın. Tüm limitlerin toplamının 2 GB'a ulaşmasına izin vermeyin; çünkü her birim aynı anda en yüksek kullanım seviyesine çıkabilir. En önemli servise en büyük payı ayırın, ardından çevresindeki tüm spekülatif servisleri sınırlandırın.
[Service]
MemoryHigh=256M
MemoryMax=384M
MemorySwapMax=0
CPUWeight=20
TasksMax=64
Restart=on-failure
RestartSec=5sSisteme erişim yolunu açık tutmak, fazladan bir ayar yapmaya değer. ssh.service için bir drop-in dosyası içerisindeki OOMScoreAdjust=-500 ayarı, global OOM killer'ın SSH daemon sürecinizi kurban olarak seçme olasılığını ciddi oranda düşürür. Bu, sunucuyu onarmak ile kontrol panelinden yeniden başlatmak arasındaki farktır. Bu ayar yalnızca çekirdeğin kurban seçimini değiştirir; sistemdeki donma süresini kısaltmaz.
Konteynerler, unit dosyalarınız tarafından değil, konteyner çalışma zamanı (runtime) tarafından oluşturulan kendi cgroup'ları içinde çalışır. Bu nedenle docker.service üzerindeki bir limit, tek bir konteyner için limit haline gelmez. MemoryMax= ve CPUQuota= ayarlarının konteyner bazlı karşılıkları, Docker Compose içinde bellek ve CPU limitlerini ayarlama bölümünde ele alınmıştır.
FAQ
VPS'im neden kontrolden çıkan süreci sonlandırmak yerine dondu?
Çünkü çekirdek, ilerlemeyi bellek geri kazanımının (reclaim) sayfaları döndürüp döndürmediğine göre değerlendirir, bu işlemin ne kadar sürdüğüne göre değil. Bellek kısıtlıyken, çalışan programların yürütülebilir sayfaları da dahil olmak üzere sayfa önbelleğini (page cache) boşaltır ve bir sonraki komutta bunları tekrar okur. Her şey depolama biriminden yanıt beklediği ve teknik olarak hiçbir bellek tahsisatı başarısız olmadığı için OOM killer devreye girmez. Bu durum yaşanırken /proc/pressure/memory komutunu kontrol edin: 40 üzerindeki bir full avg10 değeri, son on saniye içinde neredeyse hiçbir görevin çalışamadığı anlamına gelir. earlyoom gibi bir kullanıcı alanı (userspace) arka plan programı, sunucu bu duruma gelmeden önce süreci sonlandırır.
MemoryHigh ve MemoryMax arasındaki fark nedir?
MemoryHigh=, kısıtlama uygulayan yumuşak bir sınırdır. Çekirdek, birimden belleği yoğun şekilde geri kazanır ve tahsisatları yavaşlatır, ancak kullanım bu sayıyı aşabilir ve hiçbir süreç sonlandırılmaz. MemoryMax= ise katı bir sınırdır: bu sınır altında karşılanamayan bir tahsisat talebi, ilgili cgroup içinde OOM killer'ı tetikler. Böylece sunucudaki en büyük süreç yerine, soruna neden olan süreç sonlandırılır. MemoryHigh= değerini MemoryMax= değerinin altında tutun ve aradaki boşluğu bir uyarı bölgesi olarak değerlendirin.
OOM killer'ın hangi servisi sonlandırdığını nasıl bulurum?
journalctl -k --grep "Killed process" --since "2 hours ago" komutunu çalıştırın. Memory cgroup out of memory ile başlayan bir satır, bir birimin kendi MemoryMax= sınırına ulaştığı anlamına gelir; düz bir Out of memory ifadesi ise tüm makinenin belleğinin tükendiğini gösterir. Ardından journalctl -u <unit> -n 50 komutunu çalıştırın ve Failed with result 'oom-kill' ifadesini arayın. Eğer sunucunuzda /var/log/journal dizini mevcut değilse, günlük kayıtları RAM'de tutuluyordur ve kanıtlar yeniden başlatma ile silinmiştir; bu nedenle bir sonraki olaydan önce ilgili dizini oluşturun.
Küçük bir VPS'e swap eklemeli miyim?
Küçük bir swap dosyası, bir kez tahsis edilen ve bir daha kullanılmayan soğuk sayfalar için faydalıdır. Kontrolden çıkan bir süreçte işe yaramaz; sonlandırma işlemini geciktirir ve kısa süreli bir kesintiyi, müdahale edemeyeceğiniz uzun süreli bir donmaya dönüştürür. Swap miktarını makul tutun ve kaybetmeyi göze aldığınız birimlere MemorySwapMax=0 ayarını ekleyin; böylece bu birimler sınıra ulaştıklarında hızlıca yeniden başlar ve önemli servisler swap alanlarını korumaya devam eder.
Bir unit dosyası yazmadan bir komutu nasıl sınırlandırabilirim?
Evet. sudo systemd-run --scope -p MemoryMax=1G -p CPUQuota=50% ./script.sh komutu, terminalinizdeki süreci belirtilen sınırlar dahilinde geçici bir kapsamda (transient scope) çalıştırır ve süreç sonlandığında sınırlar da ortadan kalkar. systemd.resource-control içindeki tüm özellikler -p sonrasında kullanılabilir; bu nedenle MemorySwapMax=, TasksMax= ve CPUWeight= parametreleri de burada çalışır. --scope parametresini kaldırıp --unit=name ekleyerek işi arka planda çalıştırabilir ve çıktısını günlük kayıtlarına (journal) aktarabilirsiniz.