Backups de MVs KVM con Kopia

per Victor Carceler darrera modificació 2023-03-09T09:09:28+01:00

En el centro educativo se utiliza libvirt/kvm para ejecutar las máquinas virtuales que proporcionan los servicios que utilizamos. Un componente clave de esta infraestructura es OpenZFS que proporciona grandes ventajas: integridad, tolerancia a fallos, rendimiento, snapshots, compresión...

Por ejemplo, osgiliath, utiliza el dataset DATA/libvirt que está montado en /var/lib/libvirt para guardar sus máquinas virtuales. Cuando se hace un backup:

  1. Se guardan las máquinas virtuales (es decir, se guarda en disco su estado y se detiene su ejecución). Unos 30 segundos.
  2. Se toma un nuevo snapshot de los discos, la definición (los ficheros .xml) y del estado de las máquinas (el fichero con la ram de la máquina guardada). Menos de 1 segundo.
  3. Se vuelven a restaurar las MVs. Unos 30 segundos.

Todo el proceso lleva más o menos 1 minuto y se realiza de madrugada para que los usuarios no sufran ninguna afectación.

Los últimos 20 snapshots se guardan en el servidor y los más antiguos se borran para liberar espacio. Además se utiliza zfs send y zfs receive para replicar de manera eficiente estos snapshots en otra máquina local.

En estos momentos los snapshots son:

vcarceler@osgiliath:~$ zfs list -t all
NAME                               USED  AVAIL     REFER  MOUNTPOINT
DATA                              2.09T  8.35T      140K  none
DATA/backup                       4.64G  8.35T     4.64G  /opt/backup
DATA/libvirt                      2.09T  8.35T     1.29T  /var/lib/libvirt
DATA/libvirt@inicial              10.5G      -     1.33T  -
DATA/libvirt@2022-11-12_05:00:01  19.6G      -     1.34T  -
DATA/libvirt@2022-11-19_05:00:01  21.8G      -     1.33T  -
DATA/libvirt@2022-11-26_05:00:01  26.2G      -     1.34T  -
DATA/libvirt@2022-12-03_05:00:01  27.3G      -     1.35T  -
DATA/libvirt@2022-12-10_05:00:01  29.0G      -     1.35T  -
DATA/libvirt@2022-12-17_05:00:01  32.3G      -     1.36T  -
DATA/libvirt@2022-12-24_05:00:01  26.5G      -     1.35T  -
DATA/libvirt@2022-12-31_05:00:01  27.2G      -     1.36T  -
DATA/libvirt@2023-01-07_05:00:01  29.4G      -     1.36T  -
DATA/libvirt@2023-01-14_05:00:01  38.3G      -     1.29T  -
DATA/libvirt@2023-01-21_05:00:01  36.4G      -     1.29T  -
DATA/libvirt@2023-01-28_05:00:01  31.5G      -     1.30T  -
DATA/libvirt@2023-02-04_05:00:01  31.4G      -     1.30T  -
DATA/libvirt@2023-02-11_05:00:01  31.7G      -     1.30T  -
DATA/libvirt@2023-02-18_05:00:01  30.8G      -     1.31T  -
DATA/libvirt@2023-02-25_05:00:01  31.1G      -     1.30T  -
DATA/libvirt@2023-03-04_05:00:01  30.8G      -     1.31T  -
vcarceler@osgiliath:~$

Se puede comprobar el tamaño de los discos de las MVs (unos 2.5TiB)

root@osgiliath:/var/lib/libvirt/.zfs/snapshot/2023-03-04_05:00:01/images# ll -lh 
total 1,3T
drwx--x--x 2 root         root   10 nov 10 08:40 ./
drwxr-xr-x 7 root         root    7 mar  3 10:55 ../
-rw------- 1 libvirt-qemu kvm   51G mar  4 04:59 baba-yaga-2004-v2.qcow2
-rw------- 1 libvirt-qemu kvm   25G nov 23 12:34 cirdan-1604.img
-rw------- 1 libvirt-qemu kvm   51G mar  4 05:00 cirdan-2204.qcow2
-rw------- 1 libvirt-qemu kvm   50G mar  4 05:00 elastix-2.5.img
-rw------- 1 libvirt-qemu kvm  251G mar  4 05:00 matrioska-2004.qcow2
-rw------- 1 libvirt-qemu kvm  2,0T mar  4 05:00 owncloud.img
-rw------- 1 libvirt-qemu kvm   51G mar  4 05:00 unifi-2004.qcow2
-rw------- 1 libvirt-qemu kvm   25G mar  4 04:58 valinor.img
root@osgiliath:/var/lib/libvirt/.zfs/snapshot/2023-03-04_05:00:01/images#

Que, gracias a que son ficheros dispersos y a que está activa la compresión transparente con lz4, ocupan menos:

root@osgiliath:/var/lib/libvirt/.zfs/snapshot/2023-03-04_05:00:01/images# du -hs *
20G	baba-yaga-2004-v2.qcow2
3,6G	cirdan-1604.img
6,8G	cirdan-2204.qcow2
1,1G	elastix-2.5.img
107G	matrioska-2004.qcow2
1,2T	owncloud.img
13G	unifi-2004.qcow2
5,6G	valinor.img
root@osgiliath:/var/lib/libvirt/.zfs/snapshot/2023-03-04_05:00:01/images#

Es decir unos 1.4TiB de almacenamiento pero los snapshots consumen unos 30GiB porque las MVs tampoco cambian tanto durante su funcionamiento.

Pruebas de rendimiento local

Cuando se utiliza zfs send y zfs receive para transmitir un snapshot a otra máquina se está aprovechando la capacidad de OpenZFS para transmitir por la red los datos de manera incremental. Es decir, que aunque el conjunto de datos sea aproximadamente de 1.4TiB únicamente se transmite por la red los 30GiB que diferencian a los snapshots. Y además no es necesario dedicar tiempo a buscar en qué se diferencian los ficheros.

Pero cuando se utiliza una herramienta como kopia para añadir los datos de un nuevo snapshot a la copia de seguridad será necesario deduplicar los archivos buscando los fragmentos con cambios. Y siendo los discos de las MVs archivos grandes esto puede llevar un tiempo considerable.

También vale la pena valorar les espacio ahorrado gracias a la deduplicación y opcionalmente gracias a la compresión.

Las pruebas se realizarán con la imagen de baba-yaga-2004-v2.qcow2, un fichero de 51GiB, registrada en los últimos 3 snapshots.

Tiempo necesario para hacer el backup y beneficios de la deduplicación

Con kopia v0.12.1 utilizando como repo un directorio local sobre EXT4 se obtienen los siguientes tiempos al añadir los tres snapshots de la MV.

Paso Tiempo necesario Tamaño del repo
Creación del repositorio. 0 s 64KiB
kopia snapshot datos/snapshot-1 26.9 s 40 GiB
kopia snapshot datos/snapshot-2 19.2 s 56 GiB
kopia snapshot datos/snapshot-3 19.6 s 75 GiB

Los tiempos de ejecución son sorprendentemente bajos, sobre todo teniendo en cuenta que una simple copia con cp del fichero baba-yaga-2004-v2.qcow2puede tardar 70 segundos. Utilizando cp --sparse=always se gana algo de tiempo y se obtiene un fichero más pequeño.

Y los beneficios de la deduplicación son claros. Al añadir el primer snapshot el repositorio crece hasta los 40GiB (la máquina virtual tiene unos 10GiB de zeros) y al añadir los nuevos snapshots el repositorio solo crece con las diferencias (16GiB y 19GiB).

Finalmente añadir un nuevo snapshot con el directorio datos (que contiene los tres snapshots) no aumenta el taño del repositorio pero consume 37 segundos en procesar los 151 GiB (161.1 GB para kopia) de datos.

vcarceler@zvezda:~$ kopia snapshot datos/
Snapshotting vcarceler@zvezda:/home/vcarceler/datos ...
 * 0 hashing, 3 hashed (161.1 GB), 0 cached (0 B), uploaded 205 B, estimated 161.1 GB (100.0%) 0s left
Created snapshot with root k79d20070fe7772a47951ca7d32274fd5 and ID fe207bb0c9627745c75433c8cb830f3d in 37s
vcarceler@zvezda:~$

Si se añaden nuevos ficheros al directorio datos y se hace un snapshot no se vuelven a procesar los ficheros que ya estaban guardados en el repo. De tal manera que en nuestro caso cada vez que tengamos un nuevo snapshot de OpenZFS únicamente se tendrán que procesar los 2.5TiB nuevos.

Aún así 2.5TiB es un volumen de información considerable y a la velocidad (4.081GiB/s) demostrada en el test tardaría 10.5 minutos en procesarse.

Compresión con zstd

El comando kopia benchmark compression --data-file datos/snapshot-1/baba-yaga-2004-v2.qcow2 nos permite poner a prueba los diferentes algoritmos de compresión soportados por kopia con nuestro fichero de datos.

Naturalmente los resultados dependerán de los datos con los que se trabaje, en nuestro caso obtenemos:

     Compression                Compressed   Throughput   Allocs   Usage
------------------------------------------------------------------------------------------------
  0. s2-parallel-4              6.3 MiB      5.7 GiB/s    999      32.1 MiB
  1. s2-parallel-8              6.3 MiB      5.1 GiB/s    1040     38.2 MiB
  2. s2-default                 6.3 MiB      5 GiB/s      1052     51.3 MiB
  3. s2-better                  6 MiB        4.2 GiB/s    1062     62.2 MiB
  4. pgzip-best-speed           6.1 MiB      3.9 GiB/s    1413     79.8 MiB
  5. pgzip                      5.1 MiB      2.4 GiB/s    1466     85.1 MiB
  6. zstd-fastest               4.4 MiB      1.5 GiB/s    6323     22.5 MiB
  7. zstd                       4.1 MiB      1.3 GiB/s    3338     31 MiB
  8. deflate-best-speed         6.1 MiB      1.2 GiB/s    36       20.2 MiB
  9. deflate-default            5.1 MiB      850.3 MiB/s  35       20.4 MiB
 10. gzip-best-speed            5.5 MiB      734 MiB/s    41       20.2 MiB
 11. zstd-better-compression    3.9 MiB      667 MiB/s    3229     49.1 MiB
 12. gzip                       4.9 MiB      213.5 MiB/s  38       12.3 MiB
 13. pgzip-best-compression     4.9 MiB      120.2 MiB/s  1913     124.1 MiB
 14. deflate-best-compression   4.9 MiB      25 MiB/s     35       14.8 MiB
 15. gzip-best-compression      4.9 MiB      16.9 MiB/s   38       12.3 MiB

El mejor ratio de compresión lo proporciona zstd-better-compression que con 667 MiB/s es más que suficiente para el propósito que perseguimos: tener el backup en la nube.

Al repetir los pasos de la tabla anterior con un repositorio configurado para utilizar zstd-better-compression obtenemos los siguientes resultados:

Paso Tiempo necesario Tamaño del repo
Creación del repositorio. 0 s 92KiB
kopia snapshot datos/snapshot-1 81 s 9.8 GiB
kopia snapshot datos/snapshot-2 38 s 14 GiB
kopia snapshot datos/snapshot-3 41 s 18 GiB

Recuperar un fichero

Cuando utilizamos kopia mount para montar un snapshot y recuperar un fichero nos encontramos que utilizar la compresión zstd-better-compressiontiene su lado negativo: dos núcleos ocupados por kopia mount y 5 minutos 53 segundos para que cp copie baba-yaga-2004-v2.qcow2 a un directorio.

Cuando no se utiliza compresión, copiar el fichero anterior desde el backup lleva y se aprecia una menor utilización de CPU pero el tiempo necesario para restaurar el fichero es similar: 5 minutos 42 segundos.

Así que la compresión no parece penalizar el proceso de restauración.

Pruebas de rendimiento con Google Drive

En nuestro caso el objetivo final que pretendemos alcanzar con kopia es guardar los backups de nuestras MVs en Google Drive. La herramienta permite utilizar Google Drive como almacenamiento de dos maneras diferentes:

  • Soporte nativo.
  • Utilizando rclone como herramienta externa.

Las dos opciones son excluyentes porque utilizan diferente formato de repositorio. En nuestro caso hemos optado por el soporte nativo para no depender de otra herramienta, pero utilizar rclone tiene la ventaja de que abre la puerta a utilizar cualquier de los protocolos soportados.

En cualquier caso es necesario:

  • Crear una cuenta de Google Drive
  • Activar la API de Google Drive
  • Definir una cuenta de servicio

Todo el proceso está documentado en: https://kopia.io/docs/repositories/#google-drive

Añadir snapshots

Una vez creado el respositorio en Google Drive y activada la compresión con zstd-better-compression, se pueden añadir datos al repositorio de la manera habitual.

El tiempo necesario para añadir nuestros ficheros de prueba ha sido:

Paso Tiempo necesario Uploaded
kopia snapshot datos/snapshot-1 8 m 38 s 10.4 GB
kopia snapshot datos/snapshot-2 4 m 42 s 4.1 GB
kopia snapshot datos/snapshot-3

Al restaurar datos desde el repositorio no se ha obtenido un buen rendimiento. Montar un snapshot y copiar el fichero baba-yaga-2004-v2.qcow2 a un directorio ha llevado 377 minutos.

Más información: