Pourquoi ZFS est-il tellement plus lent que ext4 et btrfs?

11

Problème

J'ai récemment installé un nouveau disque et créé un zpool dessus:

/# zpool create morez /dev/sdb

Après l'avoir utilisé pendant un certain temps, j'ai remarqué que c'était assez lent:

/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)

Ce test est assez similaire à mon cas d'utilisation réel. Je lis un nombre modéré (~ 10k) d'images (~ 2 MiB chacune) à partir du disque. Ils ont été écrits d'un coup alors que le disque était presque vide, donc je ne m'attends pas à ce qu'ils soient fragmentés.

Pour comparaison, j'ai testé 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)

Et 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)

Qu'est-ce qui pourrait être à l'origine des problèmes de performances avec ZFS et comment puis-je le rendre plus rapide?

Échec d'une tentative de solution

J'ai également essayé de définir explicitement la taille du secteur pour le zpool, car mon disque ( Seagate ST1000DM003 ) utilise des secteurs physiques de 4096 octets:

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

Cela n'a pas amélioré les performances:

/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)

Observation

Curieusement, l'utilisation d'un zvol a eu de grandes performances:

/# 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)

Pourquoi cela n'affecte-t-il que les systèmes de fichiers ZFS et non les zvols?

Tests étendus pour btrfs

Dans les commentaires, il a été suggéré que la différence pourrait être due à la mise en cache. Après de nouveaux tests, je ne pense pas que ce soit le cas. J'ai augmenté la taille du test btrfs bien au-dessus de la quantité de mémoire de mon ordinateur et ses performances étaient encore nettement supérieures à celles de 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)

Information système

Logiciel

  • Arch Linux, version du noyau 4.11.6
  • ZFS sur Linux 0.6.5.10
  • fio 2.21

Matériel

Informations ZFS

Voici à quoi ressemblaient les propriétés ZFS avant d'exécuter fio. Ce ne sont que le résultat de la création d'un zpool avec les paramètres par défaut.

# 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
Boule de neige
la source
Pas de détails comme le matériel utilisé, le système d'exploitation et la version, le contrôleur, les paramètres système, etc. Je ne sais pas ce que nous pouvons vous dire!
ewwhite
2
Quel est le lecteur lui-même? Il s'agit d'un disque SATA grand public standard. Vous avez un long chemin à parcourir pour prouver qu'il peut réellement supporter plus de 200 Mo / sec. La plupart des disques SATA grand public dans des conditions réelles auront la chance d'obtenir plus de 70 à 80 opérations d'E / S par seconde, soit plus de 100 à 120 Mo / s. Et si vous effectuez des opérations d'E / S aléatoires en petit bloc sur un tel lecteur, vous obtiendrez probablement quelque chose comme 30 à 40 Ko / s. 10 Go pourraient trop facilement se retrouver dans le cache.
Andrew Henle
1
@ewwhite Aucun paramètre de réglage n'est présent dans/etc/modprobe.d/zfs.conf
Snowball
1
@ewwhite Ils le sont. J'ai effacé la table de partition entre chaque test. Dans tous les cas, la partition avait un décalage de 1 Mio depuis le début du disque.
Snowball
1
Remarque pour vous-même / toute autre personne qui tombe sur cette question: les paramètres de réglage mentionnés par ewwhite sont documentés man 5 zfs-module-parameters.
Snowball

Réponses:

6

Bien que vieille, je pense que cette question mérite une réponse.

fioémet, par défaut, des IOP de 4 Ko; Les jeux de données ZFS, à la place, utilisent 128 Ko d'enregistrement par défaut. Cette incompatibilité signifie que chaque écriture 4K entraîne une lecture / modification / écriture de l'ensemble de l'enregistrement 128K.

Les ZVOL, d'autre part, utilisent la taille de bloc vol 8K par défaut. Cela signifie qu'une écriture 4K entraîne un cycle de lecture / modification / écriture beaucoup plus petit d'un enregistrement 8K et, avec un peu de chance, deux écritures 4K peuvent être fusionnées en une seule écriture 8K (qui ne nécessite aucune lecture / modification / écriture).

La taille d'enregistrement du jeu de données ZFS peut être modifiée avec zfs set recordize=8K <dataset>et, dans ce cas, elle devrait donner des performances plus ou moins équivalentes à celles des ZVOL. Cependant, lorsqu'il est utilisé pour des transferts relativement importants (OP parlait de fichiers de 2 Mo qui, étant des images, devraient être entièrement lus chaque fois qu'ils sont accédés), il est préférable d'avoir une taille d' enregistrement / volblocs volumineuse, parfois encore plus grande que le paramètre par défaut (128K).

shodanshok
la source
4

Remarque: comme le travail fio manque direct=1( http://fio.readthedocs.io/en/latest/fio_doc.html#cmdoption-arg-direct ), une partie des E / S en cours d'exécution (en lecture et en écriture) peut être mise en cache par le système d'exploitation, faussant vos résultats (et rendant les chiffres artificiellement élevés). Cela est encore plus compliqué par les éléments suivants:

Soyez conscient O_DIRECTque les E / S tamponnées sont toujours autorisées car sous Linux, O_DIRECTc'est plus un indice (voir la section références de /programming//a/46377629/2732969 ).

Si vous êtes dans une situation où vous ne pouvez pas contourner correctement les caches, il est crucial que vous fassiez suffisamment d'E / S sur une zone suffisamment grande pour minimiser l'impact de la mise en cache (à moins, bien sûr, que vous souhaitiez réellement tester la mise en cache) ...

Anon
la source