A pressão de memória no kernel do Linux afeta diretamente os sistemas de alojamento: à medida que a pressão aumenta, o tempo de CPU e as operações de E/S são desviados para tarefas mais exigentes Reclaim, os tempos de resposta aumentam e os riscos de OOM crescem. Vou explicar claramente como identifico, avalio e resolvo a pressão sobre a memória, para que Hospedagem- Reagir de forma constante às cargas de trabalho.
Pontos centrais
Concentro-me nos fatores-chave que determinam o desempenho e as falhas em ambientes de alojamento. Os pontos seguintes constituem o fio condutor que orienta o meu diagnóstico e a minha otimização. Com esta visão geral, evito interpretações erradas de „RAM cheia“ e identifico os verdadeiros Pressão atempadamente.
- Métricas PSI mostram os tempos de espera em vez da mera ocupação e detetam atempadamente os atrasos.
- Carga de swap indica problemas de recuperação que agravam as operações de E/S e as latências.
- Limites dos cgroups controlar a limitação, a proteção e o comportamento em caso de OOM por serviço.
- Deslocamento da cache afeta diretamente o desempenho da Web e das bases de dados.
- Planeamento de capacidades e o ajuste mantêm a margem dinâmica e evitam o thrashing.
É assim que estruturo as minhas análises, desde o kernel até à aplicação, e implemento as medidas adequadas por ordem de prioridade. O foco mantém-se nos resultados mensuráveis efeitos, e não ao trabalho por prestações.
O que significa «Memory Pressure» no kernel do Linux?
A „pressão na memória“ significa que o kernel dedica um tempo considerável a libertar memória, em vez de dar continuidade ao trabalho dos processos do utilizador; a CPU passa então a dedicar-se cada vez mais a operações de leitura, gravação e evicção, enquanto as solicitações ficam em espera. Faço uma distinção clara entre „RAM cheia» e «falta de memória utilizável» espaço livre“: Um cache „cheio“ é saudável; os estrangulamentos só surgem quando os investimentos em recuperação aumentam. O kernel analisa as listas inativas, grava sujo-elimina páginas, limpa a cache de ficheiros e transfere páginas anónimas para o armazenamento externo assim que os valores de marca d'água são ultrapassados. O tempo gasto nestas atividades é determinante; reflete-se nos períodos de espera das tarefas e nos tempos de resposta prolongados. Um host pode funcionar de forma silenciosa com uma utilização de 95 %, desde que o cache seja facilmente recuperável, mas pode ficar gravemente bloqueado em condições de baixa utilização, quando as páginas anónimas ativas têm de ser substituídas.
Compreender e medir o PSI
A «Pressure Stall Information» (PSI) torna a pressão na memória tangível, porque não medo a ocupação, mas sim os atrasos. Em /proc/pressure/memory Vejo „some“ e „full“: „some“ descreve momentos em que pelo menos uma tarefa está à espera de memória, enquanto „full“ indica fases em que todas as tarefas estão paralisadas. Exemplo: „some avg10=4,67“ significa que, nos últimos 10 segundos, 4,67 % do tempo foram ocupados por bloqueios devido a estrangulamentos de memória; „full avg10=0,30“ indica bloqueios totais raros. Correlaciono precocemente os valores crescentes de „some“ com os tempos de resposta e procuro dimensionar, otimizar ou aliviar a carga antes que surjam erros graves de OOM. Esta perspetiva impede-me de me deixar enganar por uma RAM aparentemente „com muita memória livre“, pois as páginas livres sem acesso rápido Reclaim-Aproveitam pouco essa oportunidade.
| Variável medida | Valor indicativo | Sintoma | Ação |
|---|---|---|---|
| Memória PSI (média de 10) | > 2–3 % contínuo | Os tempos de resposta estão a aumentar | Verificar a margem de RAM, ajustar com precisão os limites do Cgroup |
| Memória PSI cheia (média de 10) | > 0,1 % percetível | Tempos de inatividade curtos | Identificar a causa, pôr fim ao thrashing |
| MemDisponível | < 10 % da RAM | Margem reduzida | Aliviar a carga do cache/trabalho, planear a capacidade |
| vmstat si/so | permanente > 0 | Pressão de troca | Swappiness/Ajustar swap, proteger o Hotset |
Sintomas em ambientes de alojamento
Em servidores com muita atividade, vejo primeiro picos de latência, enquanto a carga da CPU parece manter-se moderada; o kernel fica em loops de recuperação, a E/S fica congestionada e as solicitações ficam em espera. A média de carga sobe, apesar de os núcleos parecerem estar livres, porque muitas tarefas ficam bloqueadas na memória ou na E/S; isto é um sinal fundamental de aumento da Impressões. Valores persistentes de si/so no vmstat indicam que o sistema está a utilizar ativamente a memória de swap, o que retarda os handshakes TLS, os conteúdos dinâmicos e os percursos de consulta. Se esta situação não for resolvida, o sistema entra em «thrashing»: a CPU passa a maior parte do tempo com paging e swapping, em vez de realizar tarefas úteis. Nesta fase de escalada, o OOM-Killer intervém e encerra os processos com pontuação elevada; uma abordagem direcionada Análise do OOM-Killer ajuda-me a identificar padrões e configurações incorretas.
Relevância para cargas de trabalho de alojamento e cgroups
Em ambientes partilhados, basta uma única aplicação que consuma muitos recursos de memória para aumentar as latências para muitos clientes; os cgroups atenuam os efeitos, mas não resolvem o problema de uma dimensionação incorreta Instâncias. Em instâncias VPS e na nuvem, uma memória RAM insuficiente ou uma estratégia de swap inadequada conduzem mais rapidamente a picos de carga; o isolamento protege os outros serviços, mas não o próprio. As bases de dados dependem de grandes conjuntos de buffers; quando o Reclaim os liberta ou o swap intervém, os tempos de consulta aumentam e a taxa de débito diminui significativamente. As orquestrações de contentores utilizam os parâmetros `memory.low`, `memory.high` e `memory.max` para proteger serviços importantes, limitar os bloqueios e, em caso de emergência, encerrar-los de forma seletiva. Por isso, escolho os limites de forma consciente e monitorizo o PSI por serviço, para poder tomar medidas corretivas atempadamente e reservar recursos para serviços críticos Cargas de trabalho manter livre.
Estratégia de monitorização e métricas
Consulto os valores de MemAvailable, Buffers e Cached para perceber quanta memória é recuperável a curto prazo; os valores de MemFree, por si só, podem induzir facilmente em erro. Ao mesmo tempo, analiso o vmstat: valores persistentes de si/so indicam pressão de swap, o que estimula enormemente a E/S e aumenta as latências; para mais informações sobre o Utilização de swaps Utilizo padrões de diagnóstico comprovados. O PSI fornece-me o elemento que faltava, porque „some“ e „full“ quantificam os atrasos reais; emito alertas quando os limiares são atingidos e distingo picos de carga de estrangulamentos crónicos. As séries temporais obtidas através do sar ou da pilha de observabilidade tornam os padrões visíveis e ajudam-me a confirmar o sucesso dos ajustes. O dmesg revela eventos OOM que indicam limites rígidos ou configurações incorretas; assim, construo uma imagem coerente a partir da perspetiva do kernel, do comportamento de E/S e Aplicação.
Cargas de trabalho típicas sob pressão
Os servidores web como o Nginx ou o Apache fornecem conteúdos mais lentamente quando o Reclaim e o Swap estão a funcionar em segundo plano; as ligações Keep-Alive permanecem abertas por mais tempo, o que agrava as filas de espera. As pilhas de PHP e Python ocupam memória RAM devido a caches de frameworks, componentes JIT e dados de sessão; em caso de deslocamento, estes dados oscilam entre a RAM e o armazenamento, prolongando significativamente os tempos de resposta. As bases de dados perdem velocidade assim que os conjuntos de buffers diminuem ou partes deles são transferidas para o swap; mesmo uma latência adicional mínima por E/S acumula-se quando há muitas Consultas. Os serviços de cache, como o Redis ou o Memcached, dependem de acertos na RAM; se as áreas-chave forem transferidas para a área de swap, a vantagem perde-se e aumenta o risco de serem encerrados em situações de carga elevada. Em todos os casos, as métricas de PSI e de swap fornecem as indicações mais claras de que a memória se tornou o gargalo, e não a CPU.
Otimização do sistema e parâmetros do kernel
Começo pelo vm.swappiness: uma configuração moderadamente reduzida evita o uso excessivo da memória de swap, sem bloquear a recuperação necessária; avalio os efeitos de forma consistente com o PSI. Em seguida, otimizo o vm.dirty_ratio e os limites relacionados, para não desencadear longas ondas de flush e, ao mesmo tempo, não provocar uma enxurrada de pequenas gravações; ambos têm efeitos percetíveis Efeitos em termos de latências. Nos Cgroups v2, defino «memory.low» para serviços críticos, «memory.high» para limitação em caso de sobrecarga e «memory.max» como limite rígido com OOMs controláveis. Presto especial atenção às topologias NUMA: pode surgir pressão local, mesmo que ainda haja RAM livre a nível global; A vinculação de processos e de memória atenua essas armadilhas. Por fim, verifico o comportamento da cache de páginas; a substituição desnecessária reduz as taxas de acerto e custa tempo diretamente em cargas de trabalho da Web e de bases de dados, o que Otimização da cache de páginas fornece informações úteis.
Uma análise aprofundada dos percursos do Reclaim
Para escolher as medidas de forma acertada, faço a distinção entre kswapd e Recuperação Direta. O kswapd funciona de forma assíncrona quando os valores dos watermarks são ultrapassados para baixo; é relativamente suave, desde que exista cache suficiente que possa ser recuperado facilmente. O Direct Reclaim intervém de forma síncrona nos contextos de execução quando os threads necessitam urgentemente de páginas – é aqui que ocorrem os atrasos percetíveis pelos utilizadores. Observo se a recuperação afeta mais a cache de ficheiros ou as páginas anónimas: se o kernel libertar principalmente a cache de ficheiros, as falhas de cache aumentam; se libertar memória anónima (por exemplo, o heap), há risco de paragens bruscas e atividade de swap. Os mecanismos modernos de working set têm em conta as distâncias de refault para manter as páginas úteis durante mais tempo; se, mesmo assim, observar muitos refaults repetidos, sei que os hotsets são maiores do que o espaço disponível espaço livre tornaram-se.
Além disso, tenho em conta a compactação e a desfragmentação: kcompactd procura criar áreas contíguas, por exemplo, para grandes alocações ou THP. Se a compactação ficar para trás, observo um aumento da utilização da CPU no kcompactd, latências crescentes e um aumento da percentagem de PSI „full“ em picos de carga. Nesses casos, muitas vezes faz mais sentido reduzir a pressão ou ajustar as políticas de THP, em vez de simplesmente aumentar o „swap“.
Estratégias de swap em pormenor
O swap não é um inimigo, mas sim uma ferramenta – embora, se utilizado incorretamente, possa aumentar a latência. Faço a seguinte distinção:
- Sem swap: Seguro contra atrasos de swap, mas arriscado em picos – os OOMs ocorrem mais cedo, o Reclaim não tem uma reserva de segurança.
- Swap moderado num SSD rápido: É bom para transferir páginas anónimas pouco utilizadas para o disco; protege os conjuntos ativos na RAM, desde que os parâmetros de swappiness e os limites do cgroup estejam definidos de forma adequada.
- zswap/zram: A compressão alivia a carga de E/S; adequada para hosts com menor volume de E/S ou como buffer contra picos de carga de curta duração. Verifico a disponibilidade da CPU e a taxa de compressão para evitar que o sistema seja limitado pela CPU.
Não defino o valor de swappiness como baixo de forma generalizada; em cargas de trabalho com um cache de ficheiros grande, faz sentido definir um valor de swappiness ligeiramente mais elevado, para afastar páginas anónimas pouco utilizadas e manter o cache de ficheiros estável. Protejo os serviços críticos (por exemplo, bases de dados) com a opção `memory.low` e, se necessário, bloqueando os seus conjuntos ativos na RAM, para que o swap não afete o que não deve. O essencial é que vmstat si/so e o PSI diminui de forma consistente quando ajusto a estratégia; caso contrário, faço os ajustes necessários.
THP, compactação e fragmentação
Páginas enormes transparentes (THP) reduzem os acessos ao TLB e ajudam aplicações que exigem muito da CPU e consomem muita memória. No entanto, sob carga elevada, provocam trabalho de compactação; a opção „always“ pode, nesse caso, causar grandes paralisações. Utilizo o „madvise“ de forma seletiva para cargas de trabalho que beneficiam com isso (por exemplo, determinados motores em memória) e, no caso de pilhas web sensíveis à latência, prefiro desativar o THP de forma seletiva ou ativá-lo apenas através do «madvise». Além disso, observo vm.compaction_proactiveness e verifica se a compactação proativa adia a formação de estagnação ou se a reduz efetivamente. Se as faces do THP forem frequentemente fragmentadas ou se a compactação estiver a ocorrer a um ritmo acelerado, isso indica que há uma quantidade insuficiente de espaço livre ou padrões de alocação inadequados na aplicação.
Armadilhas NUMA e pressão local
Em hosts NUMA, a „RAM livre“ global é enganadora: um socket pode estar sobrecarregado, enquanto outro permanece ocioso. Verifico as estatísticas NUMA e ancoo processos localmente (vinculação de CPU/memória), para que os conjuntos ativos permaneçam próximos da carga de trabalho. A recuperação direta num nó, apesar das reservas globais, indica desequilíbrios NUMA; neste caso, as alocações intercaladas para serviços amplamente dispersos ou a vinculação rigorosa para cargas de trabalho monolíticas são úteis. O PSI por cgroup, combinado com as estatísticas NUMA, mostra-me se um único nó está a gerar as filas.
Medidas relacionadas com a aplicação
Analiso perfis de memória com o ps, o top, o htop e ferramentas de perfilagem para identificar os verdadeiros devoradores de memória e fugas; ao fazê-lo, observo como os conjuntos ativos (hotsets) evoluem ao longo do tempo. Escolho os caches das aplicações de forma consciente: se forem demasiado grandes, geram pressão; se forem demasiado pequenos, comprometem a velocidade; faço os ajustes com base no PSI e nos tempos de resposta, e não no instinto. Quando são detetados sinais de pressão, a aplicação pode libertar voluntariamente caches menos críticos ou dados temporários; assim, reduzo os bloqueios sem alterar os limites globais. Ajusto os parâmetros de arranque e o ajuste do GC (por exemplo, para JVMs) de forma a que os conjuntos de trabalho se mantenham corretamente na RAM; atenuo padrões de alocação agressivos através do processamento em lotes. Também mantenho sob vigilância os artefactos de compilação e os símbolos de depuração, pois resíduos ignorados têm um custo oculto Memória e aumentam o risco de perdas de sustentação posteriores.
Subtilezas do Cgroups v2 e estratégias OOM
Com o Cgroups v2, separo claramente a proteção, a limitação e os limites rígidos: memória.baixa Reserva margem de capacidade para serviços críticos; o restante é reatribuído a grupos menos importantes. memória.alta reduz o desempenho em caso de excedimento, através de uma limitação seletiva, e obriga as aplicações a libertar memória antes que o sistema seja afetado. memória.max é a última linha de defesa – se for ultrapassada, significa OOM num contexto controlado. Eu configuro PSI por cgroup, para que os alertas sejam acionados nos pontos onde ocorrem bloqueios; o PSI global permanece estável enquanto um único serviço entra em colapso – é precisamente este padrão que pretendo detetar. Juntamente com as prioridades OOM, defino regras de sacrifício claras: os trabalhadores em lote menos importantes são encerrados primeiro, enquanto as APIs do núcleo mantêm a sua espaço livre.
Virtualização: Ballooning, KSM e Overcommit
Em ambientes virtualizados, deparo-me com uma dupla pressão: o sistema convidado parece detetar memória RAM livre, enquanto o hipervisor, através de Balonismo retira. Este jogo aumenta os custos de recuperação para ambas as partes. Mido o PSI no convidado e cruzo os dados com as métricas do hipervisor; se o PSI aumentar durante eventos de ballooning, a VM necessita de mais capacidade garantida ou de melhores políticas de Cgroup no anfitrião. KSM Poupa RAM através da deduplicação de páginas idênticas, mas consome recursos da CPU; em configurações de alojamento com muitas máquinas virtuais semelhantes, pode valer a pena, desde que a carga adicional na CPU não comprometa os SLOs. Só planeio recorrer ao overcommit (por exemplo, a atribuição agressiva de muitas máquinas virtuais pequenas) com reservas fixas de SLO e uma gestão rigorosa memória.baixa para sistemas em que a latência é um fator crítico.
Decisões de arquitetura na hospedagem
Apostamos na distribuição horizontal, para que as instâncias individuais sofram menos picos de carga; os conjuntos escaláveis atenuam os picos e mantêm as latências mais baixas. Separo claramente as funções: bases de dados, aplicações e cache recebem os seus próprios conjuntos de recursos, para que os processos de recuperação não provoquem efeitos secundários inesperados além dos limites do sistema. Escolho o armazenamento tendo em conta a latência de gravação, pois as limpezas de páginas sujas (Dirty-Page-Flushes) têm um impacto direto nos tempos de resposta; um caminho rápido reduz sensivelmente os tempos de recuperação. Em clusters, prevejo reservas de RAM por nó e controlo através de políticas de agendamento, para que a carga e o consumo de memória se mantenham distribuídos de forma mais uniforme. Automatizo o dimensionamento com limiares PSI, para que valores crescentes de „some“ desencadeiem ações antes que se verifiquem travagens bruscas e Matar-ocorrências.
Planeamento de capacidade e modelos de margem de manobra
Defino o headroom de forma mensurável: mantenho reservas suficientes para que o „some“ PSI, em picos normais, permaneça abaixo de limiares definidos e para que o „full“ praticamente não ocorra. Para isso, utilizo percentis (por exemplo, o 99.º percentil da carga horária) e planeio 10–30 % de RAM adicional, dependendo da volatilidade da carga de trabalho. As bases de dados recebem reservas fixas maiores, enquanto os front-ends web escalam de forma mais dinâmica. Calibro os tempos de recuperação: com que rapidez o PSI e o si/so descem após um pico? Se permanecerem elevados, isso é um sinal de reservas insuficientes ou de uma estratégia de swap/dirty inadequada. Assim, o planeamento de capacidade torna-se um processo contínuo, em vez de uma estimativa anual.
Alerta e ajuste controlado por SLO
Associo o PSI aos SLOs dos utilizadores: se o „some avg10“ aumentar em simultâneo com as latências da API, intervenho. Classifico os alertas em „amarelo“ (permanente: 2–3 % „some“, „full“ próximo de 0) e „vermelho“ (mais de 5 % „some“ ou „full“ > 0,1 %). Os alarmes baseados em cgroups ajudam a isolar a minoria ruidosa. Além disso, defino alarmes para o aumento das filas «dirty» e dos tempos de espera de escrita, para que eu possa suavizar as ondas «dirty» atempadamente. O objetivo é que as medidas de ajuste (swappiness, memory.high, tamanhos de cache) sejam observáveis e reversíveis; implemento as alterações gradualmente e comparo o antes e o depois através das mesmas métricas.
Diagnóstico passo a passo no dia a dia
Primeiro, verifico o `free -h` e o `MemAvailable`: se o valor cair significativamente, procuro caches que possam ser devolvidos de forma útil e serviços com hotsets em crescimento. Depois, executo o `vmstat` com intervalos curtos para identificar tendências de si/so; o swapping prolongado confirma a pressão e leva-me ao caminho de E/S. Em seguida, leio o /proc/pressure/memory e analiso os valores „some“ e „full“ ao longo de 10, 60 e 300 segundos; associo diretamente as médias crescentes às latências observadas. O `dmesg` mostra-me vestígios de OOM e revela quais os processos que mais recentemente provocaram ou sofreram crises de memória; a partir daí, deduzo limites e prioridades para os Cgroups. Com base em tudo isto, formulo uma hipótese, implemento pequenos ajustes, verifico através do PSI e mantenho a Tempo de resposta num relance.
Manuais de procedimentos e cadeias de causas típicas
Há alguns padrões com os quais me deparo repetidamente:
- As tarefas de cópia de segurança ou de digitalização substituem a cache de páginas: De repente, as taxas de acerto da cache baixam e a Web/base de dados ficam mais lentas. Medida: reduzir a carga dos tarefas (prioridade de E/S), deslocar o intervalo de tempo, definir «memory.high» para o cgroup das tarefas e proteger o orçamento da cache de páginas dos serviços críticos.
- Fugas nos processos «worker»: Aumentos graduais da memória anónima; o PSI „some“ continua a subir ao longo de várias horas. Medida: identificar a fuga de memória, implementar políticas de reinício automático e reciclagem, definir limites de memória para que as fugas não ponham em risco todo o anfitrião.
- Perda de sustentação causada pelo THP: A carga do kcompactd aumenta durante os picos de tráfego. Medida: Definir o THP para „madvise“, ajustar os serviços afetados, verificar os parâmetros de compactação e aumentar a margem de segurança.
- Impressão local NUMA: Um socket está sobrecarregado, apesar de haver RAM livre a nível global. Medida: corrigir as afinidades, utilizar o interleave para cargas de trabalho amplamente distribuídas e ajustar a distribuição de carga no agendador.
- Swap em discos lentos: se o si/so aumentar, os tempos de resposta disparam. Medida: transferir o swap para um armazenamento mais rápido, avaliar o zswap/zram, ajustar a swappiness e as políticas do cgroup.
Cada runbook termina com uma validação: os valores „some/full“ aparecem e as latências estabilizam-se? Se não, a hipótese estava errada ou incompleta – nesse caso, continuo a iterar.
Ferramentas e traçado em funcionamento
Para além das ferramentas clássicas, aposto numa análise mais aprofundada: observo as relações entre a cache de páginas e os dados anónimos, as taxas de falhas de página, os padrões de refalha e as filas de writeback. As abordagens eBPF e de rastreamento indicam-me com precisão onde surgem os tempos de espera – por exemplo, ao longo dos percursos de recuperação, no writeback ou na alocação de blocos de grande dimensão. Para mim, é importante uma instrumentação eficiente e adequada para produção: janelas de ativação curtas, amostragem em vez de monitorização contínua e uma correlação clara com as métricas da aplicação. Assim, consigo identificar as causas antes de ajustar parâmetros em grande escala.
Pontos-chave e próximos passos
A «Memory Pressure» descreve o tempo perdido devido à escassez de memória, e não apenas à RAM ocupada; eu avalio-a com o PSI, identifico tendências numa fase precoce e tomo medidas com base nos dados. Quem analisar em conjunto o MemAvailable, o vmstat si/so, o PSI e o dmesg descobre as verdadeiras causas dos picos de latência e do thrashing. Através do ajuste dos parâmetros Swappiness, Dirty e Cgroup, reduzo os bloqueios de forma direcionada e garanto que os serviços importantes tenham o seu espaço livre. Ao nível da arquitetura, a distribuição horizontal, a definição clara das funções e os percursos rápidos de armazenamento atenuam as consequências de qualquer pico de carga. No final, o que importa é que eu relacione continuamente o diagnóstico com as medidas corretivas: medir, ajustar, medir novamente – até que o desempenho e Estabilidade voltar a servir.


