Como alguém poderia extrair rapidamente toda a memória trocada de um processo sem precisar gravar no disco?
O contexto sobre esse assunto é trivial, pois o problema sistêmico que exige a questão está sendo tratado por outras partes. No entanto, no momento, tenho um problema em que frequentemente tenho que liberar espaço de troca em um nó OpenVZ enquanto a carga e a espera de E / S são extremamente altas.
A troca geralmente é consumida principalmente por um pequeno punhado de processos MySQL e clamd executados em contêineres individuais. Reiniciar esses serviços libera a troca e resolve o problema no nó, mas é indesejável por razões óbvias.
Estou procurando uma maneira de liberar rapidamente a troca desses processos enquanto o nó está sobrecarregado e precisa de algo mais rápido que o meu método atual:
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
Esse dump principal força todo o ram a ser acessado e, portanto, faz o trabalho de retirá-lo do swap, mas ainda não encontrei uma maneira de evitar a gravação no arquivo. Além disso, parece que o processo seria mais rápido se eu pudesse isolar os intervalos de endereços atualmente trocados e apenas despejar essa parte em / dev / null, mas ainda não encontrei uma maneira de fazer isso.
Como é um nó enorme, o método usual swapoff / swapon consome tempo proibitivamente e, novamente, a configuração do nó não está sob meu controle, portanto, corrigir a causa raiz não faz parte dessa questão. No entanto, qualquer insight sobre como eu poderia liberar uma parte significativa do swap rapidamente sem matar / reiniciar nada seria apreciado.
Ambiente: CentOS 6.7 / OpenVZ
Atualize para qualquer um que possa tropeçar nisso mais tarde:
Usando a entrada de Jlong, criei a seguinte função:
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;};
É um pouco lento, mas faz exatamente o que foi solicitado aqui caso contrário. Provavelmente, poderia melhorar a velocidade encontrando apenas os maiores intervalos de endereços em troca e omitindo as iterações para as áreas trivialmente pequenas, mas a premissa é sólida.
Exemplo de trabalho:
#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
Solução final para dumping em massa apenas os grandes blocos de memória trocada:
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
Ainda estou para determinar se esse método representa algum risco para a saúde do processo ou sistema, especialmente quando repetidos vários processos simultaneamente. Se alguém tiver conhecimento de qualquer efeito potencial que isso possa ter nos processos ou no sistema, sinta-se à vontade para comentar.
gdb
instâncias paralelas se o processo a ser trocado tiver muitos fragmentos trocados. O script iniciará umagdb
instância paralela para cada fragmento trocado (grande) dos 20 maiores processos. Eu acho que se deve, pelo menos, adicionar| tail -n20
após aawk
antes de passar os resultados parawhile
loop para processos limite máximo Paraller a 400.