Armazenamento para Clusters de IA: NFS, BeeGFS, Lustre e a Questão do Object Store

O armazenamento partilhado é a parte de um cluster de treino distribuído em que ninguém pensa até se tornar a razão pela qual as GPUs ficam a 40% de utilização. A essa altura, substituí-lo é doloroso — todos os scripts de treino têm pressupostos entranhados, todos os checkpoints estão num formato que pode ou não migrar sem problemas, e o cluster está em produção. O momento certo para decidir o armazenamento é antes de o segundo nó de treino entrar no rack.

Esta é a metade dedicada ao armazenamento da série K. É uma visão de comprador e arquiteto, não um guia de administração de sistemas — o objetivo é decidir entre NFS, BeeGFS, Lustre e object stores com os olhos abertos, e ser honesto sobre qual deles a maioria dos clientes Kentino precisa de facto.

Porque é que o armazenamento partilhado é o estrangulamento silencioso

Uma máquina de treino de nó único lê o conjunto de dados do NVMe local e escreve os checkpoints no mesmo sítio. Não há nada a discutir. No momento em que um segundo nó se junta, duas coisas mudam:

  1. Todos os nós leem o mesmo conjunto de dados. Os bytes são idênticos em cada worker e têm de estar visíveis a partir de todos os nós.
  2. Todos os nós escrevem checkpoints, e a união tem de sobreviver. Com FSDP ou com sharding do DeepSpeed, cada rank escreve a sua fatia; com DDP, os ranks escrevem de forma redundante. De uma forma ou de outra, o sistema de ficheiros vê uma rajada de escritas grandes a cada poucos minutos ou poucas horas.

Estes padrões de acesso são opostos. O acesso ao conjunto de dados é sustentado, sequencial, dominado por leituras e tolerante à latência. O acesso aos checkpoints é em rajada, de blocos grandes, dominado por escritas, e o treino fica bloqueado à espera dele. Um sistema de armazenamento que é bom num é muitas vezes medíocre no outro.

Além disso, os conjuntos de dados de ML modernos fazem uma terceira coisa: tempestades de metadados. Um conjunto de dados com 50 milhões de JPEG de 4–12 KB é, do ponto de vista do sistema de ficheiros, 50 milhões de ciclos de open/stat/read/close. É o servidor de metadados, e não o caminho dos dados, que cai primeiro. É por isto que "temos largura de banda de sobra" não é uma resposta suficiente.

Carga de trabalho Padrão Do que precisa
Shuffle / leitura do conjunto de dados Leituras sequenciais sustentadas, à escala de TB Largura de banda de leitura agregada
Conjunto de dados de ficheiros pequenos Metadados aleatórios + leituras de ficheiros minúsculos IOPS de metadados, baixa latência por operação
Escrita de checkpoint Escritas grandes em rajada, todos os nós ao mesmo tempo Largura de banda de escrita em rajada, sem head-of-line
Carregamento do modelo de inferência Uma única leitura grande no arranque Tolera qualquer coisa razoável

NFS — a opção por omissão, e dura mais do que se pensa

O NFS (NFSv3 ou v4) é o caminho de menor resistência. Todas as distribuições Linux o incluem, todos os escalonadores o entendem, e um "nó de armazenamento" não passa de uma máquina Linux com muito disco, uma linha em /etc/exports e uma NIC rápida.

O que um servidor NFS bem construído oferece:

  • Um espaço de nomes único, montado de forma idêntica em todos os nós de computação.
  • Débito de leitura sequencial decente, sobretudo com nconnect em kernels modernos (multiplexando uma montagem por várias ligações TCP — o teto do fluxo único desapareceu há anos).
  • Operacionalmente aborrecido. As falhas são bem compreendidas e os procedimentos de recuperação estão em todos os manuais de administração de sistemas alguma vez escritos.

O que se perde:

  • Um servidor, um estrangulamento. O débito agregado do cluster está limitado ao que essa única máquina consegue servir.
  • Serialização de locks e metadados. As cargas de trabalho de ficheiros pequenos atingem os limites de metadados antes dos limites de largura de banda.
  • Não escala de forma elegante. Quando a máquina enche, constrói-se uma segunda com outro ponto de montagem, e os seus scripts passam a saber da existência dela.

A má fama que o NFS tem nos círculos de HPC prende-se sobretudo com o antigo teto de ligação única e com o sofrimento de metadados em ficheiros minúsculos. Para conjuntos de dados de treino entre 100 GB e 1–2 TB em nós de 4–8 GPUs, um servidor NFS bem construído é genuinamente adequado. Já vimos clientes a treinar afinações do Qwen2.5-VL com conjuntos de dados em NFS sem uma queixa.

O NFS começa a doer quando:

  • Os conjuntos de dados ultrapassam os ~2 TB e os shuffles provocam thrashing de cache no servidor.
  • Mais de ~8–12 nós de computação atacam a mesma montagem sob carga.
  • Dezenas de milhões de ficheiros pequenos dominam a carga de trabalho.
  • Os checkpoints por rank ultrapassam 50–100 GB escritos em simultâneo.

Abaixo destes quatro limiares, o NFS é quase de certeza a resposta certa e um sistema de ficheiros paralelo é sobre-engenharia.

BeeGFS — o meio-termo prático

O BeeGFS é o sistema de ficheiros paralelo que as pessoas realmente implementam quando o NFS deixa de chegar. Distribui os dados por vários alvos de armazenamento (discos em vários servidores) e alvos de metadados (servidores NVMe separados). Os clientes veem um espaço de nomes único; as leituras e escritas são distribuídas em paralelo pelos alvos de armazenamento.

Porque aparece em clusters de média escala:

  • A instalação demora dias, não semanas. Um engenheiro de Linux competente põe de pé uma instalação de dois nós de armazenamento e um MDS numa tarde. O Lustre não joga nesse campeonato.
  • A largura de banda agregada escala linearmente com os alvos de armazenamento. Três nós a 100 GbE entregam perto de 3× o débito de leitura de um.
  • RDMA nativo em InfiniBand ou RoCE — evita a sobrecarga do TCP/IP.
  • Código aberto, sem a armadilha do licenciamento por TB. Suporte comercial da ThinkParQ opcional.

Aquilo em que, honestamente, é menos bom:

  • Metadados em cargas de trabalho com muitíssimos ficheiros pequenos. Um único MDS torna-se o estrangulamento quando dominam ficheiros abaixo de 4 KB. É possível acrescentar alvos de metadados, mas a arquitetura não é tão agressiva como o DNE do Lustre.
  • Sem tiering incorporado. A gestão do que é quente e frio fica do seu lado.
  • A alta disponibilidade é acrescentada, não nativa. O espelhamento funciona, mas não é tão transparente como o failover do Lustre.

Zona ideal: 4–32 nós de treino, 10–100 TB de conjunto de dados, ficheiros entre 1 MB e 1 GB. É onde cai a maioria das configurações Kentino multinó.

Uma implementação BeeGFS de base para um cluster Kentino de 4 nós:

Componente Especificação
Nó de armazenamento 1 2U, EPYC de 24 núcleos, 256 GB de RAM, 12× NVMe de 7.68 TB, 2× 100 GbE
Nó de armazenamento 2 Idêntico
Nó de metadados 1U, EPYC de 16 núcleos, 192 GB de RAM, 2× NVMe de 3.84 TB (RAID-1), 2× 100 GbE
Rede 100 GbE leaf-spine ou switch único (com suporte RoCE)
Clientes 4× nós de treino Kentino AI, cada um com 1× 100 GbE

A leitura agregada sustentada para os quatro nós de treino situa-se tipicamente entre 30 e 60 GB/s, o suficiente para alimentar 32 GPUs na maior parte do treino de visão e de LLM. Isto deixa de escalar quando o servidor de metadados satura — acrescente um segundo alvo de metadados ou comece a pensar em Lustre.

Lustre — padrão de ouro, complexidade real

O Lustre corre a camada de armazenamento de praticamente todos os supercomputadores do top-500 que precisam de POSIX, escalando até centenas de petabytes e débitos agregados de vários TB/s. A arquitetura tem três papéis: MGS/MDS (gestão + metadados), OSS (servidores de armazenamento de objetos que detêm os OST) e clientes. Os clientes falam com o MDS para operações de espaço de nomes e depois falam diretamente com o OSS que detém os dados — o caminho dos dados contorna por completo o servidor de metadados. É esta separação que permite ao Lustre escalar, e o DNE (Distributed Namespace) deixa os metadados escalarem também na horizontal.

O custo é operacional: curva de aprendizagem mais íngreme do que o BeeGFS, requisitos estritos de kernel e controladores, dezenas de parâmetros de afinação (o desempenho de origem não costuma ser o que o hardware consegue entregar) e procedimentos de recuperação que exigem um engenheiro de armazenamento competente.

O limiar a partir do qual o Lustre faz sentido fica grosso modo em 16–32 ou mais nós de treino, ou em conjuntos de dados à escala do PB. Abaixo disso, o BeeGFS satura a rede muito antes de as vantagens arquitetónicas do Lustre fazerem diferença. A gama Kentino, na sua maioria, não chega a esse limiar — construímos um cluster Lustre se nos pedirem, mas dizemos primeiro que o BeeGFS com um MDS robusto leva o cliente a 80% do caminho com 20% do sofrimento operacional.

Armazenamento de objetos — MinIO e Ceph para data lakes de ML

Os sistemas de ficheiros paralelos acima são a escolha certa quando a framework espera ficheiros. Uma fatia crescente dos pipelines de ML modernos não espera — os conjuntos de dados vivem como objetos S3, o data loader puxa-os por HTTP, e o sistema de ficheiros local é apenas rascunho transitório.

O MinIO é um armazenamento de objetos compatível com S3 e de propósito único. O modo distribuído corre em 4–32 ou mais nós com erasure coding. É código aberto, operacionalmente mais simples do que qualquer sistema de ficheiros paralelo, e os data loaders modernos (PyTorch com fsspec/s3fs, WebDataset, NVIDIA DALI) leem-no diretamente.

O Ceph é mais abrangente — bloco (RBD), ficheiro (CephFS) e objeto (RGW) sobre a mesma camada RADOS. O Ceph ganha quando se quer um só sistema de armazenamento para várias cargas de trabalho (máquinas virtuais, partilhas de ficheiros, objetos de ML). Perde na simplicidade operacional — o Ceph é um sistema com que se assume um compromisso, com a sua própria monitorização, afinação e disciplina de piquete.

O que o armazenamento de objetos traz ao ML: capacidade barata (nós densos de HDD com erasure coding dão valores de €/TB que a flash não consegue tocar), escalabilidade horizontal operacionalmente simples, sharding por conceção (sem estrangulamento de metadados) e boa compatibilidade com data loaders baseados em shards. O que se perde: latência por operação na casa das dezenas de ms (não microssegundos), ausência de POSIX direto (reescrever o loader ou aceitar a penalização do FUSE) e ausência de escritas no local (os objetos são imutáveis — ótimo para checkpoints, mau para tudo o que mude).

A arquitetura que funciona na prática: armazenamento de objetos como data lake duradouro, grande e barato; um sistema de ficheiros paralelo ou NFS como conjunto de trabalho rápido, preparado para a execução em curso. O conjunto de dados vive no MinIO. Um job coloca os shards relevantes no BeeGFS ou em rascunho NVMe local no arranque. Os checkpoints finais voltam para o MinIO para arquivamento.

WekaIO e VAST — o patamar empresarial (em breve resumo)

A WekaIO e a VAST Data são a resposta criada de propósito e com preço empresarial: metadados extremos para ficheiros pequenos, largura de banda agregada muito elevada, S3 e POSIX nativos, tiering integrado e caminhos GPU-direct. Fazem todo o sentido para clusters de 100 ou mais GPUs, em que o armazenamento tem de acompanhar o investimento em GPUs. Não são a escolha certa para um servidor de 4 ou 8 GPUs, nem para um cluster de quatro máquinas dessas — o custo do armazenamento dominaria a configuração. Ficam aqui mencionadas por honestidade sobre a gama alta, não como recomendação para o comprador a quem esta série se dirige.

Padrões de acesso ao conjunto de dados e porque importam

Dois padrões dominam o treino de ML. Padrão A — shards grandes: conjuntos de dados pré-empacotados em tarballs WebDataset, parquet ou LMDB, de 100 MB a 10 GB por shard, lidos sequencialmente e baralhados internamente. Todos os sistemas de armazenamento são bons nisto. Padrão B — muitos ficheiros pequenos: milhões de JPEG/PNG/JSON, um por amostra, a martelar o caminho dos metadados. Isto castiga o NFS, prejudica o BeeGFS em escala e é a razão de existirem a Weka e a VAST.

A decisão com maior alavancagem no armazenamento para treino é passar o Padrão B para o Padrão A. Se o conjunto de dados for de ficheiros pequenos, reempacote-o em shards antes do treino. O custo é uma passagem de pré-processamento; o benefício é que qualquer sistema de armazenamento passa a ser adequado. Já vimos pipelines acelerarem 3–5× sem qualquer alteração de hardware de armazenamento, apenas com o reempacotamento.

Se não for possível reempacotar — conjunto de dados constantemente alterado, framework que exige mesmo ficheiros por amostra — dimensione o armazenamento em função dos IOPS de metadados, não da largura de banda. Isso empurra-o para BeeGFS com vários alvos MDS, para Weka/VAST ou para Lustre com DNE.

Estratégia de checkpoints — escrever depressa, escrever mais tarde, escrever menos

As escritas de checkpoint são o pior padrão possível: todos os ranks escrevem em simultâneo, as escritas são grandes e o treino fica bloqueado até os dados estarem seguros. Um checkpoint síncrono ingénuo num modelo de 100 B de parâmetros pode travar o treino durante dezenas de minutos.

A melhor prática atual é uma abordagem em três fases, nativa no torch.distributed.checkpoint (DCP) do PyTorch, no NVIDIA NeMo e na maioria das frameworks modernas:

  1. Cada rank escreve a sua fatia em rascunho NVMe local. A largura de banda total de escrita do cluster é a soma das taxas NVMe de cada nó (5–50 GB/s cada). O treino desbloqueia em segundos.
  2. Um processo assíncrono em segundo plano copia para o armazenamento partilhado. A esta altura o treino já recomeçou.
  3. Os checkpoints mais antigos são eliminados ou movidos para armazenamento de objetos segundo um calendário. Guarde os últimos 2–3 em armazenamento rápido e o resto no MinIO/Ceph.

A implicação: o armazenamento partilhado não precisa de absorver todos os checkpoints à velocidade máxima. Precisa de ingerir a cópia assíncrona sem ficar atrás da cadência. Para um modelo de 70 B com checkpoint a cada 30 minutos, uma escrita sustentada de poucos GB/s chega — bem dentro do alcance de um BeeGFS competente ou de um bom servidor NFS.

O erro a evitar: checkpoints síncronos e sem sharding escritos diretamente para NFS. Isso era normal em 2022. Já não é. Se o seu pipeline faz isto, corrigir o código dos checkpoints tem mais alavancagem do que melhorar o armazenamento.

A questão do uplink do cluster

O tráfego de armazenamento partilha a fabric com o treino, ou tem uma só para si?

Fabric partilhada
Uma só rede de 100/200 GbE ou IB transporta o all-reduce e o armazenamento. Mais barato, mais simples. Risco: a rajada de checkpoints pode entrar em contenção com o NCCL e travar o treino.
Fabric separada
Duas NIC por nó — uma para a fabric de computação (IB), outra para a fabric de armazenamento (Ethernet). Domínios de congestão independentes. Cerca do dobro do equipamento de rede.

A fabric partilhada serve bem clusters de 4–8 nós com checkpoints assíncronos; a fabric separada justifica-se acima de 8 nós ou com E/S síncrona intensa.

Para clusters Kentino de 4–8 nós, a fabric partilhada chega quando se usam checkpoints assíncronos e a carga de armazenamento é sobretudo de leitura — a leitura sustentada coexiste com as coletivas NCCL sem grande prejuízo. A fabric separada justifica-se em treino de LLM de grande dimensão com FSDP em graus elevados de TP/PP, com tráfego de armazenamento síncrono intenso, ou quando o orçamento permite a folga. O padrão prático: 100 GbE partilhada até 8 nós, com uma VLAN de armazenamento como isolamento suave.

Recomendações honestas por escala

Escala Conjunto de dados Camada de armazenamento Notas
1 nó Qualquer NVMe local Dispense por completo o armazenamento partilhado.
2–3 nós de treino < 1 TB NFS num nó de armazenamento robusto nconnect, RAM generosa para a cache de páginas.
4–8 nós de treino 1–10 TB NFS, ou a primeira implementação de BeeGFS BeeGFS se o conjunto de dados for dominado por ficheiros pequenos.
4–16 nós de treino 10–100 TB BeeGFS, 2–3 alvos de armazenamento, MDS dedicado Zona ideal. Acrescente MinIO para arquivamento frio.
16–32+ nós de treino 100 TB–1 PB BeeGFS no limite, ou Lustre Ponto de decisão para o Lustre.
32+ nós, escala PB, 24/7 PB+ Lustre, ou Weka/VAST se o orçamento permitir Para lá da configuração Kentino típica.
Data lake grande, treino episódico PB+ frio MinIO/Ceph, com staging para a camada rápida por job "Muitos dados, treino ocasional."

A maioria dos clientes Kentino cai na segunda e na terceira linhas. Construímos o resto se nos pedirem, mas dizemos ao cliente quando está sobredimensionado.

O que corre mal

Modos de falha que já vimos, por ordem da frequência com que mordem:

  • Esgotamento de metadados com carga de ficheiros pequenos. Sintoma: GPUs a 30–50%, rede parada, CPU do armazenamento parada, cada open() lento. Solução: reempacotar em shards, ou aumentar os alvos MDS.
  • Checkpoints síncronos a travar o treino. Solução: checkpoints assíncronos com sharding (PyTorch DCP ou NeMo).
  • Um disco lento a afundar o cluster. Um SSD em fim de vida não falha de forma limpa — limita-se a ficar lento. Solução: monitorizar a latência por dispositivo e alarmar acima de > 2× a referência.
  • Thrashing da cache de páginas no nó de armazenamento. O conjunto de dados não cabe na RAM e cada época despeja a anterior. Solução: mais RAM.
  • nconnect não ativado nos clientes NFS. O NFS de fluxo único por omissão fica muito abaixo da velocidade nominal da NIC. nconnect=8 ou =16 dá 4–8× de débito no mesmo hardware.
  • MinIO em escala sem afinação do erasure coding. Os valores por omissão privilegiam a durabilidade sobre a latência; a latência em objetos pequenos sofre. Não aceite os valores por omissão às cegas.

Nada disto é exótico. Tudo isto é previsível depois de se ver uma vez.

O que fazer a seguir

Se está a especificar armazenamento para um cluster de treino novo ou em crescimento, responda a estas perguntas antes de assinar a compra do hardware:

  1. Forma do conjunto de dados — shards grandes ou muitos ficheiros pequenos? É o maior determinante de qual sistema de armazenamento encaixa.
  2. Conjunto de trabalho ativo, não o tamanho do data lake. O orçamento de armazenamento vai para o conjunto de trabalho; o lake vive em armazenamento de objetos mais barato e mais lento.
  3. Cadência dos checkpoints, tamanho e tolerância a paragens. Dimensiona a capacidade de escrita em rajada e diz-lhe se os checkpoints assíncronos com sharding são obrigatórios (acima de ~13 B de parâmetros, normalmente são).
  4. Nós de treino hoje e projeção realista a 12 meses. Se vai ficar em 4 nós durante um ano, construa para 4 nós. Não compre Lustre por antecipação.
  5. Armazenamento na fabric de treino, ou separado? Decida antes de cablar, não depois.
  6. Plano de arquivamento frio. Modelos, versões do conjunto de dados, artefactos de execuções concluídas — isso pertence a algum sítio barato. MinIO ou Ceph é normalmente a resposta.

O armazenamento recompensa o planeamento antecipado mais do que quase qualquer outra parte de um cluster de IA, porque o custo de errar paga-se em cada execução de treino durante toda a vida do sistema. O objetivo honesto não é "o armazenamento mais rápido que conseguimos comprar" — é "o armazenamento mais simples que não estrangula as GPUs que já temos", e para a maioria das configurações à escala da Kentino isso é bem menos exótico do que o marketing dos fabricantes dá a entender.

Artigos relacionados: K01 (nó único vs multinó), K02 (mecânica do treino distribuído), K03 (clusters de inferência), N08 (RDMA + uplink do cluster), W06 (camadas de armazenamento dentro de um único servidor).


Isto faz parte da Kentino Wiki, uma série de referência sobre computação de IA, robótica e os sistemas que as ligam. Comentários e correções são bem-vindos em info@kentino.com.