¿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.
gdb
instancias de paraller si el proceso a intercambiar tiene muchos fragmentos intercambiados. El script iniciará lagdb
instancia de paraller para cada fragmento (grande) intercambiado para los 20 procesos más importantes. Creo que hay que añadir al menos| tail -n20
después de laawk
antes de pasar los resultados awhile
lazo a los procesos paraller límite máximo de 400.