Extraer toda la memoria intercambiada de un proceso de intercambio


8

¿Cómo se podría extraer rápidamente toda la memoria intercambiada de un proceso sin escribir en el disco?

El contexto sobre este tema es trivial, ya que el problema sistémico que requiere la pregunta está siendo manejado por otras partes. Sin embargo, en este momento, tengo un problema en el que con frecuencia tengo que liberar espacio de intercambio en un nodo OpenVZ mientras la carga y la espera de E / S son extremadamente altas.

El intercambio a menudo es consumido principalmente por un pequeño puñado de procesos MySQL y clamd que se ejecutan en contenedores individuales. Reiniciar estos servicios libera el intercambio y resuelve el problema en el nodo, pero no es deseable por razones obvias.

Estoy buscando una forma de liberar rápidamente el intercambio de esos procesos mientras el nodo está sobrecargado y necesito algo más rápido que mi método actual:

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

Este volcado del núcleo obliga a acceder a todos los RAM y, por lo tanto, hace el trabajo de sacarlo del intercambio, pero aún no he encontrado una manera de evitar que se escriba en el archivo. Además, parece que el proceso sería más rápido si pudiera aislar los rangos de direcciones que se intercambian actualmente y simplemente volcar esa parte en / dev / null, pero aún no he encontrado una manera de hacerlo.

Este es un nodo enorme, por lo que el método habitual de intercambio / swapon consume mucho tiempo y, de nuevo, la configuración del nodo no está bajo mi control, por lo que solucionar la causa raíz no es parte de esta pregunta. Sin embargo, cualquier idea de cómo podría liberar una porción significativa de intercambio rápidamente sin matar / reiniciar nada sería apreciada.

Entorno: CentOS 6.7 / OpenVZ

Actualización para cualquiera que pueda tropezar con esto más tarde:

Usando la entrada de Jlong, creé la siguiente función:

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;};

Es un poco lento, pero hace exactamente lo que se solicitó aquí de lo contrario. Probablemente podría mejorar la velocidad al encontrar solo los rangos de direcciones más grandes en el intercambio y omitir las iteraciones para las áreas trivialmente pequeñas, pero la premisa es sólida.

Ejemplo de trabajo:

#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

Solución final para el volcado masivo de los grandes trozos de memoria intercambiada:

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 

Todavía tengo que determinar si este método plantea algún riesgo para la salud del proceso o sistema, especialmente cuando se enlazan en múltiples procesos al mismo tiempo. Si alguien tiene una idea de cualquier efecto potencial que esto pueda tener en los procesos o el sistema, no dude en comentar.


Me parece que la "solución final" puede lanzar una gran cantidad de gdbinstancias de paraller si el proceso a intercambiar tiene muchos fragmentos intercambiados. El script iniciará la gdbinstancia de paraller para cada fragmento (grande) intercambiado para los 20 procesos más importantes. Creo que hay que añadir al menos | tail -n20después de la awkantes de pasar los resultados a whilelazo a los procesos paraller límite máximo de 400.
Mikko Rantalainen

Respuestas:


8

Puede lograr el mismo resultado utilizando el comando 'volcar memoria' de GDB y hacer que escriba en / dev / null.

Solo necesita encontrar las regiones en / proc / $ PID / smaps que necesitan ser cambiadas. ejemplo de / 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

y luego use --batch mode para ejecutar el comando gdb para que pueda usarlo en su función:

[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

Buena idea, lo mejoré un poco más tarde, luego otras personas lo mejoraron aún más a lo largo de los años, y se convirtió en github.com/wiedemannc/deswappify-auto
kubanczyk
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.