impedire il blocco / la mancata risposta del sistema a causa dello scambio dell'uso della memoria di scappamento


48

Se un processo richiede molta memoria, il sistema sposta tutti gli altri processi nel file di scambio. Compreso, sembra, i processi necessari come il server X11 o il terminale.

Quindi, se un processo continua a essere allocato senza limiti, tutto non risponde, fino a quando quel processo non viene ucciso dal killer OOM. Il mio laptop sembra essere particolarmente sensibile e reagisce in modo estremamente negativo. Ho appena trascorso un'intera ORA in attesa del termine del processo durante il quale nemmeno il cursore del mouse può essere spostato.

Come può essere evitato?

1) Disabilita lo swap => Avvio spesso molti processi che diventano inattivi. Quelli inattivi dovrebbero essere spostati nello swap.

2) Ottieni un SSD => troppo costoso

3) imposta un limite massimo di memoria ulimit => ma poi fallisce nel caso in cui un programma abbia bisogno di una grande quantità di memoria risonabile. il problema non è che usa troppo, ma che sopprime gli altri processi

4) mantenere in memoria programmi importanti (X11, bash, kill, top, ...) e non scambiare mai quelli => è possibile farlo? Come? forse scambiare solo programmi di grandi dimensioni?

5)?


E ti è successo di nuovo :( Ha iniziato gcc mentre Firefox era in esecuzione, tutto è stato bloccato per mezz'ora. Nessun movimento del mouse, nessuna lettura di ebook
BeniBela,

Non sono sicuro di capire quello che vuoi. Vuoi che il sistema faccia magicamente le cose più velocemente con le risorse che ha? Vuoi che uccida i processi che utilizzano molta memoria prima?
David Schwartz,

Sembra che ciò di cui hai veramente bisogno sia più RAM. O meno attività in background "inattive".
Daniel B,

2
Puoi usare la combinazione di tasti Alt + SysRq + F per forzare l'esecuzione di OOM-killer. Questo può ridurre il tempo ridicolo necessario per attendere che il sistema apra una console in modo da poter terminare un processo.
hololeap,

Correggimi se sbaglio, ma in realtà questo problema sembra che il sistema stia cercando spazio di swap su disco che dovrebbe esistere ma non esiste (la partizione di swap è troppo piccola). Lo spazio di swap insufficiente comporterà il "blocco" del sistema sul disco rigido (o SSD) alla ricerca di spazio disponibile.
mchid

Risposte:


45

TL; DR

Breve temporaneo / risposta

  • Più semplice : avere una partizione di swap più piccola ed evitare che il kernel tenti di essere all'altezza della menzogna che non vi è alcun limite di memoria eseguendo processi dall'archiviazione lenta.
    • Con un grosso scambio, l'OOM (gestore di memoria esaurita) non interviene abbastanza presto. In genere, spiega in base alla memoria virtuale e, nella mia esperienza passata, non ha ucciso le cose fino a quando l'intero scambio non è stato riempito, quindi il sistema di thrashing e crawling ...
  • Hai bisogno di un grande scambio con l'ibernazione?
    • Tentativo / problematico : impostare alcune ulimits (ad es. Controllo ulimit -v, e magari impostare un limite rigido o soft utilizzando l' asopzione in limits.conf). Funzionava abbastanza bene, ma grazie all'introduzione di WebKit gigacage, molte app gnome ora si aspettano spazi di indirizzi illimitati e non riescono a funzionare!
    • Tentarono / problematica : La politica overcommit e il rapporto è un altro modo per cercare di gestire e mitigare questo (per esempio sysctl vm.overcommit_memory, sysctl vm.overcommit_ratioma questo approccio non ha funzionato per me.
    • Difficile / complicato : prova ad applicare una priorità cgroup ai processi più importanti (ad es. Ssh), ma questo sembra attualmente ingombrante per cgroup v1 (speriamo che v2 renderà più facile) ...

Ho anche trovato:

Soluzione a lungo termine

attendere e sperare che alcune patch upstream entrino in kernel distro stabili. Spero anche che i fornitori di distro sintonizzino meglio le impostazioni predefinite del kernel e sfruttino meglio i cgroup di sistema per dare priorità alla reattività della GUI nelle edizioni desktop.

Alcune patch di interesse:

Quindi non è solo il cattivo codice dello spazio utente e la distro config / default che è in errore - il kernel potrebbe gestirlo meglio.

Commenti su opzioni già considerate

1) Disabilita lo scambio

Si consiglia di fornire almeno una piccola partizione di swap ( abbiamo davvero bisogno di swap su sistemi moderni? ). La disabilitazione dello swap non solo impedisce lo scambio di pagine inutilizzate, ma potrebbe anche influire sulla strategia di sovraccarico euristico predefinita del kernel per l'allocazione della memoria ( cosa significa euristica in Overcommit_memory = 0? ), Poiché l'euristica conta sulle pagine di swap. Senza swap, l'overcommit può probabilmente funzionare nelle modalità euristiche (0) o sempre (1), ma la combinazione di no swap e la strategia di mai (2) overcommit è probabilmente un'idea terribile. Pertanto, nella maggior parte dei casi, nessuno swap comprometterà le prestazioni.

Ad esempio, pensa a un lungo processo che inizialmente tocca la memoria per un lavoro una tantum, ma poi non riesce a liberare quella memoria e continua a funzionare in background. Il kernel dovrà usare la RAM per questo fino al termine del processo. Senza alcuno scambio, il kernel non può cercarlo per qualcos'altro che in realtà vuole usare attivamente la RAM. Pensa anche a quanti sviluppatori sono pigri e non liberano esplicitamente memoria dopo l'uso.

3) impostare un limite massimo di memoria

Si applica solo per processo e probabilmente è un presupposto ragionevole che un processo non dovrebbe richiedere più memoria di un sistema fisicamente! Quindi è probabilmente utile impedire a un processo folle solitario di innescare il thrashing pur essendo generosamente impostato.

4) mantenere in memoria programmi importanti (X11, bash, kill, top, ...) e non scambiarli mai

Bella idea, ma poi quei programmi porteranno alla memoria che non stanno attivamente usando. Può essere accettabile se il programma richiede solo una modesta quantità di memoria.

La versione di systemd 232 ha appena aggiunto alcune opzioni che lo rendono possibile: penso che si potrebbe usare 'MemorySwapMax = 0' per impedire a un'unità (servizio) come ssh di scambiare memoria.

Tuttavia, sarebbe in grado di dare la priorità all'accesso alla memoria.

Lunga spiegazione

Il kernel Linux è più ottimizzato per i carichi di lavoro del server, quindi la reattività della GUI è stata purtroppo una preoccupazione secondaria ... Le impostazioni di gestione della memoria del kernel nell'edizione Desktop di Ubuntu 16.04 LTS non sembravano differire dalle altre edizioni del server. Corrisponde anche alle impostazioni predefinite in RHEL / CentOS 7.2 generalmente utilizzate come server.

OOM, ulimit e scambio di integrità per reattività

Scambiare il thrashing (quando il set di memoria funzionante, ovvero le pagine che vengono lette e scritte in un determinato intervallo di tempo supera la RAM fisica) bloccherà sempre l'I / O di archiviazione - nessuna procedura guidata del kernel può salvare un sistema da questo senza uccidere un processo o due...

Spero che le modifiche di Linux OOM in arrivo nei kernel più recenti riconoscano che questo set di lavoro superi la situazione della memoria fisica e uccida un processo. In caso contrario, si verifica il problema del thrashing. Il problema è che, con una grande partizione di swap, può sembrare che il sistema abbia ancora headroom mentre il kernel si impegna allegramente e serve ancora richieste di memoria, ma il set di lavoro potrebbe trasformarsi in swap, cercando efficacemente di trattare l'archiviazione come se è RAM.

Sui server, accetta la penalità prestazionale del thrashing per un compromesso determinato, lento, non perdere dati. Sui desktop, il compromesso è diverso e gli utenti preferirebbero un po 'di perdita di dati (sacrificio di processo) per mantenere le cose reattive.

Questa è stata una bella analogia comica su OOM: oom_pardon, ovvero non uccidere il mio xlock

Per inciso, OOMScoreAdjustè un'altra opzione di sistema per aiutare a ponderare ed evitare i processi di uccisione OOM considerati più importanti.

writeback bufferizzato

Penso che " Rendere il writeback in background non succhiare " aiuterà ad evitare alcuni problemi in cui un processo di hogging RAM provoca un altro scambio (scrittura su disco) e la scrittura in blocco su disco blocca qualsiasi altra cosa che desideri IO. Non è la causa stessa del problema, ma si aggiunge al degrado generale della reattività.

limitazione di ulimits

Un problema con ulimits è che la contabilizzazione di un limite si applica allo spazio degli indirizzi di memoria virtuale (che implica la combinazione sia dello spazio fisico che di quello di scambio). Secondo man limits.conf:

       rss
          maximum resident set size (KB) (Ignored in Linux 2.4.30 and
          higher)

Quindi l'impostazione di un ulimit da applicare solo all'utilizzo fisico della RAM non sembra più utilizzabile. Quindi

      as
          address space limit (KB)

sembra essere l'unico sintonizzatore rispettato.

Sfortunatamente, come spiegato più dettagliatamente dall'esempio di WebKit / Gnome, alcune applicazioni non possono essere eseguite se l'allocazione dello spazio di indirizzi virtuali è limitata.

i cgroups dovrebbero aiutare in futuro?

Attualmente, sembra ingombrante, ma è possibile abilitare alcuni flag di cgroup del kernel cgroup_enable=memory swapaccount=1(ad es. In grub config) e quindi provare a usare il controller di memoria di cgroup per limitare l'uso della memoria.

i cgroup hanno funzionalità di limite di memoria più avanzate rispetto alle opzioni 'ulimit'. Le note di CGroup v2 suggeriscono i tentativi di migliorare il funzionamento degli ulimits.

La memoria combinata + contabilità e limitazione degli swap è sostituita da un reale controllo sullo spazio di swap.

Le opzioni di CGroup possono essere impostate tramite le opzioni di controllo delle risorse di systemd . Per esempio:

  • MemoryHigh
  • MemoryMax

Altre opzioni utili potrebbero essere

  • IOWeight
  • CPUShares

Questi hanno alcuni inconvenienti:

  1. Overhead. La documentazione della docker corrente menziona brevemente l'1% di memoria in più e il 10% di degrado delle prestazioni (probabilmente per quanto riguarda le operazioni di allocazione della memoria - non specifica).
  2. Le cose in cgroup / systemd sono state pesantemente rielaborate di recente, quindi il flusso a monte implica che i venditori di distro Linux potrebbero essere in attesa che si risolva prima.

In CGroup v2 , suggeriscono che memory.highdovrebbe essere una buona opzione per limitare e gestire l'uso della memoria da parte di un gruppo di processi. Tuttavia, questa citazione suggerisce che il monitoraggio delle situazioni di pressione della memoria richiedeva più lavoro (a partire dal 2015).

È necessaria una misura della pressione della memoria - quanto il carico di lavoro viene influenzato dalla mancanza di memoria - è necessario per determinare se un carico di lavoro ha bisogno di più memoria; sfortunatamente, il meccanismo di monitoraggio della pressione della memoria non è ancora implementato.

Dato che gli strumenti per lo spazio utente di systemd e cgroup sono complessi, non ho trovato un modo semplice per impostare qualcosa di appropriato e sfruttarlo ulteriormente. La documentazione di cgroup e systemd per Ubuntu non è eccezionale. Il lavoro futuro dovrebbe essere per le distro con edizioni desktop per sfruttare cgroups e systemd in modo che, sotto alta pressione di memoria, ssh e i componenti X-Server / window manager ottengano un accesso più prioritario a CPU, RAM fisica e IO di archiviazione, per evitare di competere con i processi scambio occupato. Le funzionalità di priorità della CPU e I / O del kernel sono in circolazione da un po 'di tempo. Sembra essere un accesso prioritario alla RAM fisica che manca.

Tuttavia, nemmeno le priorità di CPU e I / O sono impostate correttamente !? Quando ho controllato i limiti del cgroup di sistema, le condivisioni della cpu, ecc. Applicate, per quanto potevo dire, Ubuntu non aveva inserito alcuna priorità predefinita. Ad esempio ho corso:

systemctl show dev-mapper-Ubuntu\x2dswap.swap

L'ho confrontato con lo stesso output per ssh, samba, gdm e nginx. Cose importanti come la GUI e la console di amministrazione remota devono combattere allo stesso modo con tutti gli altri processi quando si verifica un arresto.

Limiti di memoria di esempio che ho su un sistema RAM da 16 GB

Volevo abilitare l'ibernazione, quindi avevo bisogno di una grande partizione di swap. Quindi tentando di mitigare con ulimits, ecc.

ulimit

Ho inserito * hard as 16777216in modo /etc/security/limits.d/mem.conftale che nessun singolo processo possa richiedere più memoria di quanto sia fisicamente possibile. Non impedirò il thrashing tutti insieme, ma senza, solo un singolo processo con avido utilizzo della memoria o una perdita di memoria, può causare il thrashing. Ad esempio, ho visto gnome-contactssucchiare 8 GB + di memoria quando facevo cose banali come l'aggiornamento dell'elenco indirizzi globale da un server di scambio ...

Contatti Gnome che masticano RAM

Come si è visto ulimit -S -v, molte distro hanno questo limite rigido e definito come "illimitato" dato, in teoria, un processo potrebbe finire per richiedere molta memoria ma solo attivamente usando un sottoinsieme, e funzionare felicemente pensando che sia stato dato dire 24 GB di RAM mentre il sistema ha solo 16 GB. Il suddetto limite rigido farà sì che i processi che potrebbero essere stati in grado di funzionare correttamente per interrompersi quando il kernel rifiuta le loro avide richieste di memoria speculativa.

Tuttavia, cattura anche cose folli come i contatti di Gnome e invece di perdere la mia reattività desktop, ottengo un errore "memoria insufficiente":

inserisci qui la descrizione dell'immagine

Complicazioni che impostano ulimit per lo spazio degli indirizzi (memoria virtuale)

Sfortunatamente, ad alcuni sviluppatori piace far finta che la memoria virtuale sia una risorsa infinita e l'impostazione di un ulimit sulla memoria virtuale può interrompere alcune app. Ad esempio WebKit (da cui dipendono alcune app di gnome) ha aggiunto una gigacagefunzione di sicurezza che tenta di allocare quantità folli di memoria virtuale e si verificano FATAL: Could not allocate gigacage memoryerrori con un suggerimento sfacciato Make sure you have not set a virtual memory limit. La soluzione,GIGACAGE_ENABLED=norinuncia ai vantaggi di sicurezza, ma allo stesso modo, non poter limitare l'allocazione di memoria virtuale è anche rinunciare a una funzione di sicurezza (ad esempio il controllo delle risorse che può impedire la negazione del servizio). Ironia della sorte, tra gli sviluppatori di gigacage e gnome, sembrano dimenticare che limitare l'allocazione della memoria è di per sé un controllo di sicurezza. E purtroppo, ho notato che le app di gnome che si basano su gigacage non si preoccupano di richiedere esplicitamente un limite più alto, quindi anche un limite morbido rompe le cose in questo caso.

Ad essere onesti, se il kernel avesse fatto un lavoro migliore nel riuscire a negare l'allocazione della memoria basata sull'uso della memoria residente invece della memoria virtuale, allora far finta che la memoria virtuale fosse illimitata sarebbe meno pericoloso.

overcommit

Se si preferisce che alle applicazioni venga negato l'accesso alla memoria e si desidera interrompere il commit eccessivo, utilizzare i comandi seguenti per testare il comportamento del sistema in caso di alta pressione della memoria.

Nel mio caso, il rapporto di commit predefinito era:

$ sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50

Ma diventa pieno effetto quando si modifica la politica per disabilitare il sovracommissione e applicare il rapporto

sudo sysctl -w vm.overcommit_memory=2

Il rapporto implicava che solo 24 GB di memoria potessero essere allocati complessivamente (16 GB RAM * 0,5 + 16 GB SWAP). Quindi probabilmente non vedrei mai comparire OOM, ed è effettivamente meno probabile che i processi accedano costantemente alla memoria durante lo scambio. Ma probabilmente sacrificherò anche l'efficienza complessiva del sistema.

Ciò causerà il crash di molte applicazioni, dato che è comune che gli sviluppatori non gestiscano con grazia il sistema operativo che rifiuta una richiesta di allocazione della memoria. Scambia il rischio occasionale di un blocco tirato a causa di un thrashing (perdi tutto il lavoro dopo un hard reset) con un rischio più frequente di crash di varie app. Nei miei test, non ha aiutato molto perché il desktop stesso si è arrestato in modo anomalo quando il sistema era sotto pressione della memoria e non poteva allocare memoria. Tuttavia, almeno console e SSH funzionavano ancora.

In che modo funziona il sovraccarico della memoria virtuale della VM ha più informazioni.

Ho scelto di ripristinare le impostazioni predefinite per questo, sudo sysctl -w vm.overcommit_memory=0dato che l'intero stack grafico del desktop e le applicazioni in esso comunque si bloccano.


4
Questo è il miglior commento che ho visto sul problema e non ricorrere a "acquista più RAM!" Una cosa che non menzionate è il modo in cui giocano le opzioni di configurazione del kernel. Ad esempio, il modello di preemtion utilizzato o lo scheduler I / O utilizzato potrebbero avere effetti rilevanti su questo?
hololeap,

2
but the kernel won't be able to use an overcommit strategy for allocating memory and this will likely hurt performance. Even a smaller swap partition allows this. C'è qualche prova a questo? Credo che il sovraccarico del kernel vada bene senza che sia configurato lo swap
ygrek,

@ygrek, grazie, la formulazione sembra un po 'sbagliata - il sovraccarico funziona ancora senza scambio, a meno che non sia stata scelta la modalità di non sovraccarico (2). La modalità euristica predefinita di overcommit (0) o sempre commette (1) probabilmente funziona ancora senza scambio. Non riesco a ricordare dove ho letto che la disattivazione dello swap danneggia la capacità del codice di overcommit di allocare memoria (e quale modalità ha interessato in modo specifico). Googled di nuovo senza fortuna, ma questo era un post semi-utile: stackoverflow.com/questions/38688824/… Modificherò la risposta in modo appropriato.
JPvRiel,

Speravo che la patch di writeback in background mi avrebbe aiutato, ma sono su un kernel nuovissimo (4.14.81) e affronterò notevoli problemi di reattività con I / O su disco pesante (indipendentemente dal fatto che lo swap sia la causa o meno). Mi chiedo se il Device Manager o la mia crittografia LUKS stiano causando problemi di prestazioni in qualche modo. Ho davvero pochi indizi su come eseguire il debug di questo tipo di problema.
Darius Jahandarie,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.