Domando a amplificação de escrita: NVMe FDP e io_uring passthrough

      André Linhares 9 min de leitura
      Domando a amplificação de escrita: NVMe FDP e io_uring passthrough

      Descubra como reduzir o WAF e eliminar a latência de cauda em SSDs Enterprise combinando NVMe Flexible Data Placement (FDP) e io_uring passthrough no Linux.

      Compartilhar:

      Se você monitora latência de disco em nível de microssegundos, sabe que a média é uma mentira confortável. O verdadeiro inferno vive no percentil 99 (p99) e além. É lá que uma operação de escrita aparentemente inocente trava seu banco de dados por centenas de milissegundos porque o SSD decidiu, naquele exato momento, que precisava reorganizar seus blocos internos.

      Estamos falando de Amplificação de Escrita (WAF - Write Amplification Factor) e overhead de kernel. Por anos, aceitamos pagar o "imposto do flash" comprando mais disco do que precisamos (over-provisioning) e queimando ciclos de CPU em trocas de contexto inúteis. Isso acabou. Com a chegada do NVMe Flexible Data Placement (FDP) e do suporte a passthrough no io_uring, temos finalmente as ferramentas para alinhar a física do NAND com a lógica da aplicação.

      Resumo em 30 segundos

      • O Problema: O Garbage Collection (GC) dos SSDs mistura dados "quentes" e "frios", gerando reescritas internas (WAF > 1) que destroem a performance e a vida útil do disco.
      • A Solução de Hardware: O NVMe FDP permite que o host indique onde os dados devem ser gravados (via Placement IDs), isolando cargas de trabalho sem a complexidade restritiva do ZNS.
      • A Solução de Software: O io_uring passthrough permite enviar comandos NVMe direto ao hardware, ignorando a camada de bloco do Linux e economizando até 50% de CPU em IOPS elevados.

      A física do NAND e a origem do caos

      Para entender por que o FDP é revolucionário, precisamos revisitar a limitação física fundamental da memória flash. Você pode ler uma página (4KB, 8KB, 16KB), pode escrever uma página, mas só pode apagar um bloco inteiro (que contém centenas de páginas).

      Quando seu banco de dados sobrescreve um registro, o SSD não sobrescreve o dado físico. Ele grava a nova versão em outro lugar e marca a antiga como "inválida". O bloco original vira um queijo suíço de dados válidos e lixo. Para recuperar espaço, o controlador do SSD precisa ler os dados válidos restantes, movê-los para um novo bloco e apagar o bloco antigo.

      Isso é o Garbage Collection. E ele é o assassino silencioso da performance.

      O ciclo destrutivo do Garbage Collection: dados válidos precisam ser movidos antes que um bloco possa ser apagado, consumindo banda interna e aumentando a latência. Figura: O ciclo destrutivo do Garbage Collection: dados válidos precisam ser movidos antes que um bloco possa ser apagado, consumindo banda interna e aumentando a latência.

      Se você escreve 1GB de dados e o SSD precisa mover internamente 3GB de dados antigos para liberar espaço, seu WAF é 4. Isso significa 4x mais desgaste no NAND e 4x menos banda disponível para sua aplicação.

      ⚠️ Perigo: Em cargas mistas (escrita aleatória intensa), o WAF pode facilmente passar de 4 ou 5 em SSDs corporativos cheios, reduzindo a vida útil do drive drasticamente.

      Por que o over-provisioning é um curativo caro

      A solução tradicional da indústria para mitigar o WAF sempre foi bruta: Over-provisioning (OP). Você compra um SSD de 4TB, mas formata apenas 3.2TB, deixando 20-28% de espaço livre para o controlador "respirar".

      Embora funcione para reduzir a probabilidade de colisão do GC, o OP é economicamente ineficiente. Você está pagando por silício que não usa para armazenar dados. Além disso, o OP não resolve a raiz do problema: a mistura de dados com tempos de vida diferentes (ex: logs de transação que duram segundos misturados com tabelas de referência que duram meses).

      NVMe flexible data placement como arquitetura de isolamento

      Ratificado na especificação técnica TP 4146 da NVM Express, o FDP (Flexible Data Placement) é a resposta pragmática da indústria ao problema da mistura de dados.

      Diferente do ZNS (Zoned Namespaces), que obriga a aplicação a escrever sequencialmente (o que exige reescrever engines de storage inteiras como RocksDB ou MySQL), o FDP permite escritas aleatórias. A mágica acontece através de "dicas" chamadas Placement IDs (PIDs).

      Como funciona o FDP

      O SSD expõe ao host (servidor) a sua geometria de alinhamento, chamada de Reclaim Units (RU). O host, sabendo quais dados pertencem a qual contexto (ex: PID 1 para Journal, PID 2 para Tabelas, PID 3 para Temp), anexa essa tag no comando de escrita.

      O SSD garante que dados com o mesmo PID sejam gravados no mesmo RU. Quando chegar a hora de apagar os dados do PID 3 (temporários), o bloco inteiro provavelmente já estará inválido ou quase vazio. O resultado? O Garbage Collector tem pouco ou nenhum trabalho para fazer. O WAF cai para próximo de 1.

      Comparação de alocação: No modo padrão (topo), dados de diferentes ciclos de vida se misturam. Com FDP (fundo), o host guia o isolamento físico dos dados. Figura: Comparação de alocação: No modo padrão (topo), dados de diferentes ciclos de vida se misturam. Com FDP (fundo), o host guia o isolamento físico dos dados.

      Tabela Comparativa: Padrão vs ZNS vs FDP

      Característica SSD NVMe Padrão Zoned Namespaces (ZNS) Flexible Data Placement (FDP)
      Mecanismo de Escrita Caixa preta (Controlador decide) Estritamente Sequencial Aleatório (com dicas de PID)
      Complexidade de Adoção Nula (Plug & Play) Alta (Requer reescrita de App) Média (Pequenas alterações no driver/app)
      Redução de WAF Baixa (Depende de sorte/OP) Máxima (WAF ~1) Alta (WAF próximo de 1)
      Uso de DRAM no SSD Alto (Tabelas de mapeamento grandes) Baixo (Mapeamento simplificado) Médio (Ainda requer mapeamento)

      Eliminando overhead de syscalls com io_uring passthrough

      Resolver o WAF é metade da batalha. A outra metade é garantir que a CPU não seja o gargalo ao enviar milhões de IOPS para esses dispositivos NVMe ultra-rápidos.

      A pilha de armazenamento tradicional do Linux (VFS -> Block Layer -> SCSI/NVMe Driver) foi desenhada na era dos discos rotacionais. Para um SSD Gen5 capaz de 14 GB/s, cada context switch e cada instrução conta.

      É aqui que entra o io_uring passthrough, introduzido no kernel 5.19 e amadurecido nas séries 6.x.

      O caminho expresso

      O io_uring original já reduzia syscalls usando anéis de submissão e completação compartilhados entre kernel e userspace. O modo passthrough leva isso além: ele permite que a aplicação construa o comando NVMe (o pacote de 64 bytes definido na spec) e o coloque diretamente na fila de submissão do driver NVMe.

      Isso ignora completamente:

      1. O sistema de arquivos (VFS).

      2. A camada de bloco (bio, request queues, schedulers).

      3. As traduções de estruturas de dados do kernel.

      💡 Dica Pro: O ganho de performance não é apenas em IOPS máximos. A maior vitória é a redução do uso de CPU por I/O. Em testes com drives Gen4/Gen5, o passthrough chega a dobrar a eficiência (IOPS/Core).

      O atalho do io_uring passthrough: ignorar a camada de bloco remove a latência de software e libera ciclos de CPU para o que importa. Figura: O atalho do io_uring passthrough: ignorar a camada de bloco remove a latência de software e libera ciclos de CPU para o que importa.

      Mensurando a redução do WAF com fio e nvme-cli

      Para engenheiros de performance, teoria sem métricas é alucinação. Vamos ver como validar isso na prática. Você precisará de um kernel recente (6.2+ recomendado) e nvme-cli atualizado.

      1. Habilitando FDP

      Primeiro, verifique se seu drive suporta FDP e habilite-o. Drives modernos de data center (como Samsung PM1743 ou Kioxia CD8) já trazem suporte.

      # Listar configurações FDP suportadas
      nvme fdp configs /dev/nvme0n1
      
      # Habilitar uma configuração (ex: config_id 1)
      nvme fdp enable /dev/nvme0n1 --conf_id=1
      

      2. Benchmarking com fio

      O fio possui suporte nativo tanto para io_uring_cmd (passthrough) quanto para diretivas de FDP.

      Exemplo de job file para simular uma carga mista com isolamento via FDP:

      [global]
      filename=/dev/ng0n1  ; Note o uso do char device para passthrough
      ioengine=io_uring_cmd
      cmd_type=nvme
      iodepth=32
      bs=4k
      direct=1
      
      [writer-log]
      rw=write
      fdp=1
      fdp_pli=0  ; Placement ID 0 para logs
      
      [writer-db]
      rw=randwrite
      fdp=1
      fdp_pli=1  ; Placement ID 1 para dados aleatórios
      

      Ao rodar esse teste, monitore os contadores de Media Units Written via SMART log. Compare o WAF (Bytes Escritos no NAND / Bytes Escritos pelo Host) com e sem FDP. A diferença em cargas de longa duração é brutal.

      Resultados reais: latência determinística e IOPS consistentes são a assinatura de uma configuração FDP bem ajustada. Figura: Resultados reais: latência determinística e IOPS consistentes são a assinatura de uma configuração FDP bem ajustada.

      O futuro é granular

      A combinação de NVMe FDP e io_uring passthrough representa o estado da arte em armazenamento de alta performance. Não estamos mais tratando o SSD como uma caixa preta mágica, mas sim colaborando com o dispositivo para gerenciar a entropia dos dados.

      Para arquitetos de infraestrutura e engenheiros de kernel, a mensagem é clara: o hardware já evoluiu. Se sua stack de software ainda trata um SSD NVMe Gen5 como se fosse um disco SAS rápido, você está deixando performance (e dinheiro) na mesa. A adoção dessas tecnologias será o divisor de águas entre sistemas que engasgam sob carga e aqueles que entregam latência previsível, independentemente do volume de escrita.

      Referências & Leitura Complementar

      • NVM Express Technical Proposal 4146 (FDP): Especificação oficial do mecanismo de Flexible Data Placement.

      • Jens Axboe's io_uring Resources: Documentação e patches do mantenedor do subsistema de bloco do Linux.

      • SNIA (Storage Networking Industry Association): Whitepapers sobre cargas de trabalho reais e amplificação de escrita.

      • Manpages: man nvme-fdp, man io_uring.


      Qual a diferença entre NVMe FDP e ZNS (Zoned Namespaces)? O ZNS exige que o host escreva sequencialmente em zonas, o que requer reescrita complexa de aplicações e sistemas de arquivos. O FDP (Flexible Data Placement) permite escritas aleatórias, mas usa 'dicas' (Placement IDs) para agrupar dados com tempo de vida similar, sendo muito mais fácil de implementar em sistemas existentes mantendo benefícios similares de redução de WAF.
      O que é io_uring passthrough? É um recurso do kernel Linux (introduzido na série 5.19+) que permite enviar comandos NVMe (como leituras/escritas) diretamente para o hardware via filas de submissão do io_uring. Ele ignora completamente a camada de bloco tradicional (block layer), eliminando overhead de tradução e reduzindo drasticamente o uso de CPU e latência.
      Como o FDP reduz a Amplificação de Escrita (WAF)? Ao agrupar dados que serão deletados ou atualizados ao mesmo tempo (ex: logs vs. dados estáticos) no mesmo Reclaim Unit, o FDP minimiza a necessidade do Garbage Collector mover dados válidos durante a limpeza de blocos. Isso evita a reescrita interna desnecessária, mantendo o WAF próximo de 1 e aumentando a vida útil do SSD.
      #NVMe FDP #Write Amplification #io_uring #Linux Kernel #SSD Enterprise #Performance Engineering #Storage Optimization
      André Linhares
      Assinatura Técnica

      André Linhares

      Engenheiro de Performance (Kernel/IO)

      "Vivo no kernel space caçando latência com eBPF. Para mim, context switches excessivos são inimigos pessoais e cada ciclo de CPU desperdiçado é uma ofensa técnica."