Estrarre tutta la memoria scambiata di un processo dallo scambio


8

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.


Mi sembra che la "soluzione finale" possa lanciare un numero enorme di gdbistanze parallele se il processo da scambiare ha molti frammenti scambiati. Lo script lancerà gdbun'istanza parallela per ogni frammento (grande) scambiato per i 20 maggiori processi. Penso che si dovrebbe almeno aggiungere | tail -n20dopo aver awkpassato i risultati in whileloop per limitare i processi paralleli massimi a 400.
Mikko Rantalainen,

Risposte:


8

Puoi ottenere lo stesso risultato usando il comando 'dump memory' di GDB e farlo scrivere su / dev / null.

Devi solo trovare le regioni in / proc / $ PID / smaps che devono essere annullate. esempio da / proc / $ PID / smaps:

02205000-05222000 rw-p 00000000 00:00 0 
Size:              49268 kB
Rss:               15792 kB
Pss:                9854 kB
Shared_Clean:          0 kB
Shared_Dirty:      11876 kB
Private_Clean:         0 kB
Private_Dirty:      3916 kB
Referenced:          564 kB
Anonymous:         15792 kB
AnonHugePages:         0 kB
Swap:              33276 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

e quindi usa la modalità --batch per eseguire il comando gdb in modo da poterlo usare nella tua funzione:

[root@nunya ~]# swapon -s ; gdb --batch --pid 33795 -ex "dump memory /dev/null 0x02205000 0x05222000" ;swapon -s
Filename                Type        Size    Used    Priority
/dev/sda2                               partition   7811068 7808096 -1

[Thread debugging using libthread_db enabled]

Filename                Type        Size    Used    Priority
/dev/sda2                               partition   7811068 7796012 -1

Buona idea, l'ho migliorato un po 'più tardi, poi altre persone lo hanno migliorato ancora di più nel corso degli anni, ed è diventato github.com/wiedemannc/deswappify-auto
kubanczyk il
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.