systemd ile islemci ve bellek sinirlandirma rehberi
systemd unit dosyalarinda MemoryMax ve CPUQuota kullanarak kaynak kullanimini kisitlayin. Servislerin sunucuyu kilitlemesini onlemek icin gerekli yapilandirmayi ogrenin.
systemd drop-in dosyası ile işlem bellek ve CPU sınırlandırma
Linux VPS üzerinde bir işlemin bellek ve CPU kullanımını, ilgili süreci çalıştıran unit dosyasına birkaç satır ekleyerek sınırlandırabilirsiniz. MemoryMax=, bellek için kesin üst sınırdır. CPUQuota= ise işlemci süresi için üst sınırdır. Her ikisi de, systemd'nin sunucudaki her servisi takip etmek 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ı alıyorsanız, drop-in dosyası yüklenmemiş demektir. Dosyanın /etc/systemd/system/myapp.service.d/override.conf konumuna 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 servisi hiçbir sınırlandırma olmadan başlatmasına neden olur.
Bu kılavuzun geri kalanı, bu değerlerin 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 durumdadır ve meşguldür, ancak yapılan işlerin hiçbiri faydalı değildir.
Bunun mekanizması belirgin olmadığı için şu şekildedir: Boş bellek azaldığında, çekirdek yeni sayfalar vermek 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ı bellekten atar 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 yavaş da olsa 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=9114233full satırı önemli olan kısımdı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.
Sınırlandırmanın tek başına bir garanti olmamasının nedeni de budur. MemoryHigh= altında tutulan bir birim sonlandırılmak yerine kısıtlanır (throttled); bu yüzden hayatta kalır, yavaş çalışır ve systemd açısından başarısız olmadığı için yeniden başlatılmaz. 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 üretir; 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 daha eski olan 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ümleri ile Debian 11 ve sonraki sürümleri varsayılan olarak v2 kullanır. Eski bir imaj veya systemd.unified_cgroup_hierarchy=0 parametresiyle başlatılmış 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ıralar; sunucu yanıt verebildiği sürece "sunucuyu neyin tükettiğini" anlamanı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ıtlamaları ve MemoryMax sonlandırmaları.
İki 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ğerin üzerinde çekirdek, ilgili cgroup içinden agresif bir şekilde bellek geri kazanır ve tahsisatları kasıtlı olarak yavaşlatır. Kullanım bu sayının üzerine çıkabilir ve hiçbir süreç sonlandırılmaz.MemoryMax=katı bir sınırdır. Bu sınır dahilinde bir tahsisat karşılanamadığında, OOM killer ilgili cgroup içinde çalışır ve o birimin kendi süreçlerinden birini sonlandırır.
İkinci durum, tam olarak güvenmediğiniz her şey için MemoryMax= ayarını yapmanızın asıl nedenidir. Bir sınır olmadığında, bellek yetersizliği tüm sunucuyu etkileyen bir sorun haline gelir ve küresel 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, soruna neden olan birimin içinde gerçekleşir.
Her iki ayarı da yapın ve MemoryHigh= değerini MemoryMax= değerinin yaklaşık yüzde 20 ila 30 altına ayarlayın. Bu boşluk bir uyarı bölgesidir: yavaş bir sızıntı High değerini aştığında servis yavaşlar, ani bir yükseliş ise doğrudan Max değerini geçer ve servis sonlanır.
Yüzde değerleri, kurulu fiziksel belleğe göre okunur; 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.
Bir sınırın yanında bir yeniden başlatma politikası gereklidir, 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ünde, Restart= ayarı ise [Service] bölümünde yer almalıdır. Herhangi birini yanlış bölüme koyarsanız systemd bunu görmezden gelir. Beş dakika içinde beş yeniden başlatma, geçici bir durumdan ziyade bir sızıntıya işaret eder; bu nedenle systemd bu noktadan sonra pes eder ve birimi failed durumunda bırakır. Sorunu gizleyen bir crash loop yerine daha sonra incelemek isteyeceğiniz durum budur.
CPUQuota ile CPU sınırlandırma veya CPUWeight ile paylaştırma
CPUQuota=, tek bir CPU üzerinde mevcut olan 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 bunu istediği kadar iş parçacığına yayabilir. 2 vCPU'lu bir planda, CPUQuota=200% tüm makineyi ifade eder.
CPUWeight=, çoğu servis için daha iyi bir varsayılan değerdir. 1 ile 10000 arasında göreceli bir paydır ve çekirdek varsayılanı 100'dür. Yalnızca bir rekabet durumu olduğunda devreye girer: CPUWeight=20 değerindeki bir yedekleme işi, yük altında 100 değerindeki bir web sunucusuna öncelik verir ve sunucu boşta olduğunda tüm makineyi kullanmaya devam eder. Katı bir kota ise bu boş kapasiteyi boşa harcar.
Bir CPU sınırının size ne kazandırdığı konusunda dürüst olun. CPU yoğunluklu bir süreç nadiren Linux'u dondurur, çünkü zamanlayıcı herkese zaman dilimi ayırmaya devam eder. Bir sunucuyu çökerten şey bellek kullanımıdır. Tahmin edilebilir bir üst sınır istediğinizde, örneğin bir saat boyunca tam kapasite çalışacak bir derleme işlemi veya aracı için 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ı 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 çalışmadığı halde CPU meşgul görünüyorsa, bunun nedeni hipervizörün diğer tarafında olabilir. Bu durum gürültülü bir komşudan kaynaklanan CPU steal time sorunudur ve belirleyeceğiniz hiçbir kota bunu değiştirmeyecektir.
TasksMax bir fork döngüsünü durdurur
TasksMax=, bir birimin barındırabileceği süreç ve iş parçacığı sayısıdır. İş parçacıkları da sayıldığından, bir Java veya Go servisi süreç listesinin önerdiğinden daha fazla alana ihtiyaç duyar. Bu, bir döngü içinde fork yapan bir betiğe karşı en ucuz 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ı bildirir. Yöneticinin varsayılan olarak ne uyguladığını systemctl show -p DefaultTasksMax ile kontrol edin.
systemd-run ile tek seferlik işleri sınırlama
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 -froot olmadığınız durumlarda aynı seçenekler --user ile de çalışır; ancak kullanıcı yöneticiniz yalnızca kendisine devredilen denetleyicilere sahiptir, bu nedenle bir özellik 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, sistemin çökmesini engellemek yerine çöküşün biçimini değiştirir.
Swap alanı yoksa, bir bellek sızıntısı sınırına ulaştığında süreç saniyeler içinde sonlanır. Kesinti gürültülü ve kısa sürer; sonrasında günlük kayıtlarında (journal) kolayca okunabilir. Swap alanı olduğunda ise çekirdek, kullanılmayan anonim sayfaları diske yazarak 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çte en azından çalışan bir kabuğa (shell) erişebilirsiniz, ancak sürekli disk işlemleriyle kilitlenmiş (thrashing) bir sunucuda bu mümkün değildir.
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 ayarını yapın. Önemli servisler swap alanını kullanmaya devam eder. Öngörülemez olanlar ise sınıra hızla ulaşır ve yeniden başlatılır.
vm.swappiness değerini düşürmek zayıf bir yöntemdir ve nedenini bilmek gerekir. Bu ayar 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 işlem de daha sonra bir disk okuma maliyeti doğurur. Bu, sunucunun kilitlenip kilitlenmeyeceğini değil, hangi sayfaların disk üzerinde sürekli yer değiştireceğini 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, makineye erişimi kaybettiğiniz kritik aralıktır. İki kullanıcı alanı daemon'ı, belleği kendileri izleyip daha erken müdahale ederek bu sorunu çözer.
earlyoom, kullanılabilir belleği ve boş takas alanını (swap) izler; bunlardan biri 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 otomatik olarak başlatır. Servis seçenekleri /etc/default/earlyoom dosyasında yer alır:
EARLYOOM_ARGS="-m 5,2 -s 5,2 --avoid '^(sshd|systemd)$' --prefer '^(node|python3)$'"-m PERCENT, minimum kullanılabilir bellek miktarını; -s PERCENT ise minimum boş takas alanı miktarını belirler; her ikisi için varsayılan değer 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 ilk değerin yarısı varsayılan değer olan ikinci değerin altına düşüldüğünde SIGKILL gönderir. Değişiklikleri uygulamak için sudo systemctl restart earlyoom komutunu kullanın ve hangi sürecin sonlandırıldığını ve bu sürecin ne kadar bellek kullandığını görmek için journalctl -u earlyoom dosyasını okuyun.
systemd-oomd diğer seçenektir. Kılavuz sayfası onu "cgroups-v2 ve pressure stall information (PSI) kullanarak, çekirdek alanında bir OOM oluşmadan önce izleme yapan ve düzeltici eylemde bulunan bir sistem servisi" olarak tanımlar. Tekil süreçler yerine tüm cgroup'lar üzerinde işlem yapar; yani başıboş bir alt süreci değil, bir birimin tamamını sonlandırır. Birimler ManagedOOMMemoryPressure=kill veya ManagedOOMSwap=kill ile bu sisteme dahil olur ve eşik değerleri /etc/systemd/oomd.conf dosyasında tutulur.
systemctl status systemd-oomd
oomctloomctl, o anda nelerin izlendiğini yazdırır. Sunucu imajlarında ayarlar birim bazında isteğe bağlı (opt-in) olduğu için genellikle hiçbir şey izlenmez. Bir daemon seçin ve onunla devam edin. Her ikisini de çalıştırmak, iki farklı aracın kurban seçmek için yarışmasına neden olur ve herhangi bir sonlandırma işleminin nedenini tespit etmeyi zorlaştırı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 gerçekleştirilen 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üreç öldüğünde 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 yazdırılan 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ığını ve sunucunun geri kalanının sorunsuz olduğunu gösterir. Yalın bir Out of memory ise makinenin genelinde bellek tükendiği anlamına gelir; bu durumda ya limitleriniz eksiktir ya da toplamda çok cömert davranılmıştır.
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, Active: failed (Result: oom-kill) ile aynı durumu tek satırda ifade eder.
Cgroup sayaçları üçüncü kaynaktır ve hiçbir log satırı üretmeyen yavaşlatma (throttling) 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, sert sınıra ne sıklıkla ulaşıldığını, oom_kill ise gerçekte kaç sürecin sonlandırıldığını gösterir. Yüksek bir high değeri ve 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ıya bakılmalıdır. Her iki dosya da birim yeniden başlatıldığında sıfırlanır, çünkü systemd cgroup'u yeniden oluşturur.
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 satırlar 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 süresinden 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 ayırın. Sınırların toplamını 2 GB'a tamamlamayın; çünkü her birim aynı anda tepe noktasına ulaşabilir. En önemli servise en büyük payı verin, ardından bunun etrafındaki spekülatif tüm 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ındaki 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.
Container'lar, unit dosyalarınız yerine container runtime tarafından oluşturulan kendi cgroup'ları içinde çalışır. Bu nedenle docker.service üzerindeki bir sınır, tek bir container için sınır teşkil etmez. Container başına düşen MemoryMax= ve CPUQuota= karşılıkları, Docker Compose içinde bellek ve CPU sınırlarını ayarlama bölümünde ele alınmıştır.
FAQ
VPS'im neden kontrolden çıkan süreci sonlandırmak yerine dondu?
Çekirdek, ilerlemeyi sürecin ne kadar sürdüğüne göre değil, bellek geri kazanımının (reclaim) sayfa döndürüp döndürmediğine göre değerlendirir. Bellek kısıtlıyken çekirdek, ç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: full avg10 değerinin 40'ın üzerinde olması, son on saniye içinde neredeyse hiçbir görevin çalışamadığı anlamına gelir. earlyoom gibi bir kullanıcı alanı daemon'ı, 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 zorla 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 sert bir sınırdır: bu sınırın altında karşılanamayan bir tahsisat, 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 ayarlayın ve aradaki farkı 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 ise işe yaramaz; sadece sonlandırma işlemini geciktirir ve kısa süreli bir kesintiyi, sisteme giriş yapıp düzeltemeyeceğiniz uzun süreli bir donmaya dönüştürür. Swap miktarını makul tutun ve kaybetmeyi göze aldığınız birimlerde MemorySwapMax=0 ayarını yapılandırın. Böylece bu birimler sınıra ulaştıklarında hızlıca yeniden başlar ve önemli servisler swap alanını korumaya devam eder.
Bir komutu unit dosyası yazmadan sınırlayabilir miyim?
Evet. sudo systemd-run --scope -p MemoryMax=1G -p CPUQuota=50% ./script.sh, komutu terminalinizde bu sınırlamalarla geçici bir kapsam (transient scope) içinde çalıştırır ve komut çıktığında sınırlar da ortadan kalkar. systemd.resource-control içindeki her özellik -p sonrasında kullanılabilir; dolayısıyla MemorySwapMax=, TasksMax= ve CPUWeight= seçenekleri burada da ç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.