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

8

Problema

Eu instalei recentemente um novo disco e criei um zpool nele:

/# zpool create morez /dev/sdb

Depois de usá-lo por um tempo, percebi que era bem 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 escritos de uma só vez quando o disco estava quase vazio, então eu não espero que eles sejam 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 com o ZFS e como posso torná-lo mais rápido?

Falha na tentativa de solução

Eu também tentei configurar explicitamente o tamanho do setor para o zpool, como meu disco ( 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, usar 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 armazenamento em cache. Depois de mais testes, não acredito que seja esse o caso. Eu 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ções do sistema

Software

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

Hardware

Informações do ZFS

Veja a aparência das 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
    
por Snowball 29.06.2017 / 19:43

2 respostas

3

Enquanto velho, sinto que esta questão merece uma resposta.

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

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

O tamanho do registro do conjunto de dados do ZFS pode ser alterado com zfs set recordize=8K <dataset> e, nesse caso, ele deve fornecer desempenho mais ou menos equivalente do que os ZVOLs. No entanto, quando usado para transferências relativamente grandes (OP falou sobre arquivos de 2 MB que, sendo imagens, devem ser totalmente lidos cada vez que eles são acessados) é melhor ter grande recordsize / volblocksize, em algum momento até grande então a configuração padrão (128K).

    
por 11.09.2018 / 21:25
2

Esteja avisado - o seu trabalho de trabalho não possui direct=1 ( link ) então, uma certa quantidade de E / S sendo executada (ambas as leituras e gravação) pode ser armazenada em cache pelo próprio sistema operacional distorcendo seus resultados, tornando-os artificialmente altos.

    
por 22.07.2017 / 04:17