¿Por qué ZFS es mucho más lento que ext4 y btrfs?

11

Problema

Recientemente instalé un nuevo disco y creé un zpool en él:

/# zpool create morez /dev/sdb

Después de usarlo por un tiempo, noté 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)

Esta prueba es bastante similar a mi caso de uso real. Estoy leyendo un número moderado (~ 10k) de imágenes (~ 2 MiB cada una) del disco. Fueron escritos de una vez cuando el disco estaba casi vacío, por lo que no espero que estén fragmentados.

A modo de comparación, probé 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)

Y 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é podría estar causando los problemas de rendimiento con ZFS y cómo puedo hacerlo más rápido?

Intento fallido de solución

También intenté establecer explícitamente el tamaño del sector para el zpool, ya que mi disco ( Seagate ST1000DM003 ) usa sectores físicos de 4096 bytes:

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

Esto no mejoró el rendimiento:

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

Observación

Curiosamente, usar un zvol tuvo un gran rendimiento:

/# 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 qué esto solo afecta a los sistemas de archivos ZFS y no a zvols?

Pruebas extendidas para btrfs

En los comentarios, se sugirió que la diferencia puede deberse al almacenamiento en caché. Después de más pruebas, no creo que este sea el caso. Aumenté el tamaño de la prueba btrfs muy por encima de la cantidad de memoria que tiene mi computadora y su rendimiento fue significativamente mayor que el 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)

Información del sistema

Software

  • Arch Linux, kernel versión 4.11.6
  • ZFS en Linux 0.6.5.10
  • fio 2.21

Hardware

Información de ZFS

Aquí se muestran las propiedades de ZFS antes de ejecutar fio. Estos son solo el resultado de crear un zpool con la configuración predeterminada.

# 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 nieve
fuente
No hay detalles como el hardware en uso, el sistema operativo y la versión, el controlador, la configuración del sistema, etc. ¡No estoy seguro de qué podemos decirle!
ewwhite
2
¿Qué es el disco en sí? Es una unidad SATA de consumo estándar. Tienes un largo camino por recorrer para demostrar que en realidad puede manejar más de 200 MB / s sostenidos. La mayoría de las unidades SATA de nivel de consumidor en condiciones reales tendrán la suerte de obtener más de 70-80 operaciones de E / S por segundo, o más de aproximadamente 100-120 MB / seg. Y si realiza operaciones aleatorias de E / S de bloque pequeño en una unidad de este tipo, es probable que obtenga algo así como 30-40 KB / seg. 10 GB podrían fácilmente estar terminando en caché.
Andrew Henle
1
@ewwhite No hay ajustes de sintonización están presentes en/etc/modprobe.d/zfs.conf
la bola de nieve
1
@ewwhite lo son. Limpié la tabla de particiones entre cada prueba. En todos los casos, la partición tenía un desplazamiento de 1 MiB desde el inicio del disco.
Snowball
1
Nota para uno mismo / cualquier otra persona que tropiece con esta pregunta: la configuración de ajuste que menciona ewwhite está documentada man 5 zfs-module-parameters.
Snowball

Respuestas:

6

Mientras viejo, siento que esta pregunta merece una respuesta.

fioemite, por defecto, IOP de tamaño 4KB; Los conjuntos de datos ZFS, en cambio, usan 128 KB de grabación por defecto. Esta falta de coincidencia significa que cada escritura 4K provoca una lectura / modificación / escritura de todo el registro de 128K.

Los ZVOL, por otro lado, usan 8K volblocksize por defecto. Esto significa que una escritura 4K causa un ciclo de lectura / modificación / escritura mucho más pequeño de un registro 8K y, con algo de suerte, dos escrituras 4K pueden fusionarse en una sola escritura 8K (que no requiere lectura / modificación / escritura).

El tamaño de registro del conjunto de datos ZFS se puede cambiar zfs set recordize=8K <dataset>y, en este caso, debería proporcionar un rendimiento más o menos equivalente que los ZVOL. Sin embargo, cuando se usa para transferencias relativamente grandes (OP habló de archivos de 2 MB que, como imágenes, deben leerse por completo cada vez que se accede a ellos) es mejor tener un gran tamaño de registro / volblocksize, a veces incluso mayor que la configuración predeterminada (128K).

shodanshok
fuente
4

Nota: como falta el trabajo de fio direct=1( http://fio.readthedocs.io/en/latest/fio_doc.html#cmdoption-arg-direct ) se puede almacenar en caché una cantidad de E / S que se está realizando (tanto lectura como escritura) por el sistema operativo, distorsionando sus resultados (y haciendo que los números sean artificialmente altos). Esto en sí mismo se complica aún más por lo siguiente:

Tenga en cuenta que O_DIRECTtodavía se permite realizar E / S con búfer porque en Linux O_DIRECTes más una sugerencia (consulte la sección de referencias de /programming//a/46377629/2732969 ).

Si se encuentra en una situación en la que no puede omitir correctamente los cachés, es crucial que haga suficiente E / S en un área lo suficientemente grande como para minimizar el impacto del almacenamiento en caché (a menos, por supuesto, que realmente desee probar el almacenamiento en caché) ...

Luego
fuente