Por que o ZFS é muito mais lento que o ext4 e o btrfs?

11

Problema

Instalei recentemente um novo disco e criei um zpool nele:

/# zpool create morez /dev/sdb

Depois de usá-lo por um tempo, notei que era bastante lento:

/morez# fio --name rw --rw rw --size 10G
   read: IOPS=19.6k, BW=76.6MiB/s (80.3MB/s)(5120MiB/66834msec)
  write: IOPS=19.6k, BW=76.6MiB/s (80.3MB/s)(5120MiB/66834msec)

Este teste é bastante semelhante ao meu caso de uso real. Estou lendo um número moderado (~ 10k) de imagens (~ 2 MiB cada) do disco. Eles foram gravados de uma só vez quando o disco estava praticamente vazio, portanto, não espero que estejam fragmentados.

Para comparação, testei o ext4:

/# gdisk /dev/sdb
...
/# mkfs.ext4 -f /dev/sdb1 && mount /dev/sdb1 /mnt && cd /mnt
/mnt# fio --name rw --rw rw --size 10G
   read: IOPS=48.3k, BW=189MiB/s (198MB/s)(5120MiB/27135msec)
  write: IOPS=48.3k, BW=189MiB/s (198MB/s)(5120MiB/27135msec)

E btrfs:

/# mkfs.btrfs -f /dev/sdb1 && mount /dev/sdb1 /mnt && cd /mnt
/mnt# fio --name rw --rw rw --size 10G
   read: IOPS=51.3k, BW=201MiB/s (210MB/s)(5120MiB/25528msec)
  write: IOPS=51.3k, BW=201MiB/s (210MB/s)(5120MiB/25528msec)

O que pode estar causando problemas de desempenho no ZFS e como posso torná-lo mais rápido?

Falha na tentativa de solução

Também tentei definir explicitamente o tamanho do setor para o zpool, pois meu disco ( Seagate ST1000DM003 ) usa setores físicos de 4096 bytes:

/# zpool create -o ashift=12 morez /dev/sdb

Isso não melhorou o desempenho:

/morez# fio --name rw --rw rw --size 10G
   read: IOPS=21.3k, BW=83.2MiB/s (87.2MB/s)(5120MiB/61573msec)
  write: IOPS=21.3k, BW=83.2MiB/s (87.2MB/s)(5120MiB/61573msec)

Observação

Estranhamente, o uso de um zvol teve um ótimo desempenho:

/# zfs create -V 20G morez/vol
/# fio --name rw --filename /dev/zvol/morez/vol --rw rw --size 10G
   read: IOPS=52.7k, BW=206MiB/s (216MB/s)(5120MiB/24852msec)
  write: IOPS=52.7k, BW=206MiB/s (216MB/s)(5120MiB/24852msec)

Por que isso afeta apenas os sistemas de arquivos ZFS e não os zvols?

Teste estendido para btrfs

Nos comentários, foi sugerido que a diferença pode ser devido ao cache. Após mais testes, não acredito que seja esse o caso. Aumentei o tamanho do teste btrfs bem acima da quantidade de memória que meu computador possui e seu desempenho ainda era significativamente maior que o do ZFS:

/# mkfs.btrfs -f /dev/sdb1 && mount /dev/sdb1 /mnt && cd /mnt
/mnt# $ fio --name rw --rw rw --size 500G --runtime 3600 --time_based --ramp_time 900
   read: IOPS=41.9k, BW=164MiB/s (172MB/s)(576GiB/3600003msec)
  write: IOPS=41.9k, BW=164MiB/s (172MB/s)(576GiB/3600003msec)

Informação do sistema

Programas

  • Arch Linux, versão do kernel 4.11.6
  • ZFS no Linux 0.6.5.10
  • fio 2.21

Hardware

Informações do ZFS

Aqui está como eram as propriedades do ZFS antes de executar o fio. Estes são apenas o resultado da criação de um zpool com as configurações padrão.

# zpool get all morez
NAME   PROPERTY                    VALUE            SOURCE
morez  size                        928G             -
morez  capacity                    0%               -
morez  altroot                     -                default
morez  health                      ONLINE           -
morez  guid                        [removed]        default
morez  version                     -                default
morez  bootfs                      -                default
morez  delegation                  on               default
morez  autoreplace                 off              default
morez  cachefile                   -                default
morez  failmode                    wait             default
morez  listsnapshots               off              default
morez  autoexpand                  off              default
morez  dedupditto                  0                default
morez  dedupratio                  1.00x            -
morez  free                        928G             -
morez  allocated                   276K             -
morez  readonly                    off              -
morez  ashift                      0                default
morez  comment                     -                default
morez  expandsize                  -                -
morez  freeing                     0                default
morez  fragmentation               0%               -
morez  leaked                      0                default
morez  feature@async_destroy       enabled          local
morez  feature@empty_bpobj         enabled          local
morez  feature@lz4_compress        active           local
morez  feature@spacemap_histogram  active           local
morez  feature@enabled_txg         active           local
morez  feature@hole_birth          active           local
morez  feature@extensible_dataset  enabled          local
morez  feature@embedded_data       active           local
morez  feature@bookmarks           enabled          local
morez  feature@filesystem_limits   enabled          local
morez  feature@large_blocks        enabled          local

# zfs get all morez
NAME   PROPERTY              VALUE                  SOURCE
morez  type                  filesystem             -
morez  creation              Thu Jun 29 19:34 2017  -
morez  used                  240K                   -
morez  available             899G                   -
morez  referenced            96K                    -
morez  compressratio         1.00x                  -
morez  mounted               yes                    -
morez  quota                 none                   default
morez  reservation           none                   default
morez  recordsize            128K                   default
morez  mountpoint            /morez                 default
morez  sharenfs              off                    default
morez  checksum              on                     default
morez  compression           off                    default
morez  atime                 on                     default
morez  devices               on                     default
morez  exec                  on                     default
morez  setuid                on                     default
morez  readonly              off                    default
morez  zoned                 off                    default
morez  snapdir               hidden                 default
morez  aclinherit            restricted             default
morez  canmount              on                     default
morez  xattr                 on                     default
morez  copies                1                      default
morez  version               5                      -
morez  utf8only              off                    -
morez  normalization         none                   -
morez  casesensitivity       sensitive              -
morez  vscan                 off                    default
morez  nbmand                off                    default
morez  sharesmb              off                    default
morez  refquota              none                   default
morez  refreservation        none                   default
morez  primarycache          all                    default
morez  secondarycache        all                    default
morez  usedbysnapshots       0                      -
morez  usedbydataset         96K                    -
morez  usedbychildren        144K                   -
morez  usedbyrefreservation  0                      -
morez  logbias               latency                default
morez  dedup                 off                    default
morez  mlslabel              none                   default
morez  sync                  standard               default
morez  refcompressratio      1.00x                  -
morez  written               96K                    -
morez  logicalused           72.5K                  -
morez  logicalreferenced     40K                    -
morez  filesystem_limit      none                   default
morez  snapshot_limit        none                   default
morez  filesystem_count      none                   default
morez  snapshot_count        none                   default
morez  snapdev               hidden                 default
morez  acltype               off                    default
morez  context               none                   default
morez  fscontext             none                   default
morez  defcontext            none                   default
morez  rootcontext           none                   default
morez  relatime              off                    default
morez  redundant_metadata    all                    default
morez  overlay               off                    default
Bola de neve
fonte
Não há detalhes como o hardware em uso, sistema operacional e versão, controlador, configurações do sistema etc. Não sei ao certo o que podemos lhe dizer!
ewwhite
2
Qual é o drive em si? É uma unidade SATA de consumo pronta para uso. Você tem um longo caminho a percorrer para provar que ele realmente pode lidar com mais de 200 MB / s sustentados. A maioria das unidades SATA de nível de consumidor em condições reais terá a sorte de obter mais de 70-80 operações de E / S por segundo, ou mais do que cerca de 100-120 MB / s. E se você fizer operações aleatórias de E / S de blocos pequenos em uma unidade como essa, provavelmente obterá algo como 30-40 KB / s. 10 GB podem facilmente ficar no cache.
Andrew Henle 29/06
1
@ewwhite Não há configurações de ajuste estão presentes em/etc/modprobe.d/zfs.conf
Snowball
1
@whwhite Eles são. Limpei a tabela de partição entre cada teste. Em todos os casos, a partição teve um deslocamento de 1 MiB desde o início do disco.
Snowball
1
Observe para si mesmo / qualquer pessoa que tropeça nessa questão: as configurações de ajuste mencionadas pelo ewwhite estão documentadas man 5 zfs-module-parameters.
Snowball

Respostas:

6

Enquanto velho, sinto que esta pergunta merece uma resposta.

fioemite, por padrão, IOPs do tamanho de 4KB; Os conjuntos de dados do ZFS, em vez disso, usam 128 KB de gravação por padrão. Essa incompatibilidade significa que cada gravação em 4K causa uma leitura / modificação / gravação de todo o registro de 128K.

Os ZVOLs, por outro lado, usam tamanho de bloco de 8K por padrão. Isso significa que uma gravação em 4K causa um ciclo de leitura / modificação / gravação muito menor de um registro de 8K e, com alguma sorte, duas gravações em 4K podem ser combinadas em uma única gravação de 8K (que não requer leitura / modificação / gravação).

O zfs set recordize=8K <dataset>tamanho do registro do conjunto de dados do ZFS pode ser alterado e, nesse caso, deve fornecer um desempenho mais ou menos equivalente aos ZVOLs. No entanto, quando usado para transferências relativamente grandes (o OP falou sobre arquivos de 2 MB que, sendo imagens, devem ser lidos inteiramente toda vez que forem acessados), é melhor ter um tamanho de registro / volume grande , às vezes até maior que a configuração padrão (128K).

shodanshok
fonte
4

Nota: como o trabalho do fio não possui direct=1( http://fio.readthedocs.io/en/latest/fio_doc.html#cmdoption-arg-direct ), uma certa quantidade de E / S que está sendo executada (leitura e gravação) pode ser armazenada em cache pelo sistema operacional, distorcendo seus resultados (e aumentando os números artificialmente). Isso por si só é ainda mais complicado pelo seguinte:

Esteja ciente de que O_DIRECTainda é permitido fazer E / S em buffer porque no Linux O_DIRECTé mais uma dica (consulte a seção de referências em /programming//a/46377629/2732969 ).

Se você estiver em uma situação em que não pode ignorar corretamente os caches, é crucial que você faça E / S suficientes em uma área grande o suficiente para minimizar o impacto do cache (a menos, é claro, que você realmente queira testar o cache) ...

Anon
fonte