ZFS recordsize y qcow2 cluster_size

per Victor Carceler darrera modificació 2021-01-07T10:29:11+02:00

https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Openzfs.svg/1000px-Openzfs.svg.pngUna aplicación frecuente de OpenZFS es almacenar ficheros qcow2 de diferentes máquinas virtuales. En esta situación conviene saber que se obtiene mejor rendimiento cuando se hace coincidir en tamaño la propiedad recordsize de OpenZFS con el valor cluster_size de los ficheros qcow2.

Sobre la propiedad recordsize

OpenZFS permite definir el valor de la propiedad recordsize para cada dataset (el equivalente de un sistema de archivos que toma capacidad de un pool). Dicha propiedad limita el tamaño de los registros, que contienen bloques, cuando se almacena la información.

El tamaño del bloque se define con el parámetroashiften el momento de construir el pool y es inmutable. Pero el tamaño de los registros se puede cambiar en cualquier momento y su valor por defecto es 128K.

Por ejemplo, podemos consultar la propiedad del pool DATA/libvirt de la siguiente manera:

root@edoras:~# zfs get recordsize DATA/libvirt
NAME PROPERTY VALUE SOURCE
DATA/libvirt recordsize 128K default
root@edoras:~#

Sobre el cluster_size de los ficheros qcow2

Los ficheros qcow2 representan los discos duros de las máquinas virtuales cuando se utiliza qemu/kvm. Se pueden utilizar otros formatos de imagen u otros medios, como dispositivos de bloques, pero resulta muy cómodo utilizar ficheros en formato qcow2 y disponer de snapshots.

En este formato de archivo cluster_size determina el tamaño de los segmentos que contienen los datos almacenados por la MV.

En el momento de crear el archivo qcow2 se puede especificar el tamaño de cluster a utilizar. Su valor por defecto son 64K.

Por ejemplo, se puede consultar el tamaño de cluster de un archivo qcow2 de la siguiente manera:

root@edoras:/var/lib/libvirt/images# qemu-img info plone-4319.qcow2 
image: plone-4319.qcow2
file format: qcow2
virtual size: 250G (268435456000 bytes)
disk size: 100G
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
root@edoras:/var/lib/libvirt/images#

Pruebas de rendimiento con los valores por defecto

Al utilizar fio para lanzar un test de escrituras aleatorias se obtiene el siguiente resultado:

root@plone-4319:~# time fio --name=randwrite --rw=randwrite --direct=1 --ioengine=libaio --bs=64k --numjobs=8 --size=2G --runtime=600 --group_reporting
randwrite: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=1
...
fio-3.1
Starting 8 processes
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
Jobs: 2 (f=2): [w(1),_(6),w(1)][100.0%][r=0KiB/s,w=142MiB/s][r=0,w=2270 IOPS][eta 00m:00s]
randwrite: (groupid=0, jobs=8): err= 0: pid=12922: Tue Apr 14 14:19:41 2020
  write: IOPS=2110, BW=132MiB/s (138MB/s)(16.0GiB/124222msec)
    slat (usec): min=9, max=144468, avg=84.48, stdev=670.63
    clat (nsec): min=1689, max=148067k, avg=3662940.78, stdev=9201394.47
     lat (usec): min=48, max=159069, avg=3752.17, stdev=9243.95
    clat percentiles (usec):
     |  1.00th=[     4],  5.00th=[   135], 10.00th=[   204], 20.00th=[   326],
     | 30.00th=[   457], 40.00th=[   619], 50.00th=[   832], 60.00th=[  1172],
     | 70.00th=[  2008], 80.00th=[  5800], 90.00th=[  9241], 95.00th=[ 12518],
     | 99.00th=[ 49021], 99.50th=[ 71828], 99.90th=[112722], 99.95th=[124257],
     | 99.99th=[135267]
   bw (  KiB/s): min= 8832, max=35301, per=12.59%, avg=16998.26, stdev=3020.92, samples=1971
   iops        : min=  138, max=  551, avg=265.17, stdev=47.20, samples=1971
  lat (usec)   : 2=0.10%, 4=0.94%, 10=0.84%, 20=0.01%, 50=0.10%
  lat (usec)   : 100=1.19%, 250=10.59%, 500=19.17%, 750=13.65%, 1000=9.03%
  lat (msec)   : 2=14.38%, 4=6.17%, 10=15.28%, 20=6.38%, 50=1.18%
  lat (msec)   : 100=0.78%, 250=0.19%
  cpu          : usr=0.50%, sys=1.34%, ctx=322779, majf=0, minf=70
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.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.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwt: total=0,262144,0, short=0,0,0, dropped=0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=132MiB/s (138MB/s), 132MiB/s-132MiB/s (138MB/s-138MB/s), io=16.0GiB (17.2GB), run=124222-124222msec

Disk stats (read/write):
  vda: ios=0/262402, merge=0/13567, ticks=0/895400, in_queue=749592, util=93.67%

real	2m4,688s
user	0m5,711s
sys	0m14,234s
root@plone-4319:~# 

Pruebas de rendimiento con los valores ajustados a 64K

Se puede ajustar la propiedad recordsize a 64K de la siguiente manera:

root@edoras:/var/lib/libvirt/images# zfs set recordsize=64k DATA/libvirt
root@edoras:/var/lib/libvirt/images# zfs get recordsize DATA/libvirt
NAME          PROPERTY    VALUE    SOURCE
DATA/libvirt  recordsize  64K      local
root@edoras:/var/lib/libvirt/images#

Una vez ajustado podemos repetir los test de escrituras aleatorias:

root@plone-4319:~# time fio --name=randwrite --rw=randwrite --direct=1 --ioengine=libaio --bs=64k --numjobs=8 --size=2G --runtime=600 --group_reporting
randwrite: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=1
...
fio-3.1
Starting 8 processes
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
randwrite: Laying out IO file (1 file / 2048MiB)
Jobs: 1 (f=1): [_(7),w(1)][100.0%][r=0KiB/s,w=51.8MiB/s][r=0,w=828 IOPS][eta 00m:00s]
randwrite: (groupid=0, jobs=8): err= 0: pid=1117: Tue Apr 14 14:39:39 2020
  write: IOPS=3121, BW=195MiB/s (205MB/s)(16.0GiB/83991msec)
    slat (usec): min=8, max=75587, avg=43.11, stdev=353.30
    clat (nsec): min=1611, max=4624.5M, avg=1824728.52, stdev=32285893.05
     lat (usec): min=53, max=4624.6k, avg=1869.87, stdev=32289.47
    clat percentiles (usec):
     |  1.00th=[     60],  5.00th=[     98], 10.00th=[    135],
     | 20.00th=[    208], 30.00th=[    318], 40.00th=[    465],
     | 50.00th=[    635], 60.00th=[    848], 70.00th=[   1139],
     | 80.00th=[   1696], 90.00th=[   3130], 95.00th=[   5080],
     | 99.00th=[  13042], 99.50th=[  20055], 99.90th=[  53216],
     | 99.95th=[ 104334], 99.99th=[1333789]
   bw (  KiB/s): min=  128, max=304993, per=19.71%, avg=39373.40, stdev=42054.47, samples=845
   iops        : min=    2, max= 4765, avg=614.85, stdev=657.13, samples=845
  lat (usec)   : 2=0.40%, 4=0.10%, 10=0.03%, 20=0.04%, 50=0.24%
  lat (usec)   : 100=4.52%, 250=19.20%, 500=17.72%, 750=13.59%, 1000=9.95%
  lat (msec)   : 2=17.39%, 4=9.73%, 10=5.46%, 20=1.14%, 50=0.39%
  lat (msec)   : 100=0.06%, 250=0.03%, 500=0.01%, 750=0.01%, 2000=0.01%
  lat (msec)   : >=2000=0.01%
  cpu          : usr=0.72%, sys=2.14%, ctx=298792, majf=0, minf=89
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.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.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwt: total=0,262144,0, short=0,0,0, dropped=0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=195MiB/s (205MB/s), 195MiB/s-195MiB/s (205MB/s-205MB/s), io=16.0GiB (17.2GB), run=83991-83991msec

Disk stats (read/write):
  vda: ios=14/262259, merge=0/6581, ticks=4/507536, in_queue=340264, util=83.44%

real	1m24,419s
user	0m3,987s
sys	0m11,241s
root@plone-4319:~# 

Más información: