Por que o fio seq_writes é muito mais rápido que o dd?

1

Eu tenho um servidor zfs, onde fiz alguns testes para entender, e isso me intriga.

Contexto: - FreeBSD 11.2, ZFS com Compressão ativada, HDDs SAS, RAIDz2, 768GB de memória.

Ambos os comandos foram executados diretamente no servidor do FreeBSD.

# time dd if=/dev/random of=./test_file bs=128k count=131072 
131072+0 records in
131072+0 records out
17179869184 bytes transferred in 135.191596 secs (127077937 bytes/sec)
0.047u 134.700s 2:15.19 99.6%   30+172k 4+131072io 0pf+0w

# #The result file size:
# du -sh test_file 
  16G   test_file

Isso mostra que eu consegui um arquivo de 16GiB com dados aleatórios em 135 segundos com uma taxa de transferência de aprox. 117 MiB / s.

Agora, tento usar fio ,

# fio --name=seqwrite --rw=write --bs=128k --numjobs=1 --size=16G --runtime=120 --iodepth=1 --group_reporting
seqwrite: (g=0): rw=write, bs=(R) 128KiB-128KiB, (W) 128KiB-128KiB, (T) 128KiB-128KiB, ioengine=psync, iodepth=1
fio-3.6
Starting 1 process
seqwrite: Laying out IO file (1 file / 16384MiB)
Jobs: 1 (f=1): [W(1)][100.0%][r=0KiB/s,w=2482MiB/s][r=0,w=19.9k IOPS][eta 00m:00s]
seqwrite: (groupid=0, jobs=1): err= 0: pid=58575: Wed Jul 25 09:38:06 2018
  write: IOPS=19.8k, BW=2478MiB/s (2598MB/s)(16.0GiB/6612msec)
    clat (usec): min=28, max=2585, avg=48.03, stdev=24.04
     lat (usec): min=29, max=2586, avg=49.75, stdev=25.19
   bw (  MiB/s): min= 2295, max= 2708, per=99.45%, avg=2464.33, stdev=124.56, samples=13
   iops        : min=18367, max=21664, avg=19714.08, stdev=996.47, samples=13
---------- Trimmed for brevity -------------
Run status group 0 (all jobs):
  WRITE: bw=2478MiB/s (2598MB/s), 2478MiB/s-2478MiB/s (2598MB/s-2598MB/s), io=16.0GiB (17.2GB), run=6612-6612msec

Agora, atingi 2478 MiB / s de taxa de transferência. enquanto usa o mesmo arquivo de 16 GiB com dados aleatórios.

Por que existe uma diferença tão grande? Meu entendimento é que o comando dd deve ter usado create call para criar um arquivo, em seguida, emitir open e write chamadas para gravar os dados aleatórios no arquivo aberto. Finalmente close o arquivo. Eu escolhi tamanho de bloco de 128 K para corresponder ao tamanho de registro padrão do ZFS.

O teste de espessura deve medir apenas as chamadas write , mas tudo o mais, o mesmo. Por que há tanta diferença no rendimento?

Para me confundir ainda mais, se eu pedi à fio para criar um arquivo com 50% de compressibilidade, o throughput cai para 847 MiB / s. Eu entendo que há um trabalho de CPU envolvido na compressão causando uma queda no throughput, mas eu esperava que seu impacto fosse neutralizado por ter quase metade da quantidade de dados para escrever. Alguma idéia de por que o impacto é tão alto?

Comando usado para executar fio com 50% de compressibilidade:

 fio --name=seqwrite --rw=write --bs=128k --numjobs=1 --size=16G --runtime=60 --iodepth=1 --buffer_compress_percentage=50 --buffer_pattern=0xdeadbeef --group_reporting
    
por Aravindh Sathish 25.07.2018 / 10:07

1 resposta

2

Vou reformular sua pergunta para destacar alguns dos contextos:

Why is

fio --name=seqwrite --rw=write --bs=128k --numjobs=1 --size=16G --runtime=120 --iodepth=1 --group_reporting

faster than

time dd if=/dev/random of=./test_file bs=128k count=131072 

on a FreeBSD 11.2 system with 768GB RAM, SAS HDDs and ZFS configured as a RAIDZ2 with compression enabled?

A principal diferença é que o fio está preparando o arquivo antes de fazer os testes de tempo:

seqwrite: Laying out IO file (1 file / 16384MiB)

considerando que dd provavelmente está fazendo gravações de extensão de arquivo (o que causará atualizações de metadados). Além disso, você tem muita memória RAM (768G) e está escrevendo tão poucos dados em comparação a ela (16G). Há uma strong chance de suas gravações serem armazenadas na RAM (e não gravadas no disco até muito mais tarde). Isso provavelmente está no caso fio em que o arquivo foi pré-criado e muito pouco metadados de arquivo precisa ser modificado por E / S. Você pode pelo menos dizer ao fio para não dizer que está pronto até que todos os dados escritos sejam escritos do kernel no final do trabalho usando end_fsync=1 .

(NB: Há uma dica sutil de que a E / S está sendo armazenada em buffer quando você vê latências de conclusão muito menores do que o que você sabe que seu disco pode fazer:

clat (usec): min=28, max=2585, avg=48.03, stdev=24.04

O seu disco giratório pode realmente completar uma E / S em 28 microssegundos? Se não é provável que tenha buffer em algum lugar)

Finalmente, o padrão é reutilizar o mesmo padrão nos blocos subseqüentes . Como há compactação acontecendo, isso pode melhorar ainda mais sua taxa de transferência de fio (mas isso dependerá de itens como o tamanho do registro do ZFS). Para verificar isso, informe ao fio para tornar seus buffers incompressíveis (o que, por sua vez, transforma refill_buffers on) e veja se a taxa de transferência cai (o que aconteceu no seu caso).

TLDR; Os comandos fio e dd que você deu não estão testando a mesma coisa. Você precisa estar ciente de coisas como se seus arquivos já existem no tamanho correto, quão compactáveis são os dados que você está escrevendo e se você está respondendo por coisas como buffer de kernel escrevendo poucos dados e não verificando se tudo foi escrito de volta para o disco.

    
por 29.07.2018 / 22:45