Estou executando alguns fio
testes em um novo servidor com a seguinte configuração:
- 1 unidade Samsung PM981a de 512 GB M.2 NVMe.
- Proxmox instalado com ZFS na raiz.
- 1x VM com 30 GB de espaço criado e Debian 10 instalado.
- 6x unidades Intel P4510 2TB U.2 NVMe conectadas a 6x pistas PCIe 4.0 x4 dedicadas com OCuLink.
- Anexado diretamente à VM única.
- Configurado como RAID10 na VM (3x espelhos distribuídos).
- Placa-mãe / CPU / memória: ASUS KRPA-U16 / EPYC 7302P / 8x32GB DDR4-3200
Os discos são classificados para leituras sequenciais de até 3.200 MB/s . Do ponto de vista teórico, isso deve fornecer uma largura de banda máxima de 19,2 GB/s.
Executando fio
com numjobs=1
o ZFS RAID estou obtendo resultados na faixa de ~2.000 - 3.000 MB/s (os discos são capazes de 3.200 MB/s completos ao testar sem ZFS ou qualquer outra sobrecarga, por exemplo, durante a execução do Crystal Disk Mark no Windows instalado diretamente em um dos discos):
fio --name=Test --size=100G --bs=1M --iodepth=8 --numjobs=1 --rw=read --filename=fio.test
=>
Run status group 0 (all jobs):
READ: bw=2939MiB/s (3082MB/s), 2939MiB/s-2939MiB/s (3082MB/s-3082MB/s), io=100GiB (107GB), run=34840-34840msec
Parece razoável tudo considerado. Também pode ser limitado à CPU, pois um dos núcleos estará com 100% de carga (com parte disso gasta em processos ZFS).
Quando eu aumento numjobs
para 8-10 as coisas ficam um pouco estranhas:
fio --name=Test --size=100G --bs=1M --iodepth=8 --numjobs=10 --rw=read --filename=fio.test
=>
Run status group 0 (all jobs):
READ: bw=35.5GiB/s (38.1GB/s), 3631MiB/s-3631MiB/s (3808MB/s-3808MB/s), io=1000GiB (1074GB), run=28198-28199msec
38,1 GB/s - bem acima da largura de banda máxima teórica.
Qual é exatamente a explicação aqui?
Adições para comentários:
Configuração da VM:
iotop
durante o teste:
O primeiro
fio
(aquele com--numjobs=1
) executa sequencialmente qualquer operação de leitura, não tendo nenhum benefício de sua configuração de distribuição além de leitura antecipada/pré-busca rápida:iodepth
aplica-se apenas a leituras assíncronas feitas vialibaio
mecanismo, que por sua vez requer suporte verdadeiro paraO_DIRECT
(o que falta ao ZFS) . Você pode tentar aumentar a janela de pré-busca dos 8M padrão para algo como 64M (echo 67108864 > /sys/module/zfs/parameters/zfetch_max_distance
). É claro que sua milhagem pode variar, portanto, certifique-se de verificar se isso não prejudica outras cargas de trabalho.O segundo
fio
(aquele com--numjobs=8
) provavelmente é distorcido pelo cache ARC. Para ter certeza, basta abrir outro terminal em execuçãodstat -d -f
: você verá a verdadeira velocidade de transferência de cada disco e certamente estará alinhada com sua taxa de transferência máxima teórica. Você também pode repetir ofio
teste com uma máquina recém-iniciada (portanto, com um ARC vazio) para ver se as coisas mudam.Para testes de E/S sequenciais com vários trabalhos, cada trabalho (ou seja, thread) tem um ponteiro de arquivo específico de thread (endereço de bloco para dispositivos brutos) que começa em zero por padrão e avança independentemente dos outros threads. Isso significa que o fio emitirá solicitações de leitura para o sistema de arquivos com ponteiros de arquivo/endereços de bloco duplicados/sobrepostos nos trabalhos. Você pode ver isso em ação se usar a
write_iolog
opção. As solicitações sobrepostas distorcerão o resultado do benchmark, pois provavelmente serão atendidas por um cache de leitura, seja no sistema de arquivos (ao testar um arquivo) ou pelo dispositivo (ao executar em um volume bruto).O que você deseja é um único trabalho e depois modificar o
iodepth
parâmetro exclusivamente para controlar a profundidade da fila de E/S. Isso especifica o número de E/Ss simultâneas que cada trabalho pode ter ativo.A única desvantagem é que os IOPs totais alcançáveis podem se tornar limitados a um único núcleo/thread. Isso não deve ser um problema para cargas de trabalho sequenciais de grandes blocos, pois elas não são vinculadas a IOPs. Para E/S aleatória, você definitivamente deseja usar vários trabalhos, especialmente em unidades NVMe que podem lidar com mais de um milhão de IOPs.