A Realidade Técnica da Expansão RAIDZ e do Reflow no OpenZFS

      Roberto Holanda 11 min de leitura
      A Realidade Técnica da Expansão RAIDZ e do Reflow no OpenZFS

      Desmistificando a engenharia por trás do 'zpool attach' em vdevs RAIDZ. Entenda o mapeamento de expansão, a geometria híbrida e por que o 'reflow' automático não existe.

      Compartilhar:

      A Realidade Técnica da Expansão RAIDZ e do Reflow no OpenZFS

      Por quase duas décadas, a regra de ouro do ZFS foi imutável: uma vez criado um VDEV RAIDZ, sua largura (width) era eterna. Se você criasse um array com 4 discos em RAIDZ1, ele morreria com 4 discos. A única forma de crescer era adicionar um novo VDEV inteiro ou substituir todos os discos por maiores, um a um, resilver após resilver. Essa rigidez não era teimosia dos desenvolvedores; era uma consequência direta de como o alocador de blocos do ZFS desenha dados no disco.

      Com a chegada do OpenZFS 2.2 e versões subsequentes, a funcionalidade de "RAIDZ Expansion" finalmente aterrissou nos repositórios estáveis. Sysadmins e entusiastas de storage celebraram. No entanto, existe uma dissonância cognitiva perigosa entre o que o usuário acha que acontece e o que a matemática do sistema de arquivos realmente faz.

      A expansão não é mágica. Ela é uma operação de metadados que introduz um estado híbrido no seu pool. Entender a geometria subjacente não é apenas curiosidade acadêmica; é um requisito para não desperdiçar terabytes de capacidade bruta achando que estão disponíveis para dados.

      Resumo em 30 segundos

      • Capacidade vs. Eficiência: A expansão disponibiliza espaço bruto imediatamente, mas os dados antigos continuam ocupando a proporção de paridade original (menos eficiente).
      • Geometria Híbrida: Um VDEV expandido contém regiões com larguras de stripe diferentes. O ZFS mapeia logicamente os dados antigos para a nova topologia sem movê-los fisicamente.
      • O Imperativo do Reflow: Para ganhar a eficiência de espaço da nova geometria (ex: ir de 3+1 para 4+1), você é obrigado a reescrever (reflow) todos os dados antigos.

      A rigidez matemática da geometria RAIDZ tradicional

      Para compreender a expansão, precisamos dissecar por que ela era impossível anteriormente. Diferente do RAID5 tradicional de hardware, que opera em stripes de tamanho fixo e cegos ao conteúdo, o RAIDZ é um esquema de paridade de largura variável.

      No ZFS, cada bloco lógico de dados é transformado em um "setor físico" no disco. Se eu gravo um arquivo de 128KB, o ZFS o divide em colunas baseadas no número de discos de dados. Em um RAIDZ1 de 4 discos (3 dados + 1 paridade), o sistema aloca faixas (stripes) que preenchem essa geometria perfeitamente.

      O problema reside na alocação de espaço livre. O ZFS usa uma estrutura chamada Metaslab. Pense no Metaslab como um mapa de bits gigante que diz "este espaço está livre". Quando você tem um VDEV de 4 discos, o alocador sabe matematicamente onde cortar os blocos. Se você subitamente adiciona um 5º disco, a matemática de endereçamento de todos os dados anteriores quebra. O ponteiro que dizia "Vá para o offset X no VDEV Y" agora apontaria para o lugar errado, pois a largura da "estrada" mudou.

      A inovação da expansão RAIDZ não foi mudar a física, mas sim abstrair a lógica.

      Fig. 1: A geometria imutável dos dados antigos vs. a nova eficiência dos dados novos. Fig. 1: A geometria imutável dos dados antigos vs. a nova eficiência dos dados novos.

      Mecânica de expansão: O conceito de vdev híbrido

      Quando você executa o comando zpool attach para adicionar um disco a um grupo RAIDZ existente, o ZFS não move um único byte dos dados existentes. Em vez disso, ele cria uma descontinuidade no tempo e no espaço do seu armazenamento.

      O VDEV passa a operar em um modo híbrido. O sistema de arquivos mantém um registro interno de que, até o "Bloco X", a geometria é de 4 discos. Do "Bloco X" em diante (o novo espaço livre criado pela expansão), a geometria é de 5 discos.

      Isso é realizado através de uma camada de indireção. O ZFS virtualiza o endereçamento dos blocos antigos. Quando uma leitura é solicitada para um dado antigo, o sistema consulta a tabela de mapeamento e entende: "Ah, embora este VDEV agora tenha 5 colunas, este bloco específico foi gravado na era das 4 colunas". Ele lê apenas os discos originais para aquele bloco.

      💡 Dica Pro: Você pode visualizar essa estrutura híbrida inspecionando o zdb (ZFS Debugger). Ele mostrará regiões de metaslabs com diferentes configurações de asize (allocated size) dentro do mesmo VDEV top-level.

      Essa abordagem é brilhante porque torna a expansão quase instantânea. Não há um processo de "restripe" massivo que deixa o array lento por dias (como ocorre em controladores RAID tradicionais ou no mdadm do Linux). O disco é adicionado, os novos metaslabs são inicializados no novo disco e o espaço está "disponível". Mas aqui reside a armadilha.

      Fig. 2: O VDEV híbrido. O ZFS mantém um mapa de quais blocos pertencem a qual 'era' da geometria do array. Fig. 2: O VDEV híbrido. O ZFS mantém um mapa de quais blocos pertencem a qual 'era' da geometria do array.

      O abismo entre capacidade bruta e eficiência de paridade

      Aqui é onde a maioria dos administradores de storage se confunde. Adicionar um disco aumenta a capacidade bruta, mas não altera a eficiência de paridade dos dados existentes.

      Vamos usar um exemplo prático e aritmético:

      1. Cenário Inicial: RAIDZ1 com 4 discos (3 Dados + 1 Paridade).

        • Eficiência de armazenamento: 75% (3/4).
        • Overhead de paridade: 25%.
      2. Ação: Você adiciona 1 disco. Agora é um RAIDZ1 de 5 discos.

        • Nova geometria alvo: 4 Dados + 1 Paridade.
        • Nova eficiência alvo: 80% (4/5).
        • Novo overhead alvo: 20%.

      No momento em que a expansão termina, 100% dos seus dados antigos continuam gravados com 25% de overhead. Apenas os novos dados gravados a partir desse segundo desfrutarão da eficiência de 80%.

      Se o seu pool estava 90% cheio antes da expansão, a adição do novo disco oferece muito pouco ganho real imediato para os dados existentes. O espaço livre aumentou, sim, mas o "peso" dos dados antigos permanece inalterado. Você está carregando "espaço fantasma" na forma de paridade excessiva que não é mais necessária na nova geometria, mas que não pode ser removida sem reescrita.

      O paradoxo do espaço livre e a ilusão do zfs list

      O comando zfs list tenta ser útil, mas em cenários de expansão RAIDZ, ele pode ser enganoso. O ZFS calcula o espaço disponível (AVAIL) baseando-se em uma estimativa da taxa de compressão e da eficiência de paridade atual de gravação.

      Após expandir um VDEV, o zfs list pode reportar um aumento significativo no espaço disponível. No entanto, se você não reescrever os dados antigos, seu pool se encherá mais rápido do que a matemática simples sugere, porque os blocos antigos continuam consumindo mais setores físicos do que o "novo normal" do array ditaria.

      ⚠️ Perigo: Não confie cegamente na coluna AVAIL logo após uma expansão para planejamento de capacidade a longo prazo. O valor real depende inteiramente da proporção de dados "velhos" (ineficientes) versus dados "novos" (eficientes) que você terá no futuro.

      A necessidade de reescrita para recuperação de overhead

      Para alinhar a realidade física dos dados antigos com a nova geometria do VDEV, é necessário realizar o que chamamos de Reflow.

      Diferente do Btrfs, que possui um comando btrfs balance explícito para reescrever extents e redistribuir dados entre todos os dispositivos, o ZFS (até o momento desta escrita) não possui um botão mágico "rebalancear vdev". O ZFS opera sob o princípio estrito de Copy-on-Write (CoW) e alocação na escrita. Um bloco só muda de lugar ou geometria se for modificado.

      Para recuperar a eficiência de paridade (aquele salto de 75% para 80% no nosso exemplo), você deve forçar o sistema a ler o dado antigo e gravá-lo novamente como um novo dado. Ao fazer isso, o alocador de blocos pegará esse dado e o distribuirá pela nova largura de stripe de 5 discos.

      Fig. 3: A curva de eficiência de paridade. A expansão traz capacidade bruta, mas a eficiência só sobe com a reescrita dos dados. Fig. 3: A curva de eficiência de paridade. A expansão traz capacidade bruta, mas a eficiência só sobe com a reescrita dos dados.

      Métodos de Reflow

      Existem três abordagens principais para realizar esse reflow, cada uma com seus riscos e custos de I/O:

      1. ZFS Send/Recv (O Método Canônico): Enviar o dataset para um backup e recebê-lo de volta, ou enviar para um dataset temporário no mesmo pool e depois renomear.

        • Prós: Garante desfragmentação total e reescrita sequencial perfeita.
        • Contras: Requer tempo de inatividade ou configuração complexa de datasets.
      2. Reescrita In-Place (CP e MV): Copiar arquivos para um diretório temporário e movê-los de volta.

        • Prós: Simples para diretórios pequenos.
        • Contras: Terrível para snapshots. Se você tem snapshots, essa operação duplicará o uso de espaço (os dados velhos ficam presos nos snapshots, os novos ocupam espaço ativo). Só faça isso se não se importar em perder o histórico de snapshots.
      3. Scrub de Reescrita (Futuro/Conceitual): Há discussões na comunidade OpenZFS sobre implementar uma flag no zpool scrub para reescrever dados, mas isso envolve complexidades massivas de transacionalidade e segurança. Por enquanto, não é uma realidade em produção.

      Impacto na performance e fragmentação

      A expansão RAIDZ também introduz um vetor de fragmentação único. Normalmente, pensamos em fragmentação como arquivos espalhados pelo disco. Aqui, temos fragmentação de geometria.

      Um arquivo lido sequencialmente pode ter seus primeiros 500MB na geometria antiga (lendo 3 discos + paridade) e os próximos 500MB na geometria nova (lendo 4 discos + paridade). Isso exige que a controladora e o código do ZFS mudem o padrão de acesso aos discos em tempo real.

      Embora o impacto de CPU seja negligenciável em processadores modernos (Xeon, EPYC ou mesmo Ryzen recentes), o impacto nas IOPS pode ser notável em discos rotacionais (HDD). O braço do disco novo (o expandido) trabalhará menos nas leituras de dados velhos (pois ele não contém partes desses dados), criando um desbalanceamento de carga mecânica até que o reflow seja concluído.

      Perguntas Frequentes

      P: Posso remover um disco de um RAIDZ após expandi-lo? R: Não. A expansão RAIDZ é uma viagem só de ida. Uma vez que o VDEV foi expandido e novos dados foram escritos na nova geometria, não há como "encolher" o stripe sem destruir o pool e restaurar do backup. A funcionalidade de zpool remove existe, mas aplica-se apenas a VDEVs inteiros (em configurações de stripe/mirror) ou discos de cache/log, não a discos individuais dentro de um RAIDZ.

      P: A expansão funciona com RAIDZ2 e RAIDZ3? R: Sim. A lógica é idêntica. Um RAIDZ2 de 6 discos (4+2) pode virar um de 7 discos (5+2). A ineficiência inicial será proporcional à mudança da razão dados/paridade.

      P: O resilver é necessário após a expansão? R: Não no sentido tradicional. Não há dados para "reconstruir" no novo disco imediatamente, pois ele está vazio. O disco é integrado instantaneamente. No entanto, recomenda-se um reflow (reescrita) gradual para balancear o uso.

      P: É seguro fazer isso em produção crítica? R: A funcionalidade passou por anos de testes e validação (pull request original de Matt Ahrens). A integridade dos dados (checksums) é mantida. O risco não é de corrupção, mas operacional: entender que a performance e a capacidade não se comportarão linearmente até que os dados sejam reescritos.

      O veredito do arquiteto

      A expansão RAIDZ é uma ferramenta poderosa, mas não é uma licença para o planejamento preguiçoso. Ela resolve o problema agudo de "preciso de mais espaço agora e tenho um slot livre", mas introduz uma dívida técnica na forma de dados com geometria mista.

      Se você gerencia petabytes ou apenas seu precioso home lab, trate a expansão como um procedimento cirúrgico, não como manutenção de rotina. O estado ideal de um pool ZFS é a homogeneidade. Um VDEV híbrido é, por definição, um estado de transição. Planeje a expansão, execute-a e, em seguida, planeje o ciclo de reescrita dos seus dados. A integridade do ZFS garante que você não perderá bits, mas apenas a sua diligência garantirá que você não perderá performance e eficiência.

      No mundo do armazenamento, a física é implacável: você pode adiar o pagamento da paridade, mas nunca pode caloteá-la.

      Referências & Leitura Complementar

      1. OpenZFS Pull Request #15022: "RAIDZ Expansion" - A implementação técnica oficial e discussão de código.

      2. Ahrens, M. (2023). RAIDZ Expansion: How it works and how to use it. Apresentação no OpenZFS Developer Summit.

      3. Bonwick, J. & Moore, B. ZFS On-Disk Specification. Documentação fundamental sobre a estrutura de blocos e ponteiros de bloco (blkptr_t).

      4. JEDEC SSD Specifications: Para entender as implicações de write amplification ao realizar reflow em SSDs de consumo vs. Enterprise.

      #OpenZFS #RAIDZ Expansion #Storage Engineering #ZFS Reflow #zpool attach #Parity Overhead #Data Integrity
      Roberto Holanda
      Assinatura Técnica

      Roberto Holanda

      Guru de Sistemas de Arquivos (ZFS/Btrfs)

      "Dedico minha carreira à integridade dos dados. Para mim, o bit rot é o inimigo e o Copy-on-Write é a salvação. Exploro a fundo ZFS, Btrfs e a beleza dos checksums."