Afinidade NUMA e storage: otimizando a latência PCIe em servidores modernos
Descubra como o desalinhamento entre CPU e PCIe cria gargalos silenciosos em NVMe. Uma análise técnica sobre topologia NUMA, IRQ affinity e redução de latência em infraestrutura enterprise.
A arquitetura de servidores modernos esconde uma complexidade física que frequentemente sabota o investimento em hardware de ponta. Você adquire os SSDs NVMe Gen5 mais rápidos do mercado, instala-os em um servidor dual-socket de última geração e, ainda assim, observa picos de latência inexplicáveis em cargas de trabalho de banco de dados ou virtualização densa. O culpado raramente é o disco em si, mas sim a topologia invisível que conecta o processador ao armazenamento: a arquitetura NUMA (Non-Uniform Memory Access).
Em projetos de infraestrutura de alta performance, tratar um servidor como um pool homogêneo de recursos é um erro de design fundamental. A distância física entre a CPU que processa a instrução de I/O e o slot PCIe onde o disco reside dita a performance final. Ignorar a afinidade NUMA transforma o barramento de interconexão entre processadores em um gargalo silencioso, destruindo o ROI de arrays All-Flash.
Resumo em 30 segundos
- A Física Importa: Em servidores com múltiplos processadores, cada slot PCIe é fisicamente conectado a apenas uma CPU. Acessar um disco conectado à "outra" CPU incorre em penalidade de latência.
- O Custo do Cruzamento: O tráfego que atravessa o link entre sockets (UPI/Infinity Fabric) sofre com maior latência de cauda e disputa de largura de banda com a coerência de cache.
- Otimização Obrigatória: Para NVMe de alta performance, o agendador padrão do SO é insuficiente. É necessário fixar (pinning) processos e interrupções no mesmo nó NUMA do dispositivo de armazenamento.
A física do barramento: distâncias entre lanes PCIe e núcleos
Para entender a latência, precisamos descer ao nível do silício. Em um servidor dual-socket padrão, não existe um barramento PCIe centralizado. O que temos são dois computadores distintos (nós NUMA) conectados por um link de alta velocidade — Intel UPI (Ultra Path Interconnect) ou AMD Infinity Fabric.
Cada processador possui seu próprio Root Complex PCIe. Isso significa que os slots de expansão no chassi do servidor são fisicamente cabeados para a CPU 0 ou para a CPU 1. Quando um processo rodando na CPU 0 solicita dados de um SSD NVMe conectado ao barramento PCIe da CPU 0, chamamos isso de Acesso Local. O caminho é curto, direto e livre de contencão externa.
Entretanto, se o agendador do sistema operacional alocar esse processo na CPU 1, mas o disco estiver na CPU 0, ocorre o Acesso Remoto. O pedido de I/O precisa sair da CPU 1, atravessar o link de interconexão (que já está ocupado mantendo a coerência de cache da memória RAM), chegar à CPU 0 e só então acessar o controlador do disco.
Figura: A topologia física de um servidor dual-socket ilustrando a diferença de caminho entre o acesso local (verde) e o acesso remoto via interconexão (vermelho).
O impacto invisível na latência de cauda
A diferença de latência média entre acesso local e remoto pode parecer pequena em benchmarks sintéticos de baixa profundidade de fila (Queue Depth), muitas vezes na casa de 20 a 40 nanossegundos para acesso à memória, e alguns microssegundos para I/O. Contudo, em arquitetura de soluções, a média é uma métrica mentirosa.
O verdadeiro problema reside na latência de cauda (p99 ou p99.9). O link de interconexão é um recurso compartilhado finito. Quando o servidor está sob carga pesada — imagine um cluster de vSAN ou Ceph reconstruindo dados enquanto serve tráfego de produção — esse link satura. Nesse cenário, um acesso remoto ao storage não sofre apenas a penalidade da distância, mas também a penalidade do congestionamento. O resultado é o jitter: requisições que deveriam levar 100µs levam 5ms, causando timeouts em aplicações sensíveis.
⚠️ Perigo: Em ambientes de High-Frequency Trading (HFT) ou bancos de dados em memória (como Redis/SAP HANA) com persistência em NVMe, ignorar o alinhamento NUMA pode reduzir o throughput efetivo em até 40% devido à saturação do link QPI/UPI.
A falácia do agendador padrão
Muitos administradores de sistemas confiam cegamente no scheduler do Linux ou do hypervisor (ESXi/Hyper-V) para gerenciar a alocação de recursos. A premissa é que o SO "sabe o que é melhor". Na prática, o objetivo primário do agendador é o balanceamento de carga de CPU, não a otimização de I/O de armazenamento.
O agendador tentará manter todas as CPUs ocupadas. Se a CPU 0 (onde o disco está) estiver 90% ocupada e a CPU 1 estiver ociosa, o SO moverá a thread do banco de dados para a CPU 1. Do ponto de vista de computação pura, isso é eficiente. Do ponto de vista de storage, acabamos de introduzir latência em cada operação de leitura e escrita.
Além disso, temos as interrupções (IRQs). Quando um disco NVMe completa uma operação, ele envia uma interrupção para a CPU processar. Se o serviço irqbalance (comum em distros Linux) não estiver configurado para consciência NUMA, ele pode espalhar essas interrupções por todos os núcleos disponíveis, forçando trocas de contexto desnecessárias e tráfego cross-socket.
Arquitetura consciente de topologia: mapeamento e fixação
Para resolver isso, a abordagem deve ser determinística. Não deixamos a performance ao acaso; nós a projetamos. O primeiro passo é sempre o mapeamento da topologia.
Ferramentas como lstopo (do pacote hwloc) são indispensáveis. Elas geram um mapa visual de qual dispositivo PCI está ligado a qual nó NUMA. No Linux, você também pode verificar isso diretamente no sistema de arquivos virtual sysfs.
# Verificando o nó NUMA de um dispositivo NVMe específico
cat /sys/class/nvme/nvme0/device/numa_node
Se o resultado for 0, o dispositivo está fisicamente ligado ao primeiro socket. Se for 1 (em um sistema dual-socket), está no segundo. Se o resultado for -1, o sistema não conseguiu determinar a afinidade (comum em BIOS mal configuradas ou plataformas virtualizadas sem vNUMA exposto).
Figura: Visualização hierárquica de recursos com lstopo, destacando a vinculação física de controladores de armazenamento a nós NUMA específicos.
Estratégias de mitigação
Uma vez mapeado, aplicamos a afinidade. Existem três camadas principais de intervenção:
Afinidade de Processo (
numactl): Ao iniciar um banco de dados ou uma aplicação intensiva em I/O, usamosnumactlpara restringir a execução aos núcleos do mesmo nó do disco. Exemplo:numactl --cpunodebind=0 --membind=0 mongod ...(Assumindo que os discos do MongoDB estão no nó 0).Afinidade de Interrupção (SMP Affinity): Configurar o
/proc/irq/NUMERO_IRQ/smp_affinitypara garantir que apenas as CPUs do nó local tratem as interrupções daquele controlador NVMe. Scripts modernos de tuning muitas vezes desativam oirqbalanceautomático em favor de scripts estáticos para servidores de banco de dados dedicados.Design de Storage Tiering: Em servidores com muitos discos, é comum ter SSDs espalhados por ambos os sockets. A solução arquitetural aqui é criar pools de armazenamento conscientes do NUMA. Por exemplo, em um cluster de virtualização, você pode fixar VMs críticas no Socket 0 e usar apenas o Datastore formado pelos discos do Socket 0.
Comparativo: quando o NUMA realmente importa?
A obsessão por otimização deve ser temperada pelo pragmatismo. Nem todo cenário exige esse nível de microgerenciamento. O impacto da penalidade NUMA é diretamente proporcional à velocidade do dispositivo de armazenamento subjacente.
Se você está utilizando HDDs mecânicos (spinning rust), a latência rotacional (seek time) é da ordem de milissegundos (ex: 5ms a 10ms). Adicionar 0.05ms de latência de interconexão NUMA é irrelevante; é um erro de arredondamento.
Porém, com SSDs NVMe Gen4 e Gen5, estamos falando de latências de acesso na casa dos 10 a 70 microssegundos. Nesse cenário, a sobrecarga do cross-socket pode representar um aumento de 20% a 50% na latência total percebida pela aplicação.
Tabela de impacto por tecnologia de storage
| Tecnologia de Storage | Latência Típica (Média) | Impacto da Penalidade NUMA | Recomendação de Tuning |
|---|---|---|---|
| HDD (SAS/SATA) | 5ms - 15ms | Insignificante (< 1%) | Desnecessário. O gargalo é mecânico. |
| SSD SATA/SAS | 200µs - 500µs | Baixo (5% - 10%) | Opcional. Válido apenas em cargas extremas. |
| NVMe Gen3/Gen4 | 20µs - 100µs | Alto (20% - 40%) | Recomendado. Crítico para DBs transacionais. |
| NVMe Gen5 / Optane | < 10µs | Crítico (> 50%) | Obrigatório. Sem tuning, o hardware é subutilizado. |
| CXL Memory | < 1µs (próximo a DRAM) | Catastrófico | A arquitetura deve ser desenhada em torno do NUMA. |
💡 Dica Pro: Ao utilizar tecnologias emergentes como CXL (Compute Express Link) para expansão de memória ou storage de classe de memória, a localidade NUMA deixa de ser uma otimização e passa a ser um requisito funcional para viabilidade.
Figura: Comparativo de impacto: A latência adicional do acesso remoto é mascarada em discos lentos, mas torna-se o fator dominante em armazenamento flash de alta performance.
O veredito arquitetural
A complexidade de gerenciar a afinidade NUMA adiciona um custo operacional (OpEx) à administração da infraestrutura. Requer scripts de inicialização personalizados, cuidado no provisionamento de VMs e um entendimento profundo da topologia de hardware.
Portanto, a decisão de implementar essa otimização deve ser baseada em dados, não em dogmas. Para servidores de arquivos gerais, web servers ou ambientes de desenvolvimento, o agendador padrão é suficiente. O custo de complexidade não paga o ganho marginal de performance.
Contudo, para cargas de trabalho de Tier-1 — bancos de dados OLTP de alto volume, clusters de analytics em tempo real e infraestrutura de virtualização de alta densidade — ignorar a topologia NUMA é deixar dinheiro na mesa. Você pagou pelo desempenho do NVMe, mas a arquitetura do seu servidor está entregando latência de rede.
Em um cenário onde o hardware de armazenamento está se tornando mais rápido que o barramento que o conecta, a "geografia" interna do servidor é o novo fronte de otimização. Não trate seus sockets como iguais; eles são vizinhos distantes, e o custo da viagem entre eles é pago na moeda mais valiosa do data center: o tempo.
Referências & Leitura Complementar
Intel Corporation. (2023). Intel Xeon Scalable Processor Reference Manual. Foca na arquitetura Mesh e anéis de interconexão UPI.
Red Hat. (2024). Performance Tuning Guide for RHEL 9. Seções específicas sobre
numade perfis de tuned para throughput-performance.SNIA (Storage Networking Industry Association). Solid State Storage Performance Test Specification (PTS). Metodologias para medir latência real e impacto de preconditioning.
JEDEC. DDR5 & NVDIMM Standards. Para compreensão das latências de memória que competem com o tráfego de storage no barramento.
O que é acesso NUMA local vs remoto em storage?
Acesso local ocorre quando a CPU processando o dado é a mesma que controla fisicamente o slot PCIe onde o disco está instalado. O acesso remoto acontece quando a requisição precisa atravessar o barramento de interconexão (UPI/Infinity Fabric) para chegar a um disco conectado a outra CPU, aumentando a latência e consumindo largura de banda do link entre processadores.Como identificar qual CPU controla um disco NVMe no Linux?
A maneira mais direta é verificar o arquivo de sistema virtual com o comando `cat /sys/class/nvme/nvmeX/device/numa_node` (substituindo X pelo número do disco). Para uma visão gráfica completa da topologia, incluindo caches e slots PCIe, a ferramenta `lstopo` do pacote `hwloc` é o padrão da indústria.O tuning de afinidade NUMA vale a pena para SSDs SATA?
Geralmente não. A latência intrínseca do protocolo SATA (AHCI) e a própria performance dos discos SSD SATA ou HDDs são altas o suficiente (na casa das centenas de microssegundos ou milissegundos) para mascarar a penalidade do tráfego NUMA. O ajuste fino de afinidade é crítico principalmente para dispositivos NVMe de baixa latência e alta contagem de IOPS.
Otávio Henriques
Arquiteto de Soluções Enterprise
"Com duas décadas desenhando infraestruturas críticas, olho além do hype. Foco em TCO, resiliência e trade-offs, pois na arquitetura corporativa a resposta correta quase sempre é 'depende'."