Executando Storage Benchmarking com o Fio

Como engenheiros, temos que projetar sistemas computacionais e testar hardware para garantir que tarefas específicas funcionem corretamente. Um dos testes mais comuns é verificar o sistema de armazenamento, usando software de terceiros ou escrevendo códigos para avaliar sua performance e obter informações específicas.

Ao usar nossos códigos, temos a liberdade de criar suítes de testes especializadas e diversificadas. Mas, infelizmente, esses códigos não nos permitem fazer uma interpretação e comparação adequada dos resultados em relação a uma referência bem estabelecida e amplamente aceita pela comunidade científica e de engenharia. Dessa forma, temos que procurar ferramentas que nos ajudem a realizar essa análise de benchmark do sistema de armazenamento.

A partir dessa necessidade, Jens Boe desenvolveu a ferramenta Fio (Flexible I/O Tester), uma ferramenta de benchmarking de código aberto que possibilita o teste de dispositivos de armazenamento por meio da simulação de cargas de trabalho. Atualmente, o Fio possui suporte para várias plataformas, como Debian, Ubuntu, Red Hat, Fedora, CentOS & Co, Mandriva, Arch Linux, Solaris, Windows, Berkeley Software and Distributions (BSDs).

Nas seções seguintes mostraremos algumas definições relacionadas ao sistema de armazenamento que você deve conhecer antes de executar o Fio. Mas se você já estiver ciente deles, basta ir para a seção de Primeiros passos com Fio.

Principais métricas dos dispositivos de armazenamento

Cache e buffer

A memória buffer é uma região da memória física destinada a armazenar, de forma temporal, enquanto dados estão sendo transferidos entre dispositivos de entrada e saída. O buffer também ajuda a compensar a diferença de velocidade entre dois processos com tempos de execução diferentes (por exemplo, enviar um documento para impressão).

Por outro lado, na maioria dos casos, a memória cache é uma área de armazenamento que armazena arquivos de forma temporal para a sua posterior leitura. O principal objetivo do cache é aumentar a performance da transferência de dados, ao armazenar uma cópia de um arquivo para evitar a leitura de dados desde uma camada subjacente do sistema de armazenamento, reduzindo assim o tempo de leitura.

Para conhecer o uso das memórias buffer e cache do seu sistema, só precisa escrever no terminal do seu pc o comando free -h  (para meu exemplo, eu usei a opção -h para escolher o formato “human-readable”).

luis@Desktop:~$ free -h

Logo você verá um relatório geral do estado de uso das memórias e exibido da seguinte forma:

          total     used     free    shared   buff/cache   available
Mem:            15Gi     6.4Gi   9.3Gi       17Mi       223Mi       9.4Gi
Swap:           27Gi     17 Mi   27Gi

onde buff/cache é a soma da memória buffer e cache. Você pode usar o comando free –help para obter mais informação.

IOPS

O valor de IOPS (Input/Output Operations Per Second) é uma métrica usada para estimar o número máximo de operações que a unidade de armazenamento pode processar em um intervalo de um segundo. IOPS são comumente medidos em KiB (kibibyte) ou MiB (mebibyte) e seus valores respondem ao tipo de unidade de armazenamento, o número de operações de leitura e gravação, o uso de padrões de acesso sequencial ou aleatório, tamanhos de blocos de dados (por exemplo, 256 blocos de 4 KiB) e outras pré-condições.

Com relação aos seus elementos de construção, o número de operações que um HDD (Hard-Disk Drive) pode realizar depende da latência de rotação (rotational latency) que descreve o tempo necessário para girar o disco para alcanzar um setor específico, assim como do tempo de consulta (seek latency) que descreve o tempo de deslocamento do braço de leitura (actuator arm), resultando em uma velocidade na escala de 102 IOPS. Por outro lado, um SSD (Solid-State Drive) não possui elementos mecânicos, o que permite atingir velocidades mais altas. As velocidades típicas estão na escala de 103 IOPS.

Assim, um SSD será útil em situações em que você precise de acessar uma base de dados, mover arquivos grandes ou executar um programa com frequência, pois os SDDs tem um número maior de IOPS, por outro lado, um HDD é mais barato e responde melhor aos processos de multitarefa como executar uma verificação de vírus, usar um programa e abrir o navegador da Web, tudo ao mesmo tempo.

Throughput

O disk throughput representa a velocidade (em MiB/s) com a qual o disco pode escrever ou ler de forma contínua. Embora seu aplicativo esteja em execução em um site, base de dados, servidor ou outro dispositivo, essa é uma das métricas mais observadas pois fornece uma visão geral da capacidade da taxa de transferência de dados.

Latência

Como consequência da velocidade máxima de processamento de tarefas e parâmetros construtivos, o tempo necessário para realizar uma transferência de dados, ou latência, varia de acordo com o tipo de disco. Dessa forma, uma unidade magnética será muito mais lenta que uma unidade de estado sólido, o que implica em transferência de dados mais lenta e uma menor performance de todo o sistema.

Bandwidth

A largura de banda determina a quantidade de informação que uma unidade de armazenamento pode enviar durante uma transferência. Sua capacidade depende de conexões físicas e lógicas, além de outras limitações tecnológicas.

Primeiros passos com o Fio

Descrição

O Fio é uma ferramenta open source de benchmarking que permite padronizar os testes do sistema de armazenamento, além de evitar que os usuários escrevam códigos de casos de teste específicos. É um gerador de carga de trabalho de entrada e saída (I/O) versátil e flexível o suficiente para suportar configurações detalhadas.

Instalação do Fio

Para arquiteturas baseadas em Linux, as instruções de instalação são semelhantes. Você só precisa usar o comando:

luis@Desktop:~$ sudo apt-get install fio

Acesse a documentação do Fio para conhecer o processo de instalação em outras plataformas.

Argumentos de entrada do Fio

-- name=strO Fio cria um arquivo de acordo com o nome especificado para executar os testes.
--rw=strDefine o tipo de padrão de operações de I/O. Você pode escolher entre as seguintes opções: read, write, randread, randwrite, trim, randtrim, rw,readwrite, randrw, trimwrite e randtrimwrite.
--bs=intDefine o tamanho do bloco que o teste usará para gerar operações de I/O. Se não for especificado, o valor padrão será 4k.
--ioengine=strDefine como a tarefa emitirá os I/O para o arquivo de teste. Acesse a documentação do Fio para ver outros mecanismos de I/O disponíveis (por exemplo, libaio é o mecanismo de I/O padrão no Linux).
--size=intDefine o tamanho do arquivo com o qual o Fio executará o teste. Se a unidade não for escrita, a unidade padrão será MiB.
--numjobs=intDefine o número de threads ou processos independentes. Ao definir um número maior do que 1, o Fio realizará vários processos fazendo a mesma coisa. (por exemplo, ao definir –numjobs=5, cinco arquivos de teste individuais com tamanho definido em –size=int serão criados.)
--runtime=intDefine o tempo total estabelecido para concluir o teste. Se o processo terminar antes de atingir esse período de tempo, o Fio recomeçará até que a simulação seja concluída. As unidades estão em segundos, e seu valor geralmente é 60.
--time_basedSe estiver incluído, este especifica que o teste será executado repetidamente quantas vezes o tempo de execução permitir.
--group_reportingSe estiver incluído, o Fio gera um relatório de todos os testes executados em vez de mostrá-los individualmente.
--iodepth=intDefine o número de comandos que estarão esperando na fila para serem executados pelo disco rígido.

Executando o Fio

Antes de executar o Fio desde o terminal (ou desde um arquivo de trabalho), você precisará navegar através do diretório para selecionar o disco ou simplesmente indicá-lo ao lado dos argumentos do Fio. Para encontrar facilmente o nome do seu disco, simplesmente deve usar o seguinte comando:

luis@Desktop:~$ lsblk

Este comando permitirá visualizar detalhes dos dispositivos conectados ao PC, na seguinte forma:

NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0    7:0    0     4K  1 loop /snap/bare/5
loop1    7:1    0 400.8M  1 loop /snap/gnome-3-38-2004/112
loop2    7:2    0    62M  1 loop /snap/core20/1587
loop3    7:3    0 163.3M  1 loop /snap/firefox/1635
loop4    7:4    0  91.7M  1 loop /snap/gtk-common-themes/1535
loop5    7:5    0  45.9M  1 loop /snap/snap-store/582
loop6    7:6    0    47M  1 loop /snap/snapd/16292
loop7    7:7    0   284K  1 loop /snap/snapd-desktop-integration/14
sda      8:0    0 931.5G  0 disk
├─sda1   8:1    0   512M  0 part /boot/efi
└─sda2   8:2    0   931G  0 part /
sdb      8:16   1  14.4G  0 disk
└─sdb1   8:17   1  14.4G  0 part /media/luis/LUCHO
sr0     11:0    1  1024M  0 rom

No meu caso, tenho um HDD e um disco externo com capacidade de 931,5 GiB (sda) e 14,1 GiB (sdb), respectivamente. Uma vez que foi identificado o disco a ser avaliado, o endereço deve ser definido como –filename=/dev/sdb.

Nota: Verifique que o nome da unidade esteja correto, pois especificar uma unidade errada pode causar sérios problemas.

Você pode executar o Fio e simular testes desejados escrevendo os argumentos em uma única linha da seguinte forma

luis@Desktop:~$ sudo fio --filename=/dev/sdb --rw=read --direct=1 --bs=4k --ioengine=libaio --runtime=60 --numjobs=1 --time_based --group_reporting --name=seq_read --iodepth=16

O Fio iniciará o teste imediatamente e, uma vez concluído, exibirá um relatório como mostrado abaixo.

Seq_read: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=16
fio-3.28
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=28.8MiB/s][r=7371 IOPS][eta 00m:00s]
seq_read: (groupid=0, jobs=1): err= 0: pid=5028: Fri Oct 21 13:20:15 2022
  read: IOPS=7329, BW=28.6MiB/s (30.0MB/s)(1718MiB/60002msec)
    slat (nsec): min=1550, max=1752.6k, avg=4170.66, stdev=9485.59
    clat (usec): min=307, max=15484, avg=2177.77, stdev=222.49
     lat (usec): min=329, max=15486, avg=2182.10, stdev=222.55
    clat percentiles (usec):
     |  1.00th=[ 1926],  5.00th=[ 2024], 10.00th=[ 2089], 20.00th=[ 2114],
     | 30.00th=[ 2114], 40.00th=[ 2114], 50.00th=[ 2147], 60.00th=[ 2147],
     | 70.00th=[ 2212], 80.00th=[ 2245], 90.00th=[ 2311], 95.00th=[ 2442],
     | 99.00th=[ 2704], 99.50th=[ 2868], 99.90th=[ 4359], 99.95th=[ 4948],
     | 99.99th=[ 7242]
   bw (  KiB/s): min=27920, max=30928, per=100.00%, avg=29333.65, stdev=656.56, samples=119
   iops        : min= 6980, max= 7732, avg=7333.39, stdev=164.13, samples=119
  lat (usec)   : 500=0.04%, 750=0.04%, 1000=0.11%
  lat (msec)   : 2=4.13%, 4=95.53%, 10=0.14%, 20=0.01%
  cpu          : usr=2.39%, sys=4.00%, ctx=54843, majf=0, minf=26
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=100.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=439765,0,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16
Run status group 0 (all jobs):
   READ: bw=28.6MiB/s (30.0MB/s), 28.6MiB/s-28.6MiB/s (30.0MB/s-30.0MB/s), io=1718MiB (1801MB), run=60002-60002msec
Disk stats (read/write):
  sdb: ios=54619/0, merge=384382/0, ticks=118257/0, in_queue=118258, util=99.90%

Descrição do relatório de Fio

Agora, vamos identificar as várias linhas exibidas no relatório.

slat (nsec): min=1550, max=1752.6k, avg=4170.66, stdev=9485.59

slat é a latência de envio e defina pelo valor mínimo (min), máximo (max), médio (avg) e desvio padrão (stdev),

clat (usec): min=307, max=15484, avg=2177.77, stdev=222.49

clat denota a latência de conclusão (completion latency),

lat (usec): min=329, max=15486, avg=2182.10, stdev=222.55

lat é a latência total (é a soma de clat e slat),

clat percentiles (usec):     
|  1.00th=[ 1926],  5.00th=[ 2024], 10.00th=[ 2089], 20.00th=[ 2114],     
| 30.00th=[ 2114], 40.00th=[ 2114], 50.00th=[ 2147], 60.00th=[ 2147],     
| 70.00th=[ 2212], 80.00th=[ 2245], 90.00th=[ 2311], 95.00th=[ 2442],     
| 99.00th=[ 2704], 99.50th=[ 2868], 99.90th=[ 4359], 99.95th=[ 4948],     
| 99.99th=[ 7242]

clat percentiles descreve os percentis de latência de conclusão (provavelmente a informação mais útil),

bw (  KiB/s): min=27920, max=30928, per=100.00%, avg=29333.65, stdev=656.56, samples=119

bw denota a largura de banda ou bandwidth,

iops        : min= 6980, max= 7732, avg=7333.39, stdev=164.13, 

iops são estatísticas de IOPS baseadas nas amostras,

samples=119lat (usec)   : 500=0.04%, 750=0.04%, 1000=0.11%lat (msec)   : 2=4.13%, 4=95.53%, 10=0.14%, 20=0.01%

lat é a distribuição de latência em microssegundos (usec) e milissegundos (msec),

cpu          : usr=2.39%, sys=4.00%, ctx=54843, majf=0, minf=26

cpu descreve o uso da CPU,

IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=100.0%, 32=0.0%, >=64=0.0%   
submit       : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%   
complete     : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0%  
issued rwts  : total=439765,0,0,0 short=0,0,0,0 dropped=0,0,0,0   
latency      : target=0, window=0, percentile=100.00%, depth=16

IO depths representam o número de I/O emitidas para o sistema operativo em um determinado período de tempo, IO submit e IO complete representam as I/O enviadas e concluídas pelo Fio em um determinado período de tempo, IO issued rwts e IO latency descrevem a profundidade de I/O necessária para atingir o objetivo de latência especificada (esses valores são usados ​​em simulações que empregam latency_target e outras opções relacionadas).

Run status group 0 (all jobs):READ: bw=28.6MiB/s (30.0MB/s), 28.6MiB/s-28.6MiB/s (30.0MB/s-30.0MB/s), io=1718MiB (1801MB), run=60002-60002msec

Posteriormente, estatísticas do grupo são apresentadas após o término dos testes. Lembre-se, no meu exemplo eu realizei um teste de leitura (READ). Aqui, bw=28,6MiB/s corresponde à largura de banda agregada das threads, seguida de seus valores máximo e mínimo (28,6MiB/s-28,6MiB/s), io é o valor de I/O agregada realizada de todas as threads deste grupo, run indica os tempos de execução menores e mais longos dos threads.

 Nota: Os valores são impressos tanto na base 2 (MiB/s) quanto na base 10 (MB/s).

Disk stats (read/write):  sdb: ios=54619/0, merge=384382/0, ticks=118257/0, in_queue=118258, util=99.90%

Por fim, o Fio exibe as estatísticas do disco analisado (sdb). Aqui, ios é o número de I/Os, merge é o número de merges, ticks é o número de ticks que mantivemos o disco ocupado (quantidade de tempo medido em ticks), in_queue é o tempo total gasto na fila do disco e util é a porcentagem da utilização do disco.

Resumo

O Fio é uma ferramenta amplamente aceita e utilizada em infraestruturas como Red Hat, Oracle Cloud, Amazon e Azure. O Fio tem suporte multiplataforma e pode ser usado para verificar a performance e encontrar bugs.

Para conhecer mais sobre essa ferramenta, acesse a documentação do Fio.

Scroll to Top