Diagnosticando Swap Thrashing no Linux: Quando a Pressão de Memória Causa Lentidão
O que é Swap Thrashing?
Conclusão: A memória física está esgotada, então o kernel constantemente expulsa páginas para o swap (disco) e as lê de volta. A CPU fica quase ociosa enquanto o I/O de disco satura, e todo o sistema fica extremamente lento. A causa raiz é "memória insuficiente", mas o sintoma parece "o disco está lento" ou "apenas o load average está alto".
Quando a memória fica escassa, o Linux move páginas raramente usadas para a área de swap (swap-out) para liberar RAM. Isso sozinho é normal. O problema começa quando uma página expulsa é necessária novamente quase imediatamente: lê-la de volta (swap-in), expulsar outra página para abrir espaço, precisar daquela novamente, e assim por diante. Esse ciclo é thrashing, e a CPU gasta seu tempo esperando transferências de páginas 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 está ociosa mas tudo está lento" é a assinatura clássica de thrashing.
Premissas (ambiente alvo)
- SO: Ubuntu / Linux em geral
- Sintoma: o servidor de repente fica lento, não responde, até o SSH trava
- Swap está habilitado (a linha Swap no
freenão é 0) - Você pode ler
vmstat/free//proc(configurações permanentes requeremsudo)
Por que observar a taxa e não o uso do swap?
Conclusão: Swap em uso não é um problema por si só. Páginas de processos ociosos descansando no swap é saudável. O perigo é quando o fluxo de swap-in / swap-out é continuo e rápido -- somente isso se correlaciona com a lentidão perceptível. Julgue pela taxa (
vmstatsi/so), não pelo uso (free).
Mesmo se free -h mostrar o Swap cheio, isso pode ser apenas "expulso há muito tempo e deixado lá", o que é inofensivo. Por outro lado, uso moderado de swap com tráfego pesado por segundo fará o sistema parecer congelado.
| Aspecto | Saudável | Thrashing |
|---|---|---|
Uso do swap (free) |
Estável, mesmo se alto | Oscila rápido para cima e baixo |
si/so (vmstat) |
Próximo de 0 | Continuamente grande |
| CPU | Normal | Alto wa (I/O wait) |
| Sensação | Normal | Cada ação está lenta |
O indicador principal de thrashing não é "quanto swap está preenchido" mas "quanto está sendo movido para dentro e fora por segundo agora". A primeira coisa a verificar são as colunas si / so do vmstat.
Como observar primeiro? (vmstat / free)
Conclusão: Execute
vmstat 1. Sesi(swap-in KB/s) eso(swap-out KB/s) permanecerem grandes, o thrashing está confirmado. Cruze com a margem disponível comfree -he o altowacomtop.
Comece transmitindo o vmstat em intervalos de 1 segundo. A primeira linha é uma média desde o boot, mas cada linha subsequente cobre o último segundo, então você vê 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) está acima de 80%. b (processos bloqueados) também está alto. Isso é evidência concreta de thrashing. Em seguida, verifique a margem disponível.
$ 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 é minúsculo e o Swap está quase cheio. A memória física está esgotada e não é mais possível 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) é minúsculo. A CPU está esperando a conclusão de I/O, não computando.
Se o sar (pacote sysstat) estiver disponível, você pode revisar o histórico com sar -W (pswpin/s, pswpout/s para swap-in/out) e sar -B (pgpgin/s, pgpgout/s para paginação) para ver "quando começou". Combinar o vmstat em tempo real com o histórico do sar facilita identificar o momento de início.
Qual processo está consumindo o swap?
Conclusão:
smem -s swap -ré a forma mais legível de ver o uso de swap por processo. Se osmemnão estiver disponível, someVmSwapde/proc/<pid>/status. O maior consumidor de swap geralmente é 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 é o culpado. Se você não pode instalar o smem (adicionar um novo pacote é indesejável), 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 memória mal configurada (um -Xmx da JVM maior que a RAM física, um buffer pool de banco de dados superdimensionado, etc.) é a causa típica. Reduzir o limite para um valor que cabe na memória física geralmente é a correção real.
Alto uso de swap não significa automaticamente "o culpado". Para encontrar "o processo movendo páginas para dentro e fora agora", capture o smem várias vezes durante o thrashing e observe quais processos têm um valor de Swap variável. Um valor estático são apenas páginas dormindo.
Como parar a lentidão agora? (Primeiros socorros)
Conclusão: Parar um processo descontrolado ou superdimensionado, ou reduzir seu limite de memória e reiniciá-lo, é a correção mais rápida. Para reiniciar o swap acumulado, use
swapoff -a && swapon -a, mas executá-lo sem memória livre suficiente convida o OOM killer, então é perigoso. Os primeiros socorros devem apenas ir na direção de "liberar memória".
O passo mais seguro e eficaz é 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 páginas em swap de volta para a RAM, use swapoff -> swapon. Mas isso recarrega todo o conteúdo do swap na memória de uma vez, então se a memória física livre for menor que o uso do swap, o OOM killer é 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
Não execute swapoff -a casualmente no meio de thrashing. Ele tenta trazer cada página em swap de volta para a memória, e se não houver espaço suficiente, o kernel mata processos. Sempre pare o culpado e crie margem no free antes de executá-lo.
"Apenas reiniciar" faz o sintoma desaparecer, mas ele voltará a menos que você corrija a configuração de memória ou o vazamento. Após os primeiros socorros, sempre prossiga para identificar a causa raiz (configuração superdimensionada / vazamento / RAM simplesmente insuficiente).
Deve-se ajustar o swappiness?
Conclusão:
vm.swappinessé um valor de tendência (0-200, padrão 60; valores acima de 100 são para swap rápido como zram/zswap) para "quão agressivamente usar swap". Reduzi-lo torna o kernel menos ansioso para expulsar páginas de aplicação, o que pode melhorar a sensação de um servidor interativo. Mas não resolve a escassez de memória física em si. A correção real é 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 | Tendência | Indicado para |
|---|---|---|
| 0-10 | Evitar swap o máximo possível | Servidores interativos, baixa latência |
| 60 (padrão) | Equilibrado | Uso geral |
| 100 | Swap agressivamente | Batch, orientado a throughput |
| Acima de 100 (até 200) | Swap ainda mais agressivamente | Swap rápido como zram/zswap |
Definir swappiness como 0 não desabilita completamente o swap (ainda faz swap sob pressão de memória). Reduzi-lo demais também desequilibra o cache de arquivos e pode criar um tipo diferente de lentidão. Evite valores extremos e ajuste observando vmstat para si/so se estabilizarem.
Como limitar o swap de um serviço com cgroups?
Conclusão: Para um serviço gerenciado pelo systemd,
MemoryMax/MemoryHighimpõem um limite de memória e contêm o thrashing para que um serviço não prejudique todo o host. Quando o limite é excedido, apenas aquele serviço é submetido a recuperação / OOM, e o restante fica protegido.
Defina um limite de memória em um serviço específico (ex: uma aplicação Java superdimensionada).
$ sudo systemctl edit myapp.service
Escreva os limites na seção [Service].
[Service] MemoryHigh=2G MemoryMax=2.5G
MemoryHigh é um "limite suave" que aciona recuperação agressiva quando excedido; MemoryMax é um "limite rigido" que aciona OOM kill quando excedido. Aplique após salvar.
$ sudo systemctl daemon-reload $ sudo systemctl restart myapp.service $ systemctl show -p MemoryMax myapp.service
Agora o uso de memória do serviço é limitado pelo cgroup e não espalha mais thrashing por todo o sistema.
Definir MemoryHigh um pouco abaixo de MemoryMax cria uma zona de amortecimento onde o serviço "é limitado e fica lento" antes de ser subitamente morto no limite rigido. Em produção, especificar ambos é mais seguro do que apenas MemoryMax.
E se a causa real for RAM insuficiente? (Adicionando Swap / Capacidade)
Conclusão: Se não há configuração errada e nenhum vazamento, e a memória é simplesmente sempre escassa, adicionar hardware (mais RAM) é o caminho correto. Adicionar swap é 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 você não 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 não para a paginação enquanto a memória está escassa, então continua "lento". Adicionar swap é um paliativo para evitar OOM kills; não cura a lentidão do thrashing em si. Se você sofre thrashing crônico, mais RAM ou reduzir a carga de trabalho (reduzir limites de memória por processo, reduzir concorrência) é a abordagem correta.
Checklist quando ainda não melhora
Conclusão: Thrashing significa que "memória física insuficiente" está confirmada. Confirme si/so com
vmstat-> identifique o culpado comsmem-> corrija a configuração superdimensionada / vazamento -> adicione RAM se ainda insuficiente. A causa converge nessa camada. swappiness e cgroups são sintomáticos; a raiz é o balanco com a quantidade de memória.
- [ ] Confirmou que
si/sonovmstat 1estão continuamente grandes (taxa, não uso)? - [ ] Confirmou que
wa(I/O wait) está alto enquantous/syestão baixos notop? - [ ] Verificou a margem
availablee do Swap comfree -h? - [ ] Identificou o culpado com
smem -s swap -rou VmSwap em/proc/*/status? - [ ] A configuração de memória daquele processo (JVM
-Xmx, buffers de banco) cabe na RAM física? - [ ] Descartou vazamento de memória (não está aumentando monotonicamente ao longo do tempo)?
- [ ] Confirmou
available > Swap usedantes dos primeiros socorros (swapoff)? - [ ] Considerou mais RAM / menos concorrência se crônico?