Come farebbe per estrarre rapidamente tutta la memoria scambiata di un processo dallo swap senza scrivere sul disco?
Il contesto su questo tema è banale, in quanto il problema sistemico che richiede la questione viene gestito da altre parti. Tuttavia, in questo momento, ho un problema in cui spesso devo liberare spazio di scambio su un nodo OpenVZ mentre il carico e l'attesa IO sono estremamente elevati.
Lo swap è spesso consumato principalmente da una manciata di processi MySQL e clamd in esecuzione su singoli contenitori. Il riavvio di questi servizi libera lo scambio e risolve il problema sul nodo, ma è indesiderabile per ovvi motivi.
Sto cercando un modo per liberare rapidamente lo swap da quei processi mentre il nodo è sovraccarico e ho bisogno di qualcosa di più veloce del mio metodo attuale:
unswap(){ [[ $1 && $(ls /proc/$1/maps) ]] && ((gcore -o /tmp/deleteme $1 &>/dev/null; rm -fv /tmp/deleteme.$1)&) 2>/dev/null || echo "must provide valid pid";};unswap
Questo dump core forza l'accesso a tutti i ram e quindi fa il lavoro di estrarlo dallo swap, ma devo ancora trovare un modo per evitare che si scriva su file. Inoltre, sembra che il processo sarebbe più veloce se potessi isolare gli intervalli di indirizzi che sono attualmente scambiati e scaricare tale porzione su / dev / null, ma devo ancora trovare un modo per farlo.
Questo è un nodo enorme, quindi il solito metodo swapoff / swapon richiede in modo proibitivo tempo e, di nuovo, la configurazione del nodo non è sotto il mio controllo, quindi correggere la causa principale non fa parte di questa domanda. Tuttavia, qualsiasi approfondimento su come potrei liberare rapidamente una parte significativa dello scambio senza uccidere / riavviare qualcosa sarebbe apprezzato.
Ambiente: CentOS 6.7 / OpenVZ
Aggiornamento per chiunque possa inciampare su questo in seguito:
Utilizzando l'input di Jlong, ho creato la seguente funzione:
unswap(){ (awk -F'[ \t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>0{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;};
È un po 'lento, ma fa esattamente ciò che è stato richiesto qui altrimenti. Probabilmente potrebbe migliorare la velocità trovando solo gli intervalli di indirizzi più grandi in swap e omettendo le iterazioni per le aree banalmente piccole, ma la premessa è solida.
Esempio funzionante:
#Find the process with the highest swap use
[~]# grep VmSwap /proc/*/status 2>/dev/null | sort -nk2 | tail -n1 | while read line; do fp=$(echo $line | cut -d: -f1); echo $line" "$(stat --format="%U" $fp)" "$(grep -oP "(?<=NameS).*" $fp); done | column -t
/proc/6225/status:VmSwap: 230700 kB root mysqld
#Dump the swapped address ranges and observe the swap use of the proc over time
[~]# unswap(){ (awk -F'[ t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>0{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;}; unswap 6225; while true; do grep VmSwap /proc/6225/status; sleep 1; done
VmSwap: 230700 kB
VmSwap: 230700 kB
VmSwap: 230676 kB
VmSwap: 229824 kB
VmSwap: 227564 kB
... 36 lines omitted for brevity ...
VmSwap: 9564 kB
VmSwap: 3212 kB
VmSwap: 1876 kB
VmSwap: 44 kB
VmSwap: 0 kB
Soluzione finale per lo scarico in blocco solo dei grossi pezzi di memoria scambiata:
unswap(){ (awk -F'[ \t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>1000{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;}; grep VmSwap /proc/*/status 2>/dev/null | sort -nk2 | tail -n20 | cut -d/ -f3 | while read line; do unswap $line; done;echo "Dumps Free(m)"; rcount=10; while [[ $rcount -gt 0 ]]; do rcount=$(ps fauxww | grep "dump memory" | grep -v grep | wc -l); echo "$rcount $(free -m | awk '/Swap/{print $4}')"; sleep 1; done
Devo ancora determinare se questo metodo rappresenta un rischio per la salute del processo o del sistema, specialmente se eseguito contemporaneamente su più processi. Se qualcuno ha una visione di qualsiasi potenziale effetto che ciò potrebbe avere sui processi o sul sistema, non esitate a commentare.
gdb
istanze parallele se il processo da scambiare ha molti frammenti scambiati. Lo script lanceràgdb
un'istanza parallela per ogni frammento (grande) scambiato per i 20 maggiori processi. Penso che si dovrebbe almeno aggiungere| tail -n20
dopo averawk
passato i risultati inwhile
loop per limitare i processi paralleli massimi a 400.