Retirando toda a memória trocada de um processo da troca


8

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.


Parece-me que a "solução final" pode lançar um grande número de gdbinstâncias paralelas se o processo a ser trocado tiver muitos fragmentos trocados. O script iniciará uma gdbinstância paralela para cada fragmento trocado (grande) dos 20 maiores processos. Eu acho que se deve, pelo menos, adicionar | tail -n20após a awkantes de passar os resultados para whileloop para processos limite máximo Paraller a 400.
Mikko Rantalainen

Respostas:


8

Você pode obter o mesmo resultado usando o comando 'dump memory' do GDB e gravá-lo em / dev / null.

Você só precisa encontrar as regiões em / proc / $ PID / smaps que precisam ser desassociadas. exemplo 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

e use o modo --batch para executar o comando gdb para que você possa usá-lo em sua função:

[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

Boa ideia, eu melhorei um pouco mais tarde, em seguida, outras pessoas melhorou ainda mais ao longo dos anos, e tornou-se github.com/wiedemannc/deswappify-auto
kubanczyk
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.