...

Fragmentação da memória no funcionamento do servidor: causas e soluções

A fragmentação da memória no funcionamento do servidor significa que blocos grandes e contíguos já não estão disponíveis apesar da RAM livre e que as atribuições críticas falham. Apresento as causas, os sintomas típicos e as contramedidas direcionadas para que Servidor reagem de uma forma calculável e as afectações podem ser fiáveis função.

Pontos centrais

  • Interno e externo Diferenciar e abordar especificamente a fragmentação.
  • Atribuição de amigos compreender: Pedidos, divisões, fusões em falta.
  • Esquiador de fundo-Definir corretamente as cargas de trabalho, a sobrecarga do hipervisor e o THP.
  • Diagnóstico com buddyinfo, vmstat e métricas de compactação.
  • Padrão de afetação melhorar: Agrupamentos, pré-atribuição, tempos de vida separados.

O que significa a fragmentação da memória na utilização quotidiana do servidor?

Chamo-lhe Memória A fragmentação é o estado em que a memória de trabalho livre se divide em muitas pequenas lacunas e os grandes pedidos deixam de receber uma área contígua. A fragmentação interna ocorre quando um bloco alocado é maior do que a necessidade real e bytes não utilizados são deixados no bloco, o que pode levar ao Eficiência é reduzida. A fragmentação externa ocorre quando as secções livres são distribuídas e já não se juntam para formar uma grande área, apesar de haver suficiente RAM livre no total. É precisamente aqui que os grandes buffers, as reservas JIT ou os controladores que favorecem a memória contígua falham devido à escassez aparentemente paradoxal de grandes blocos. Nos ambientes de alojamento, as elevadas cargas paralelas, os longos tempos de atividade e as pilhas de software heterogéneas agravam este problema. Dinâmica percetível.

Como o Linux-Buddy-Allocator cria fragmentação

O kernel Linux gere a memória física através de um Amigo-que organiza as páginas em classes de tamanho (ordens), começando em 4 KB. Se os processos solicitarem áreas maiores, o kernel divide os blocos grandes em companheiros até que um tamanho adequado esteja disponível; ao liberar, ele tenta reunir os companheiros. No entanto, as diferentes durações dos pedidos, a alteração dos tempos de vida e a libertação irregular impedem a remontagem e incentivam a utilização de ficheiros externos. Fragmentação. Com o tempo, o stock de grandes encomendas esvazia-se, enquanto as pequenas encomendas aumentam - /proc/buddyinfo mostra então números elevados nas encomendas baixas e zeros nas encomendas altas. A partir deste momento, a compactação e possivelmente o comportamento OOM intervêm com mais frequência, o que cria latências e aumenta as interrupções.

Causas em ambientes de alojamento e virtualização

As cargas de trabalho de longa duração da Web e da base de dados criam um padrão variável de atribuições que divide os grandes blocos e permite a posterior Fundir impedido. As estruturas e bibliotecas que libertam memória tardiamente ou de forma descoordenada deixam lacunas nas quais só podem ser acomodados pequenos pedidos. A virtualização acrescenta a sua própria sobrecarga e transfere as atribuições para o convidado e para o hipervisor, o que significa que os Fragmentação é criado mais rapidamente. Valores vm.min_free_kbytes definidos incorretamente aumentam a pressão porque o kernel tem poucos buffers para alocações atómicas ou reserva-os em excesso. Mais transparência sobre Memória virtual ajuda-me a organizar a interação entre o alocador de convidados, o THP, o Huge Pages e o hipervisor.

Efeitos no desempenho e na experiência do utilizador

Se o depósito estiver dividido em várias pequenas ilhas, o Latências, porque o kernel comprime e desloca-se com mais frequência antes de poder lidar com grandes pedidos. As aplicações que requerem áreas contínuas - como bases de dados, caches ou pipelines multimédia - vacilam mais rapidamente. Apesar da RAM „livre“, as grandes alocações falham e geram mensagens de erro, reinícios ou cancelamentos forçados, o que pode causar sessões e Transacções prejudicado. As actividades em segundo plano, como a compactação, aumentam a carga da CPU e a pressão de E/S, fazendo com que mesmo as cargas de trabalho leves pareçam mais lentas. Em cenários de alojamento, esta situação manifesta-se em tempos de resposta longos, timeouts esporádicos e um escalonamento mais fraco durante os picos de carga.

Diagnóstico: Do buddyinfo às métricas de compactação

Eu primeiro verifico /proc/buddyinfo para ver qual Encomendas O vmstat e o sar mostram com que frequência o kernel compacta ou se o caminho OOM se tornou ativo, o que indica a pressão de grandes alocações. Utilizo o perf e o strace para reconhecer se as threads estão à espera de compactação direta e, por conseguinte, os tempos de resposta flutuam, o que é visível nos registos e nas métricas. Em ambientes com servidores Windows, visualizo heaps fragmentados com ferramentas de depuração para verificar se existem grandes lacunas e afinar os parâmetros de heap. ajustar. Também meço o maior bloco livre, porque a soma da RAM livre não é suficiente como diagnóstico.

Ajuste do kernel e da VM na prática

Eu defino vm.min_free_kbytes moderadamente mais alto, muitas vezes no corredor de 5-10 % de RAM, para que o kernel tenha grandes, atómicos Pedidos de informação pode ser operado de forma fiável. Eu ativo as páginas enormes transparentes com precaução: a pedido ou através do madvise, dependendo do perfil de carga e do risco de fragmentação. As páginas enormes estáticas oferecem previsibilidade, mas exigem um planeamento adequado para não causar problemas noutros locais. Estrangulamentos para criar ordem. A compactação desencadeia a ordem a curto prazo, mas não substitui uma solução estrutural para padrões permanentes e instáveis. Incluo topologias NUMA no ajuste para que as grandes alocações permaneçam locais e não se espalhem pelos nós.

Definição Objetivo Benefício Nota
vm.min_free_kbytes Reserva para grandes afectações Menos picos de OOM/compactação Aumentar gradualmente e medir o valor
THP (sobre/aconselhar) Favorecer páginas maiores Menos fragmentação, melhor rácio TLB Preste atenção às latências da carga de trabalho
Páginas enormes (estático) Reserva de áreas contínuas Grandes blocos previsíveis Planear a capacidade com antecedência
Compactação Áreas livres de contratos Blocos temporariamente maiores Aumenta a CPU/I&O a curto prazo
NUMA-Política Atribuição local segura Menor latência, menos tráfego cruzado Configurar o equilíbrio

Zonas de armazenamento, tipos de migração e porque é que o „inamovível“ bloqueia tudo

O alocador de páginas funciona não só com ordens, mas também com zonas (DMA, DMA32, Normal, Móvel) e Migrar tipos (MÓVEL, IMÓVEL, RECUPERÁVEL). Os grânulos para isto são os „pageblocks“. Assim que as páginas NÃO MÓVEIS (por exemplo, estruturas do kernel, páginas fixadas pelos drivers) entram num bloco de páginas, o kernel marca este bloco como difícil de mover. São precisamente estes blocos „contaminados“ que impedem a Compactação de combinar áreas livres em grandes blocos contíguos Áreas formulários. Por isso, planeio conscientemente a capacidade em ZONE_MOVABLE (sempre que possível) e asseguro que os dados da aplicação são predominantemente atribuídos como MOVABLE. Isso significa que reservas grandes e contíguas têm maior probabilidade de permanecerem disponíveis. Para cargas de trabalho com altos requisitos de DMA, uso reservas direcionadas para que as páginas UNMOVABLE não destruam a zona normal ampla.

Desenho de padrão de atribuição limpo

Agrupo as necessidades de armazenagem de acordo com Vida útilos objectos de curta duração em pools, os objectos de longa duração em regiões separadas, de modo a que os lançamentos não destruam tudo em toda a linha. Eu agrupo tamanhos frequentes em pools fixos para reduzir a flutuação de pedidos e aliviar o buddy allocator. Planeio previamente grandes buffers no início, em vez de os pedir no meio do tráfego, o que evita picos de carga quando se juntam. Adapto os pedidos de alinhamento às necessidades reais, uma vez que os alinhamentos excessivos desperdiçam espaço e incentivam o alinhamento interno. Fragmentação. Nos pipelines de criação e implementação, testo os caminhos de armazenamento com cenários de carga antes de o tráfego entrar em direto.

Seleção de alocadores no espaço do utilizador: glibc, jemalloc, tcmalloc

Nem toda a fragmentação é um problema do kernel. O Espaço do utilizador-O malloc da glibc usa arenas por thread; em muitos núcleos isso pode levar a uma alta fragmentação interna. Eu limito o número de arenas e corto de forma mais agressiva para que as áreas não utilizadas retornem ao sistema operacional mais rapidamente. Alternativas como jemalloc ou tcmalloc oferecem classes de tamanho mais finas e padrões de compartilhamento mais consistentes, o que pode reduzir visivelmente a fragmentação externa. O fator decisivo é: Eu meço sob carga de produção, porque cada alocador tem diferentes compensações em termos de latência, taxa de transferência e espaço de memória. Para serviços com elevado débito e tamanhos de objectos uniformes, as arenas dedicadas ou os pools do tipo slab proporcionam frequentemente o desempenho mais estável. Latências.

Medidas do lado da aplicação: Java, PHP, caches e bases de dados

Em Java, utilizo Arenas ou alocador de região e escolher perfis de GC que favoreçam reservas grandes e contíguas ao invés de constantemente quebrar a pilha em pedaços pequenos. Equilibro o Xms/Xmx de modo a que a pilha não esteja constantemente a crescer e a diminuir, uma vez que esta bombagem encoraja a existência de buracos. Para pilhas PHP e MySQL, utilizo pools de memória fixa, limito objectos de grandes dimensões e optimizo os tamanhos dos buffers com o objetivo de obter padrões de alocação consistentes; conhecimentos práticos mais aprofundados estão reunidos na página sobre Otimização de PHP/MySQL. Organizo os sistemas de cache (por exemplo, caches de objectos ou de páginas) para que os lançamentos não deixem grandes lacunas a toda a hora. Se nada mais ajudar, planeio reinícios controlados em janelas de manutenção em vez de arriscar eventos OOM não planeados que podem destruir todo o sistema. Serviços para anular.

Prática de contentores e Kubernetes

Os contentores não alteram a funcionalidade do Amigo-alocadores - apenas segmentam vistas e limites. A fragmentação, portanto, continua sendo um problema do host, mas se manifesta nos pods por meio de despejos, latências flutuantes ou custos de divisão do THP. Eu alcanço a estabilidade através de:

  • Definir classes de QoS (Garantido/Burstable) para que os pods críticos recebam reservas fixas e não cresçam e diminuam ao mesmo tempo.
  • limites de memória de forma realista, de modo a que o corte e a recuperação não violem permanentemente os limites de memória. Limites colidem.
  • THP/Hugepages consistentemente em todo o host e fornece pods que precisam de páginas grandes com pools reservados estaticamente.
  • Utilizar estratégias de aquecimento (pré-falha, pré-atribuição) para que os blocos grandes sejam ocupados mais cedo e não sejam solicitados mais tarde sob carga.

Monitorizo nós contentorizados como se fossem bare metal: buddyinfo, eventos de compactação, OOM kills - só que também correlaciono com reinícios e despejos de pods para separar a causa de forma limpa.

Virtualização, NUMA e influências do hardware

Entre os hipervisores, verifico como interagem o alocador de convidado, o ballooning e o THP do anfitrião, porque as camadas podem aumentar a fragmentação e criar grandes Blocos torna-o escasso. Observo consistentemente as topologias NUMA: a atribuição local reduz a latência e impede que os pedidos de grande dimensão sejam distribuídos pelos nós e, por conseguinte, sejam reduzidos. Quando faz sentido, coloco as cargas de trabalho nos nós NUMA e observo o efeito nas falhas de página e nos acessos ao TLB. Para um controlo mais rigoroso, defino diretrizes para os nós de armazenamento e retiro Balanceamento NUMA de uma forma direcionada. Incluo também actualizações de firmware e microcódigo para poder excluir efeitos secundários inesperados e garantir a previsibilidade com grandes Requisitos receber.

Controlador de dispositivo, DMA e CMA

Condutores que são fisicamente coerente áreas (por exemplo, certos motores DMA, multimédia, placas de captura) exacerbam a fragmentação externa. Aqui eu planeio usar o alocador de memória contígua (CMA) ou reservar grandes blocos no início do processo de arranque. Isso evita que muitas alocações pequenas „roam“ o espaço de endereço antes que o driver obtenha seus buffers. Ao mesmo tempo, isolo as páginas fixadas (por exemplo, usando RDMA/DPDK) da memória geral da aplicação para que o seu carácter UNMOVABLE não torne inutilizáveis blocos de páginas inteiros. Também devo verificar se as configurações de IOMMU virtualizam suficientemente áreas maiores e não contíguas - caso contrário, preciso de reservas específicas e limites de tempo claros. Janelas para estas afectações.

Rotina operacional: utilizar de forma inteligente as janelas de monitorização e manutenção

Incorporo instantâneos buddyinfo, contadores de compactação e eventos OOM no meu Monitorização, para ver tendências em vez de eventos individuais. Reduzo as implementações contínuas para que a flutuação da memória se concentre em janelas de tempo e o resto da semana corra melhor. Durante as janelas de manutenção, acciono manualmente a compactação, se necessário, limpo as caches e reinicio os serviços antes que a fragmentação cause problemas produtivos. Correlaciono os registos e as métricas com os picos de tráfego para reconhecer padrões recorrentes e ajustar os buffers em conformidade. Para alterações maiores, testo primeiro em staging para não descobrir alterações surpreendentes. Efeitos secundários em funcionamento em direto.

Livro de execução: Quando as grandes afectações falham hoje

Se houver mensagens de erro agudas do tipo „a atribuição da ordem X falhou“, trabalho em etapas claras:

  1. Quadro da situação: Guardar buddyinfo, verificar vmstat (allocstall/compact), procurar no dmesg por entradas Compaction/OOM. Estimar o maior bloco livre (ordem mais alta com >0).
  2. Alívio a curto prazo: Pausar os serviços não críticos, limitar a carga, limpar as caches de forma direcionada. Acionar a compactação manualmente e desativar temporariamente o THP Defrag se estiver a causar danos.
  3. Apuramento direcionado: Reconstruir buffers grandes e contíguos em serviços definidos (reinício controlado) antes de ocorrer o próximo pico.
  4. Aumentar a reserva: vm.min_free_kbytes e marca d'água cuidadosamente para garantir alocações atómicas para as próximas horas; efeitos apertados monitor.
  5. Solução permanente: Corrigir os padrões de atribuição, introduzir pools, mover a pré-alocação para o início, verificar a localização NUMA e ajustar corretamente as páginas THP/Huge.

Variáveis medidas, SLOs e alarmes

Não me limito a medir os totais de RAM, mas também defino SLOs para a capacidade de afetação: „ordem mais elevada com disponibilidade“, „tempo até uma afetação grande bem sucedida“, „percentagem de paragem da compactação“. A partir daí, obtenho alarmes que atacam cedo, antes de os utilizadores verem os tempos limite. Os índices úteis incluem

  • Número de blocos livres em ordens elevadas (por exemplo, ≥ ordem-9) por minuto.
  • Frequência e duração dos tempos de espera de compactação direta ou de recuperação.
  • Proporção de páginas fixas/não fixas em relação à memória total.
  • Taxa de sucesso de grandes atribuições em testes de carga e após implementações.

Relaciono estas métricas com os tempos de lançamento, picos de tráfego e alterações de configuração. Desta forma, reconheço padrões de acordo com os quais posso proactivamente escala ou reprogramar a janela de atribuição.

Planeamento da capacidade e sensibilização para os custos

Calculo as margens de armazenagem de forma a que ambos Funcionamento normal e as fases de manutenção com alocações maiores são devidamente cobertas. Em vez de fazer uma atualização geral, verifico primeiro as correcções de padrões, porque uma boa afinação traz muitas vezes mais do que RAM adicional. Quando expando a capacidade, planeio reservas para THP/páginas grandes, para que as páginas grandes não colidam com os picos de aplicação. A consolidação em menos hosts, mas mais potentes, pode reduzir a fragmentação, desde que eu defina o NUMA e os perfis de alocação adequadamente. O resultado final é que poupo custos em euros quando reduzo a fragmentação, porque reduzo os picos de CPU e o congestionamento de E/S e utilizo as licenças de forma mais eficiente. utilização.

Brevemente resumido

A fragmentação da memória ocorre quando muitas atribuições de diferentes comprimentos e tamanhos são ligadas entre si. Áreas e os grandes pedidos de informação acabam por não dar em nada. Resolvo o problema em três frentes: Ajuste do Kernel/VM (vm.min_free_kbytes, THP/Huge Pages), melhores padrões de alocação (pools, pré-alocação, tempos de vida separados) e gerenciamento de operações limpas (monitoramento, poda programada, disciplina NUMA). Confio no /proc/buddyinfo, nos contadores de compactação e na medição do maior bloco livre para diagnóstico, porque os totais puros de RAM são enganadores. Presto atenção explícita à virtualização e aos hipervisores para que o convidado e o anfitrião não trabalhem um contra o outro e para que grandes Blocos reservado numa fase inicial. A combinação destes blocos de construção aumenta a previsibilidade, evita falhas devido a OOM e proporciona respostas mais rápidas - especialmente quando o tráfego e os dados estão a aumentar.

Artigos actuais