Diagnosticando Swap Thrashing no Linux: Quando a Pressao de Memoria Causa Lentidao
O que e Swap Thrashing?
Conclusao: A memoria fisica esta esgotada, entao o kernel constantemente expulsa paginas para o swap (disco) e as le de volta. A CPU fica quase ociosa enquanto o I/O de disco satura, e todo o sistema fica extremamente lento. A causa raiz e "memoria insuficiente", mas o sintoma parece "o disco esta lento" ou "apenas o load average esta alto".
Quando a memoria fica escassa, o Linux move paginas raramente usadas para a area de swap (swap-out) para liberar RAM. Isso sozinho e normal. O problema comeca quando uma pagina expulsa e necessaria novamente quase imediatamente: le-la de volta (swap-in), expulsar outra pagina para abrir espaco, precisar daquela novamente, e assim por diante. Esse ciclo e thrashing, e a CPU gasta seu tempo esperando transferencias de paginas em vez de fazer trabalho real.
$ uptime 14:32:10 up 8 days, 3:11, 2 users, load average: 18.40, 16.92, 12.05
O load average dispara, mas o top mostra baixo uso de CPU (us/sy) e um alto wa (I/O wait). "A CPU esta ociosa mas tudo esta lento" e a assinatura classica de thrashing.
Premissas (ambiente alvo)
- SO: Ubuntu / Linux em geral
- Sintoma: o servidor de repente fica lento, nao responde, ate o SSH trava
- Swap esta habilitado (a linha Swap no
freenao e 0) - Voce pode ler
vmstat/free//proc(configuracoes permanentes requeremsudo)
Por que observar a taxa e nao o uso do swap?
Conclusao: Swap em uso nao e um problema por si so. Paginas de processos ociosos descansando no swap e saudavel. O perigo e quando o fluxo de swap-in / swap-out e continuo e rapido -- somente isso se correlaciona com a lentidao perceptivel. Julgue pela taxa (
vmstatsi/so), nao pelo uso (free).
Mesmo se free -h mostrar o Swap cheio, isso pode ser apenas "expulso ha muito tempo e deixado la", o que e inofensivo. Por outro lado, uso moderado de swap com trafego pesado por segundo fara o sistema parecer congelado.
| Aspecto | Saudavel | Thrashing |
|---|---|---|
Uso do swap (free) |
Estavel, mesmo se alto | Oscila rapido para cima e baixo |
si/so (vmstat) |
Proximo de 0 | Continuamente grande |
| CPU | Normal | Alto wa (I/O wait) |
| Sensacao | Normal | Cada acao esta lenta |
O indicador principal de thrashing nao e "quanto swap esta preenchido" mas "quanto esta sendo movido para dentro e fora por segundo agora". A primeira coisa a verificar sao as colunas si / so do vmstat.
Como observar primeiro? (vmstat / free)
Conclusao: Execute
vmstat 1. Sesi(swap-in KB/s) eso(swap-out KB/s) permanecerem grandes, o thrashing esta confirmado. Cruze com a margem disponivel comfree -he o altowacomtop.
Comece transmitindo o vmstat em intervalos de 1 segundo. A primeira linha e uma media desde o boot, mas cada linha subsequente cobre o ultimo segundo, entao voce ve o "fluxo" de si/so.
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 14 2087600 51200 10240 102400 4096 5120 4200 5300 3100 8900 3 4 8 85 0 1 12 2091200 48300 10100 101800 3800 4900 3900 5100 2980 8500 2 3 10 85 0
si / so continuam fluindo em megabytes por segundo e wa (I/O wait) esta acima de 80%. b (processos bloqueados) tambem esta alto. Isso e evidencia concreta de thrashing. Em seguida, verifique a margem disponivel.
$ free -h
total used free shared buff/cache available Mem: 3.8Gi 3.5Gi 120Mi 12Mi 180Mi 90Mi Swap: 2.0Gi 1.9Gi 80Mi
available e minusculo e o Swap esta quase cheio. A memoria fisica esta esgotada e nao e mais possivel descarregar para o swap. Confirme com top.
$ top -bn1 | head -5
top - 14:32:40 up 8 days, load average: 18.40, 16.92, 12.05 Tasks: 210 total, 1 running, 209 sleeping %Cpu(s): 3.0 us, 4.0 sy, 0.0 ni, 8.0 id, 85.0 wa, 0.0 hi, 0.0 si MiB Mem : 3891.0 total, 120.0 free, 3591.0 used, 180.0 buff/cache MiB Swap: 2048.0 total, 80.0 free, 1968.0 used
wa domina e id (idle) e minusculo. A CPU esta esperando a conclusao de I/O, nao computando.
Se o sar (pacote sysstat) estiver disponivel, voce pode revisar o historico com sar -W (pswpin/s, pswpout/s para swap-in/out) e sar -B (pgpgin/s, pgpgout/s para paginacao) para ver "quando comecou". Combinar o vmstat em tempo real com o historico do sar facilita identificar o momento de inicio.
Qual processo esta consumindo o swap?
Conclusao:
smem -s swap -re a forma mais legivel de ver o uso de swap por processo. Se osmemnao estiver disponivel, someVmSwapde/proc/<pid>/status. O maior consumidor de swap geralmente e a causa principal do thrashing.
O smem pode mostrar o uso de swap por processo diretamente (sudo apt install smem).
$ sudo smem -s swap -r | head
PID User Command Swap USS PSS RSS 2314 www-data java -Xmx3g -jar app.jar 1245184 210432 215300 240128 1190 mysql /usr/sbin/mysqld 412300 98200 101400 130560 1532 root /usr/bin/dockerd 120400 40100 42300 61440
O processo com a coluna Swap desproporcional e o culpado. Se voce nao pode instalar o smem (adicionar um novo pacote e indesejavel), some diretamente do /proc.
# Listar VmSwap de todos os processos, maior primeiro (KB)
$ for f in /proc/[0-9]*/status; do
awk '/^Name:/{n=$2} /^VmSwap:/{print $2, n, FILENAME}' "$f"
done 2>/dev/null | sort -rn | head1245184 java /proc/2314/status 412300 mysqld /proc/1190/status 120400 dockerd /proc/1532/status
Uma reserva de memoria mal configurada (um -Xmx da JVM maior que a RAM fisica, um buffer pool de banco de dados superdimensionado, etc.) e a causa tipica. Reduzir o limite para um valor que cabe na memoria fisica geralmente e a correcao real.
Alto uso de swap nao significa automaticamente "o culpado". Para encontrar "o processo movendo paginas para dentro e fora agora", capture o smem varias vezes durante o thrashing e observe quais processos tem um valor de Swap variavel. Um valor estatico sao apenas paginas dormindo.
Como parar a lentidao agora? (Primeiros socorros)
Conclusao: Parar um processo descontrolado ou superdimensionado, ou reduzir seu limite de memoria e reinicia-lo, e a correcao mais rapida. Para reiniciar o swap acumulado, use
swapoff -a && swapon -a, mas executa-lo sem memoria livre suficiente convida o OOM killer, entao e perigoso. Os primeiros socorros devem apenas ir na direcao de "liberar memoria".
O passo mais seguro e eficaz e parar ou reconfigurar o processo superdimensionado encontrado com smem.
# Reiniciar o culpado pelo caminho adequado (apos revisar sua configuracao) $ sudo systemctl restart myapp.service
Para "reiniciar" trazendo as paginas em swap de volta para a RAM, use swapoff -> swapon. Mas isso recarrega todo o conteudo do swap na memoria de uma vez, entao se a memoria fisica livre for menor que o uso do swap, o OOM killer e acionado.
# Perigoso: convida OOM se a memoria livre for menor que o uso do swap $ free -h # Confirme que available > Swap used primeiro $ sudo swapoff -a && sudo swapon -a
Nao execute swapoff -a casualmente no meio de thrashing. Ele tenta trazer cada pagina em swap de volta para a memoria, e se nao houver espaco suficiente, o kernel mata processos. Sempre pare o culpado e crie margem no free antes de executa-lo.
"Apenas reiniciar" faz o sintoma desaparecer, mas ele voltara a menos que voce corrija a configuracao de memoria ou o vazamento. Apos os primeiros socorros, sempre prossiga para identificar a causa raiz (configuracao superdimensionada / vazamento / RAM simplesmente insuficiente).
Deve-se ajustar o swappiness?
Conclusao:
vm.swappinesse um valor de tendencia (0-200, padrao 60; valores acima de 100 sao para swap rapido como zram/zswap) para "quao agressivamente usar swap". Reduzi-lo torna o kernel menos ansioso para expulsar paginas de aplicacao, o que pode melhorar a sensacao de um servidor interativo. Mas nao resolve a escassez de memoria fisica em si. A correcao real e mais RAM ou menos uso.
Verifique o valor atual.
$ cat /proc/sys/vm/swappiness
60
Reduza temporariamente e observe (reverte no reboot).
# Comece em torno de 10 em vez de 0 $ sudo sysctl -w vm.swappiness=10
Uma vez confirmado o efeito, torne permanente.
$ echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-swappiness.conf $ sudo sysctl --system
| swappiness | Tendencia | Indicado para |
|---|---|---|
| 0-10 | Evitar swap o maximo possivel | Servidores interativos, baixa latencia |
| 60 (padrao) | Equilibrado | Uso geral |
| 100 | Swap agressivamente | Batch, orientado a throughput |
| Acima de 100 (ate 200) | Swap ainda mais agressivamente | Swap rapido como zram/zswap |
Definir swappiness como 0 nao desabilita completamente o swap (ainda faz swap sob pressao de memoria). Reduzi-lo demais tambem desequilibra o cache de arquivos e pode criar um tipo diferente de lentidao. Evite valores extremos e ajuste observando vmstat para si/so se estabilizarem.
Como limitar o swap de um servico com cgroups?
Conclusao: Para um servico gerenciado pelo systemd,
MemoryMax/MemoryHighimpoem um limite de memoria e contem o thrashing para que um servico nao prejudique todo o host. Quando o limite e excedido, apenas aquele servico e submetido a recuperacao / OOM, e o restante fica protegido.
Defina um limite de memoria em um servico especifico (ex: uma aplicacao Java superdimensionada).
$ sudo systemctl edit myapp.service
Escreva os limites na secao [Service].
[Service] MemoryHigh=2G MemoryMax=2.5G
MemoryHigh e um "limite suave" que aciona recuperacao agressiva quando excedido; MemoryMax e um "limite rigido" que aciona OOM kill quando excedido. Aplique apos salvar.
$ sudo systemctl daemon-reload $ sudo systemctl restart myapp.service $ systemctl show -p MemoryMax myapp.service
Agora o uso de memoria do servico e limitado pelo cgroup e nao espalha mais thrashing por todo o sistema.
Definir MemoryHigh um pouco abaixo de MemoryMax cria uma zona de amortecimento onde o servico "e limitado e fica lento" antes de ser subitamente morto no limite rigido. Em producao, especificar ambos e mais seguro do que apenas MemoryMax.
E se a causa real for RAM insuficiente? (Adicionando Swap / Capacidade)
Conclusao: Se nao ha configuracao errada e nenhum vazamento, e a memoria e simplesmente sempre escassa, adicionar hardware (mais RAM) e o caminho correto. Adicionar swap e apenas um buffer "melhor do que morrer por OOM"; mesmo com mais swap, thrashing continua lento. Adicionar swap ganha tempo; adicionar RAM resolve.
Passos para adicionar um arquivo de swap para evitar OOM iminente (quando voce nao pode adicionar RAM imediatamente, ex: na nuvem).
# Criar um arquivo de swap de 2GB $ sudo fallocate -l 2G /swapfile $ sudo chmod 600 /swapfile $ sudo mkswap /swapfile $ sudo swapon /swapfile
Torne permanente adicionando ao /etc/fstab.
/swapfile none swap sw 0 0
Adicionar swap nao para a paginacao enquanto a memoria esta escassa, entao continua "lento". Adicionar swap e um paliativo para evitar OOM kills; nao cura a lentidao do thrashing em si. Se voce sofre thrashing cronico, mais RAM ou reduzir a carga de trabalho (reduzir limites de memoria por processo, reduzir concorrencia) e a abordagem correta.
Checklist quando ainda nao melhora
Conclusao: Thrashing significa que "memoria fisica insuficiente" esta confirmada. Confirme si/so com
vmstat-> identifique o culpado comsmem-> corrija a configuracao superdimensionada / vazamento -> adicione RAM se ainda insuficiente. A causa converge nessa camada. swappiness e cgroups sao sintomaticos; a raiz e o balanco com a quantidade de memoria.
- [ ] Confirmou que
si/sonovmstat 1estao continuamente grandes (taxa, nao uso)? - [ ] Confirmou que
wa(I/O wait) esta alto enquantous/syestao baixos notop? - [ ] Verificou a margem
availablee do Swap comfree -h? - [ ] Identificou o culpado com
smem -s swap -rou VmSwap em/proc/*/status? - [ ] A configuracao de memoria daquele processo (JVM
-Xmx, buffers de banco) cabe na RAM fisica? - [ ] Descartou vazamento de memoria (nao esta aumentando monotonicamente ao longo do tempo)?
- [ ] Confirmou
available > Swap usedantes dos primeiros socorros (swapoff)? - [ ] Considerou mais RAM / menos concorrencia se cronico?