Konfiguracja swapa i zapobieganie awariom z braku pamięci

Opublikowano 13 min czytania

Usługa zniknęła, żadnego raportu o awarii, plik logu urywa się w połowie zdania. Tak udowodnisz zabicie procesu przez OOM, poprawnie założysz plik swap i rozpoznasz, kiedy swap tylko odsuwa problem.

Usługa zniknęła. Żadnego raportu o awarii, żadnego stosu wywołań, plik logu urywa się w połowie wiersza. MariaDB przestaje odpowiadać, nginx zwraca 502, serwer Minecraft jest offline, a w samej aplikacji nie widać niczego podejrzanego. Prawie zawsze stoi za tym ten sam schemat: jądru zabrakło wolnej pamięci i zakończyło jakiś proces, żeby utrzymać system przy życiu. W tym poradniku pokazujemy, jak udowodnić to ponad wszelką wątpliwość, jak poprawnie założyć plik swap i wpisać go na stałe, oraz w jakich sytuacjach swap odsuwa problem tylko o kilka minut.

Zbierz dowody: dmesg i journalctl

Zanim cokolwiek zaczniesz konfigurować, potrzebujesz dowodu. Przy każdym zabiciu procesu z powodu braku pamięci (OOM, Out of Memory) jądro zapisuje w buforze pierścieniowym obszerny blok informacji:

dmesg -T | grep -iE 'out of memory|oom-kill'

Jeśli nie wróci żaden wiersz, a polecenie zakończy się kodem wyjścia 1, od ostatniego startu systemu nie doszło do OOM na poziomie jądra. Ten kod wyjścia nie oznacza błędu, to zwykła odpowiedź polecenia grep, które niczego nie znalazło. Jeśli coś wróci, na wszystkich czterech omawianych tu systemach wygląda to tak:

mariadbd invoked oom-killer: gfp_mask=0x140cca(GFP_HIGHUSER_MOVABLE|__GFP_COMP), order=0, oom_score_adj=0
oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/system.slice/mariadb.service,task=mariadbd,pid=1043,uid=107
Out of memory: Killed process 1043 (mariadbd) total-vm:2894760kB, anon-rss:1583204kB, file-rss:0kB, shmem-rss:0kB, UID:107 pgtables:3820kB oom_score_adj:0

Ważne są w tym trzy rzeczy. Po pierwsze: invoked oom-killer wskazuje proces, który zażądał pamięci, niekoniecznie winowajcę. Po drugie: zabity proces stoi w wierszu Killed process. Po trzecie: liczy się anon-rss, czyli faktycznie zajęta pamięć anonimowa. total-vm to zarezerwowana przestrzeń adresowa, przy Javie albo Go regularnie jej wielokrotność, i niczego nie dowodzi.

Uruchomiony bez roota dmesg odpowiada na Debianie 12, Debianie 13, Ubuntu 22.04 i Ubuntu 24.04 komunikatem dmesg: read kernel buffer failed: Operation not permitted, bo kernel.dmesg_restrict ma wszędzie wartość 1. Pracuj więc przez sudo albo jako root. Jeśli komunikat zostaje także na koncie root, siedzisz w kontenerze LXC albo OpenVZ, który nie ma dostępu do bufora pierścieniowego hosta. Wtedy prowadzi dalej wyłącznie druga droga, przez journalctl -k.

Po restarcie bufor pierścieniowy jest pusty. Stąd druga droga, przez journal, i tu właśnie czai się pułapka, którą większość poradników pomija:

journalctl -k --grep "Out of memory"

-k włącza w domyśle -b, pokazuje więc wyłącznie bieżące uruchomienie systemu. Jeśli maszyna została po zdarzeniu zrestartowana, to polecenie nie zwróci nic, choć zdarzenie zostało zapisane. Dla poprzedniego startu albo dla wybranego okresu:

journalctl -k -b -1 --grep "Out of memory"
journalctl --since "7 days ago" --grep "Out of memory|oom-kill"

Jeśli pierwsze z tych dwóch poleceń odpowie No journal boot entry found for the specified boot (-1), w journalu po prostu nie ma zapisanego wcześniejszego uruchomienia. To również nie jest błąd, tylko normalna sytuacja na systemie, którego journal zapisuje dane dopiero od bieżącego startu.

Działa to jednak tylko wtedy, gdy journal w ogóle jest trwały. Sprawdź to:

ls -d /var/log/journal

Na Debianie i Ubuntu ten katalog istnieje fabrycznie, więc test prawie zawsze coś zwróci, a późniejsze mkdir zadziała wtedy na pusto i niczego nie zepsuje. Jeśli wyjątkowo katalogu jednak nie ma, journal leży wyłącznie w /run i po każdym restarcie przepada. Nadrabia się to dwoma poleceniami:

mkdir -p /var/log/journal
systemctl restart systemd-journald

OOM jądra czy limit systemd? Dwie różne przyczyny

To rozróżnienie decyduje o tym, czy swap w ogóle coś da. Zwróć uwagę na pole constraint w komunikacie jądra.

CONSTRAINT_NONE oznacza: pamięci zabrakło całemu systemowi. Tu swap pomoże.

CONSTRAINT_MEMCG oznacza: limit przekroczyła tylko pojedyncza control group, a reszta systemu miała mnóstwo zapasu. Tu swap nie pomoże, tu trzeba podnieść limit albo zmusić aplikację do oszczędności. Takie zabicia rozpoznasz również po samej usłudze:

systemctl status mariadb

Jeśli stoi tam Main process exited, code=killed, status=9/KILL, a niżej Failed with result 'oom-kill', było to zabicie z powodu braku pamięci. Czy w grę wchodził limit cgroup, zdradzi plik z licznikami. Wymaga on cgroup v2, czyli standardu na wszystkich czterech dystrybucjach; przy starszym cgroup v1 ta ścieżka nie istnieje:

cat /sys/fs/cgroup/system.slice/mariadb.service/memory.events
systemctl show mariadb -p MemoryMax -p MemoryHigh

Wartość większa od zera przy oom_kill razem z ustawionym MemoryMax to dowód na lokalny limit.

Jest jeszcze trzeci kandydat, często pomijany, bo nie zapisuje w dmesg zupełnie niczego: systemd-oomd. Ta usługa działa w przestrzeni użytkownika, analizuje wskaźnik presji PSI i kończy całe control groups, zanim jądro w ogóle zdąży zareagować. Jej komunikat w journalu brzmi mniej więcej Killed /system.slice/... due to memory pressure for /system.slice being 60.00% > 50.00% for > 20s with reclaim activity. Sprawdź, czy usługa działa:

systemctl is-active systemd-oomd

Na Ubuntu systemd-oomd jest od wersji 22.04 fabrycznie zainstalowany i włączony, na Debianie nie należy do standardowego wyposażenia. Odpowiedź inactive na serwerze z Debianem jest więc spodziewana i nie świadczy o żadnym błędzie.

Ważne na później: systemd-oomd potrafi zadziałać również dlatego, że zapełnia się swap. Przy włączonym oomd większy swap może więc wywoływać przerwania wcześniej, a nie później.

Zanim dodasz swap: ile pamięci naprawdę brakuje

Dwie minuty pomiarów oszczędzą ci błędnej decyzji.

free -h

Interesuje cię wyłącznie kolumna available, a nie free. Cache liczy się jako dostępny i w razie potrzeby zostaje zwolniony. Kto patrzy na kolumnę free, uzna każdy zdrowy system za przeciążony.

ps -eo pid,comm,rss,%mem --sort=-rss | head -n 11
systemd-cgtop --order=memory -b -n 1

Pierwsze polecenie pokazuje największe pojedyncze procesy, drugie grupuje je według usług. W praktyce stoją tam prawie zawsze ci sami trzej podejrzani: MariaDB ze zbyt dużym innodb_buffer_pool_size, PHP-FPM ze zbyt wysokim pm.max_children oraz JVM ze zbyt hojnym -Xmx.

Jako punkt wyjścia dla rozmiaru pliku swap wystarczy ta tabela. Na serwerze większy nie znaczy lepszy, bo swap, który faktycznie zapełnisz w całości, sprawia, że maszyna przestaje reagować.

Pamięć RAMRozsądny plik swap
1 GB1-2 GB
2 GB2 GB
4-8 GB2-4 GB
16 GB i więcej4 GB, rzadko więcej

Zakładanie pliku swap

Najpierw sprawdź, czy swap już istnieje. Serwery Ubuntu z instalatora ISO często mają już /swap.img, Debian z instalatora zwykle prawdziwą partycję swap. Obrazy chmurowe obu dystrybucji z reguły nie mają nic.

swapon --show

Jeśli wynik pozostanie pusty, swapa nie ma. Następnie sprawdź system plików, bo od niego zależy dalsze postępowanie:

findmnt -no FSTYPE -T /

Przy ext4 albo xfs idziesz od razu dalej. Plik zakładaj poleceniem dd, nie fallocate. fallocate jest szybszy, ale zależnie od systemu plików i jądra tworzy plik z niezapisanymi obszarami, a wtedy swapon go odrzuci. dd zapisuje prawdziwe zera i działa wszędzie:

dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
chmod 600 /swapfile

Przed następnym krokiem warto wykonać kontrolę, którą wielu pomija. Jeśli pod ścieżką /swapfile jest już włączony swap, choćby z wcześniejszej próby albo z domyślnej konfiguracji obrazu, mkswap odmówi pracy komunikatem mkswap: error: /swapfile is mounted; will not make swapspace. Liczy się przy tym wyłącznie to, czy ścieżka figuruje jako aktywna w /proc/swaps. Sprawdź więc i w razie potrzeby wyłącz:

swapon --show
swapoff /swapfile

Jeśli w swapon --show nie pojawi się wiersz z /swapfile, możesz pominąć swapoff. Potem zapisz obszar wymiany:

mkswap /swapfile

mkswap odpowiada komunikatem Setting up swapspace version 1, size = 2 GiB (2147479552 bytes) i nowym UUID. Dopiero potem włącz:

swapon /swapfile

Kolejność nie podlega negocjacji. chmod przed mkswap, mkswap przed swapon, a ewentualne swapoff przed wszystkim innym.

Po czym poznasz, że naprawdę się udało

To, że swapon przejdzie bez komunikatu o błędzie, jeszcze niczego nie dowodzi. Dowodem są te dwa wyniki:

swapon --show
free -h

swapon --show musi wypisać wiersz z /swapfile, typem file, rozmiarem i priorytetem. W free -h wiersz Swap: musi przeskoczyć z 0B na nowy rozmiar. Jeśli jeden z tych dwóch wyników pozostanie bez zmian, swap nie jest aktywny, cokolwiek wcześniej zgłosiło samo polecenie.

Wpis na stałe, bez ryzykowania startu systemu

Samo swapon nie przeżyje restartu. Wpis należy do /etc/fstab, a właśnie tam najłatwiej rozłożyć serwer. Najpierw kopia zapasowa:

cp /etc/fstab /etc/fstab.bak
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Zwróć uwagę na dwa znaki większości. Pojedynczy > nadpisze cały plik, a wtedy maszyna nie wystartuje już poprawnie. Potem sprawdź składnię, zanim zrestartujesz:

findmnt --verify

Jedno ostrzeżenie jest przy tym zupełnie normalne i nie stanowi powodu, żeby usuwać wiersz: [W] non-bind mount source /swapfile is a directory or regular file. Przy pliku swap inaczej być nie może, a polecenie i tak kończy się kodem powrotu 0. Jeśli plikowi brakuje dodatkowo poprawnego nagłówka swap, dochodzi [W] cannot detect on-disk filesystem type, i wtedy faktycznie zapomniałeś o mkswap.

Jeśli swap włączyłeś już wcześniej ręcznie przez swapon /swapfile, jest teraz aktywny. Jeśli nie, swapon -a uruchomi wszystkie wpisy z fstab bez konieczności restartu. Właściwy test jest jednak inny. systemd tworzy z każdego wiersza fstab osobną jednostkę, dla /swapfile nazywa się ona swapfile.swap. Jeśli ta jednostka się pojawi i będzie aktywna, przy następnym starcie swap zostanie podłączony na pewno:

systemctl daemon-reload
systemctl list-units --type swap

Spodziewany jest wiersz swapfile.swap loaded active active Swap. Jeśli go brakuje, wiersz w fstab jest błędny, a restart skończyłby się bez swapa. Dopiero gdy wszystko się zgadza, warto zrestartować i sprawdzić wynik przez swapon --show.

Prawidłowe ustawienie swappiness

Parametr jądra vm.swappiness steruje tym, jak chętnie jądro wypycha strony anonimowe do wymiany, zamiast odrzucać cache plików. Wartość domyślna jest na Debianie 12, Debianie 13, Ubuntu 22.04 i Ubuntu 24.04 identyczna i wynosi 60:

cat /proc/sys/vm/swappiness

Zakres wartości sięga od jądra 5.8 od 0 do 200, a wszystkie cztery dystrybucje pracują na nowszych jądrach. Dwa rozpowszechnione nieporozumienia: vm.swappiness=0 nie wyłącza swapa, blokuje jedynie wypychanie stron na zapas, a jądro i tak sięgnie po wymianę, zanim kogokolwiek zabije. Poza tym niska wartość nie przyspieszy systemu, w którym pamięci po prostu brakuje.

Rozsądne wartości: 10-20 na serwerach bazodanowych, 60 na mieszanych serwerach WWW, 100 i więcej, jeśli używasz zram. Na stałe wpisuje się to do własnego pliku w /etc/sysctl.d/, a nie do /etc/sysctl.conf, który przeszkadza przy aktualizacjach pakietów:

echo 'vm.swappiness = 10' > /etc/sysctl.d/99-swappiness.conf
sysctl --system
cat /proc/sys/vm/swappiness

Trzecie polecenie to kontrola skuteczności. sysctl --system czyta wszystkie katalogi w stałej kolejności, a istniejący już plik o wyższym numerze może nadpisać twoją wartość.

Gdy coś pójdzie nie tak: komunikaty błędów dosłownie

swapon: /swapfile: insecure permissions 0644, 0600 suggested. To tylko ostrzeżenie, swap mimo wszystko działa. Napraw to jednak, bo inaczej każdy użytkownik może odczytać zawartość wypchniętych procesów: chmod 600 /swapfile.

swapon: /swapfile: swapon failed: Invalid argument Najczęstszy błąd. Albo zapomniano o mkswap, albo plik zawiera dziury. W logu jądra pojawia się wtedy dodatkowo swapon: swapfile has holes. Rozwiązanie: usuń plik i załóż go od nowa poleceniem dd zamiast fallocate.

Na btrfs obowiązuje ten sam błąd plus BTRFS warning: swapfile must not be copy-on-write. Tutaj kolejność jest inna: plik trzeba utworzyć pusty i przed wypełnieniem oznaczyć jako nieobjęty mechanizmem copy-on-write. Jedna uwaga na wstępie, która potrafi zadecydować o losie działającego serwera: truncate -s 0 oraz rm wykonają się także wtedy, gdy pod tą ścieżką podłączony jest jeszcze aktywny swap. Jądro wskazuje potem na bloki, których już nie ma. Jeśli swapon --show pokazuje ścieżkę jako aktywną, przed tymi poleceniami musi więc koniecznie paść swapoff /swapfile.

truncate -s 0 /swapfile
chattr +C /swapfile

Potem wypełnij plik jak zwykle poleceniem dd, dalej chmod 600, mkswap, swapon. Na skompresowanych subwolumenach i w snapshotach swap nadal nie działa.

swapon: /swapfile: swapon failed: Operation not permitted Siedzisz w kontenerze. LXC, OpenVZ i Docker dzielą jądro hosta i nie mogą włączyć własnego swapa. Sprawdzisz to poleceniem:

systemd-detect-virt

Jeśli polecenie zgłosi kvm, qemu albo none, działa własne jądro i swap jest możliwy. Jeśli zgłosi lxc, openvz albo docker, pomoże tylko więcej pamięci RAM albo produkt z pełną wirtualizacją. Serwery root KVM i serwery dedykowane od KernelHost mają własne jądro, swap można tam skonfigurować bez ograniczeń.

dd: error writing '/swapfile': No space left on device Dysk jest zbyt zapełniony. Najpierw df -h, potem usuń niedokończony plik przez rm /swapfile, bo inaczej dalej zajmuje miejsce. Także tutaj obowiązuje zasada: jeśli swapon --show pokazuje ścieżkę jako aktywną, przed usunięciem musi paść swapoff /swapfile.

System nie startuje, pojawia się konsola awaryjna. Prawie zawsze chodzi o literówkę w /etc/fstab. Zaloguj się przez konsolę w panelu klienta, potem mount -o remount,rw /, usuń błędny wiersz albo skopiuj z powrotem /etc/fstab.bak, zrestartuj. Dokładnie po to powstała wcześniej kopia zapasowa.

Różnice między Debianem 13, Debianem 12, Ubuntu 24.04 i 22.04

Polecenia są na wszystkich czterech systemach identyczne, stan wyjściowy już nie.

  • Istniejący swap: Ubuntu Server z instalatora ISO często zakłada /swap.img, Debian z instalatora partycję swap. Obrazy chmurowe obu dystrybucji przychodzą bez swapa. Zawsze najpierw swapon --show.
  • systemd-oomd: na Ubuntu od 22.04 fabrycznie zainstalowany i włączony, w obu wersjach Debiana nie należy do standardowego wyposażenia. To tłumaczy, dlaczego identyczne oprogramowanie potrafi umierać inaczej na dwóch pozornie takich samych systemach.
  • Baza danych: Debian 12 i Debian 13 nie dostarczają pakietu mysql-server, tam działa zawsze MariaDB (10.11 na Debianie 12, 11.8 na Debianie 13). Ubuntu 22.04 i 24.04 mają jedno i drugie. Domyślne wartości innodb_buffer_pool_size odpowiednio się różnią, a właśnie ta wartość bywa na małych serwerach najczęstszą przyczyną OOM.
  • Java: Debian 12 zna wyłącznie OpenJDK 17, Debian 13 wyłącznie OpenJDK 21, Ubuntu 22.04 i 24.04 obejmują wersje od 8 do 21. JVM bez ustawionego -Xmx bierze sobie domyślnie ćwierć pamięci RAM, a przy kilku instancjach zabicie przez OOM jest wtedy zaprogramowane z góry.
  • Komunikaty jądra: format i treść komunikatu OOM są na wszystkich czterech systemach takie same, powyższe przykłady pasują wszędzie.
  • swappiness: wszędzie domyślnie 60.

Kiedy swap pomaga, a kiedy tylko odsuwa problem

Swap pomaga niezawodnie przy krótkich szczytach, na przykład podczas tworzenia kopii zapasowej, aktualizacji pakietów albo nocnego importu. Pomaga przy usługach, które zajmują dużo pamięci, a potem całymi dniami nic nie robią, bo te strony spokojnie mogą leżeć na dysku. I daje ci w razie kłopotów kilka minut, w których sesja SSH jeszcze odpowiada i możesz zareagować, zamiast stać przed martwym serwerem.

Swap nie pomoże, jeśli stałe zapotrzebowanie po prostu przewyższa dostępny RAM. System zaczyna wtedy thrashing: bez przerwy wypycha strony i wciąga je z powrotem, load rośnie do wartości dwucyfrowych, obciążenie CPU pozostaje niskie, a wszystko czeka na I/O. W praktyce jest to gorsze niż czyste zabicie przez OOM, bo nie przechodzi nawet logowanie. Dwa polecenia pokażą, czy jesteś w tym stanie:

vmstat 1 5
test -e /proc/pressure/memory && cat /proc/pressure/memory

Przy vmstat liczą się kolumny siso. Trwale trzycyfrowe wartości oznaczają aktywne wypychanie i wciąganie stron. W /proc/pressure/memory decyduje full avg10: wartości powyżej 10 znaczą, że cały system dziesięć procent czasu czeka na pamięć. Powyżej 40 maszyna jest praktycznie martwa. Plik istnieje jednak tylko wtedy, gdy w jądrze włączone jest Pressure Stall Information. Standardowe jądra Debiana i Ubuntu to mają, inne jądra niekoniecznie. Stąd zabezpieczenie przez test -e: jeśli pliku brakuje, wynik zostaje pusty, zamiast żebyś wziął No such file or directory za usterkę. PSI da się dołożyć przez parametr startowy jądra psi=1.

Które procesy faktycznie leżą w swapie, pokaże ten wiersz:

grep VmSwap /proc/*/status | sort -k2 -rn | head

Swap nic nie da również przeciwko limitowi cgroup (CONSTRAINT_MEMCG), przeciwko pamięci przypiętej przez mlock ani przeciwko JVM, której sterta jest skonfigurowana większa niż dostępny RAM. Garbage collector regularnie przechodzi przez całą stertę i natychmiast ściąga z powrotem każdą wypchniętą stronę.

Trzy narzędzia na wypadek, gdy swap nie wystarczy

zram zakłada skompresowany obszar wymiany bezpośrednio w pamięci RAM. Jest o rzędy wielkości szybszy niż plik na dysku i zależnie od charakteru danych daje efektywnie 20-40 procent więcej pamięci:

apt update
apt install -y zram-tools

Konfiguracja odbywa się w /etc/default/zramswap przez ALGO=zstdPERCENT=50, potem systemctl restart zramswap. Kontrola przez zramctl i ponownie swapon --show, gdzie pojawi się wtedy /dev/zram0. Przy zram vm.swappiness należy podnieść do 100-180, bo wypychanie stron jest tu tanie.

earlyoom wkracza, zanim jądro zamrozi system, i zabija celowo zamiast według heurystyki:

apt install -y earlyoom

/etc/default/earlyoom ustawiasz przez EARLYOOM_ARGS progi i chronisz ważne procesy, na przykład przez -m 5 -s 5 --avoid '(^|/)(sshd|systemd)$'. Dzięki temu logowanie po SSH pozostaje dostępne, podczas gdy pada proces pożerający pamięć.

Sztywne limity dla poszczególnych usług to najczystsze rozwiązanie, gdy konkretna usługa regularnie się wyrywa. Przez systemctl edit mariadb wpisujesz MemoryHigh=1200MMemoryMax=1500M. Usługa zostaje wtedy przyhamowana, a w razie potrzeby zakończona sama, zamiast pociągnąć za sobą cały serwer. Kontrola przez systemctl show mariadb -p MemoryMax.

Właściwą naprawą pozostaje jednak w większości przypadków konfiguracja aplikacji: innodb_buffer_pool_size na realistycznym poziomie, pm.max_children wyliczone z rzeczywistego zapotrzebowania pamięci na jeden proces roboczy, ustawione -Xmx dla każdej JVM. Swap to siatka bezpieczeństwa, a nie rozwiązanie.

Wycofanie zmian, jeśli rozwiązanie się nie sprawdzi

Droga powrotna jest krótka i powinna przebiegać w tej kolejności:

swapoff /swapfile

Przy mocno zapełnionym swapie polecenie może pracować kilka minut, bo wszystkie strony muszą wrócić do RAM. Jeśli zakończy się komunikatem swapoff: /swapfile: swapoff failed: Cannot allocate memory, w RAM nie ma miejsca na powrót danych i trzeba najpierw zatrzymać jakieś usługi. Dopiero po udanym swapoff usuń wiersz z fstab i skasuj plik:

rm /swapfile
swapon --show

Skasowanie pliku, dopóki jest on jeszcze podłączony, prowadzi do systemu, którego zarządzanie pamięcią wskazuje na nieistniejący inode. Kończy się to nieprzyjemnie. Na koniec jeszcze raz free -h i restart jako próba kontrolna.

Najczęstsze pytania

Ile swapa potrzebuję na serwerze?
Na serwerach nie obowiązuje już stara reguła o dwukrotności pamięci RAM. Rozsądne wartości to 1-2 GB przy 1 GB RAM, 2 GB przy 2 GB RAM oraz 2-4 GB przy 4-8 GB RAM. Od 16 GB wystarczą 4 GB. Swap, który naprawdę zapełnisz w całości, sprawia przez ciągłe wypychanie i wciąganie stron, że system przestaje reagować. Większy plik nie jest więc rezerwą, tylko dłuższą agonią.
Dlaczego journalctl -k nie pokazuje zabicia przez OOM, choć do niego doszło?
Bo opcja -k włącza w domyśle -b i pokazuje wyłącznie bieżące uruchomienie systemu. Jeśli serwer został po zdarzeniu zrestartowany, nie zobaczysz nic. Użyj journalctl -k -b -1 dla poprzedniego startu albo journalctl --since „7 days ago” --grep „Out of memory|oom-kill” dla wybranego okresu. Warunkiem jest trwały journal, co sprawdzisz poleceniem ls -d /var/log/journal, a na Debianie i Ubuntu ten katalog istnieje fabrycznie. Jeśli journalctl -k -b -1 odpowie zamiast tego „No journal boot entry found for the specified boot (-1)”, w journalu po prostu nie ma zapisanego wcześniejszego uruchomienia.
Po czym poznam, czy proces zakończyło jądro, czy limit systemd?
Po polu constraint w komunikacie jądra. CONSTRAINT_NONE oznacza, że pamięci zabrakło całemu systemowi, i tu swap pomoże. CONSTRAINT_MEMCG oznacza, że limit przekroczyła pojedyncza control group, i tu swap nie pomoże. Sprawdź dodatkowo systemctl show USLUGA -p MemoryMax oraz licznik oom_kill w pliku memory.events danej control group.
Dlaczego swapon kończy się błędem „Invalid argument”?
Albo zapomniano o mkswap, albo plik powstał przez fallocate i zawiera niezapisane obszary. W logu jądra pojawia się wtedy swapon: swapfile has holes. Zakładaj plik zamiast tego poleceniem dd if=/dev/zero. Na btrfs plik trzeba dodatkowo wcześniej oznaczyć przez truncate -s 0 i chattr +C jako nieobjęty mechanizmem copy-on-write, a to dopiero po swapoff /swapfile, bo opróżnienie podłączonego pliku swap każe jądru wskazywać na nieistniejące już bloki. Jeśli pracy odmawia już samo mkswap komunikatem „/swapfile is mounted; will not make swapspace”, pod tą ścieżką podłączony jest jeszcze aktywny swap, widoczny przez swapon --show.
Czy mogę skonfigurować swap w kontenerze?
Nie. LXC, OpenVZ i Docker korzystają z jądra systemu gospodarza i nie mogą włączyć własnego swapa, swapon kwituje to komunikatem „Operation not permitted”. Sprawdź to poleceniem systemd-detect-virt: przy kvm, qemu albo none działa własne jądro i swap jest możliwy. W kontenerze pomoże tylko więcej pamięci RAM albo przejście na pełną wirtualizację.
Czy vm.swappiness=0 oznacza, że nic już nie trafia do wymiany?
Nie. Od jądra 3.5 ta wartość blokuje jedynie wypychanie stron na zapas. Gdy pamięci zaczyna brakować, jądro i tak sięgnie po wymianę, zanim zakończy jakiś proces. Kto chce wyłączyć swap naprawdę, musi użyć swapoff. Zakres wartości sięga na wszystkich aktualnych jądrach Debiana i Ubuntu od 0 do 200, a domyślnie wszędzie ustawione jest 60.

Linux Swap Rozwiązywanie problemów Debian Ubuntu Administracja serwerem