Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

ZFS y errores (II): Replicación de metadatos

Última Actualización: 13 de julio de 2007 - Viernes

En el documento ZFS y errores explico que ZFS mantiene cierto nivel de replicación de la información más crítica del "zpool", con el fin de mantener su integridad aunque ocurran errores en un "zpool" sin redundancia, o si la redundancia es insuficiente para corregir todos los errores que han aparecido.

En concreto, la versión actual de ZFS almacena dos copias de los metadatos de cada "dataset", y tres copias de los metadatos globales a todo el "zpool". Versiones inminentes de ZFS permitirán grabar hasta tres copias de todos los metadatos, así como de los propios datos del usuario (configurable por "dataset"). Además, se intentan almacenar dichas copias en discos duros distintos del "zpool" y, si no es posible, en un mismo disco duro pero "alejadas" unas de otras.

Por tanto, aún con corrupción de datos, fallos de discos duros, etc., es posible navegar por los directorios y ver las características de los ficheros (nombre, tamaño, fechas, permisos, etc), aunque los datos en sí de los ficheros se hayan destruidos. Al mantenerse la integridad del "zpool", podemos borrar esos ficheros dañados y recuperarlos de una copia de seguridad previa, sabiendo que la estructura lógica del almacenamiento sigue siendo consistente. Explico cómo identificar los ficheros dañados en el documento anterior.

En este documento vamos a ver un ejemplo de esta capacidad de supervivencia.

El primer paso consiste en crear dos ficheros de un gigabyte, que utilizaremos como unidades de almacenamiento. A continuación creamos un "zpool" nuevo, con dichas unidades:

[root@tesalia z]# mkfile 1G file1
[root@tesalia z]# mkfile 1G file2
[root@tesalia z]# ls -la
total 2097164
drwxr-xr-x 2 root root        241 2007-07-13 19:57 .
drwxrwxrwt 8 root sys        7368 2007-07-13 19:57 ..
-rw------T 1 root root 1073741824 2007-07-13 19:57 file1
-rw------T 1 root root 1073741824 2007-07-13 19:57 file2
[root@tesalia z]# zpool create prueba /tmp/z/file1 /tmp/z/file2
[root@tesalia z]# zpool list
NAME                    SIZE    USED   AVAIL    CAP  HEALTH     ALTROOT
[...]
prueba                 1.98G     80K   1.98G     0%  ONLINE     -
[root@tesalia z]#

Aquí podemos comprobar que se ha creado un "zpool" llamado "prueba", de dos gigabytes de capacidad. Como hemos creado el "zpool" a partir de dos ficheros de un gigabyte cada uno, es evidente que no estamos utilizando ningún sistema de redundancia como replicación, RAIDZ o similar.

Copiemos ahora algo "gordo", para ocupar sitio:

[root@tesalia z]# cp -a /usr/local /prueba
[...]
cp: cannot create directory `/prueba/local/BerkeleyDB.4.4': No space left on device
cp: preserving permissions for `/prueba/local': No space left on device
[root@tesalia z]# zpool list
NAME                    SIZE    USED   AVAIL    CAP  HEALTH     ALTROOT
[...]
prueba                 1.98G   1.95G   31.9M    98%  ONLINE     -

La copia no se completa porque mi directorio "/usr/local/" mide más de 2 gigabytes. Vemos que todavía quedan unos 32 megabytes libres, pero ese espacio está reservado por ZFS para poder hacer cosas como borrar un fichero, o cambiarle su nombre, ya que se trata de un sistema de ficheros "COW" ("Copy On Write").

ZFS es muy agresivo cacheando información en memoria, así que el primer paso será exportar y reimportar de nuevo el "zpool" para asegurarnos de que la caché está vacía, y que todos los datos que pidamos tendrán que ir a buscarse al disco duro. A continuación, antes de hacer nada más, vamos a corromper uno de los ficheros que se usan como almacenaje del "zpool":

[root@tesalia z]# zpool export prueba
[root@tesalia z]# zpool import -d /tmp/z/ prueba
[root@tesalia z]# ls -la
total 2097164
drwxr-xr-x 2 root root        241 2007-07-13 19:57 .
drwxrwxrwt 8 root sys        7744 2007-07-13 20:13 ..
-rw------T 1 root root 1073741824 2007-07-13 20:12 file1
-rw------T 1 root root 1073741824 2007-07-13 20:12 file2
[root@tesalia z]# dd if=/dev/zero of=file1 bs=1024 count=1048576 seek=0 conv=notrunc
1048576+0 records in
1048576+0 records out
1073741824 bytes (1.1 GB) copied, 36.707 s, 29.3 MB/s
[root@tesalia z]# ls -la
total 2097164
drwxr-xr-x 2 root root        241 2007-07-13 19:57 .
drwxrwxrwt 8 root sys        7750 2007-07-13 20:17 ..
-rw------T 1 root root 1073741824 2007-07-13 20:17 file1
-rw------T 1 root root 1073741824 2007-07-13 20:12 file2

Según esto, hemos corrompido la mitad de nuestro "zpool". Pero si vamos al "zpool" en cuestión y empezamos a movernos por él y a listar directorios, vemos que todo funciona con normalidad:

[root@tesalia z]# cd /prueba/local/
[root@tesalia local]# ls -la
total 28
drwxr-xr-x 15 root root     15 2007-06-21 12:10 .
drwxr-xr-x  3 root sys       3 2007-07-13 20:01 ..
drwxr-xr-x 13 root root     13 2007-05-08 18:26 apache
drwxr-xr-x  7 root root      7 2007-07-02 13:26 apache2
drwxr-xr-x  7 root root      7 2006-02-22 20:16 apr
drwxr-xr-x  3 root root      3 2006-02-06 23:23 doc
drwxr-xr-x 25 root root     80 2007-06-30 16:29 include
drwxr-xr-x  2 root root    135 2007-06-28 21:14 info
drwxrwsr-x 13 root mailman  13 2006-02-24 18:35 mailman
drwxr-xr-x 27 root root     28 2007-05-29 21:15 man
drwxr-xr-x  2 root root      3 2006-10-13 15:49 php
drwxr-xr-x 27 root root     27 2007-06-04 15:40 share
drwxr-xr-x  9 root root     10 2007-03-26 19:01 ssl
drwxr-xr-x  2 root root     13 2007-04-23 12:57 svc
drwxr-xr-x  3 root root      3 2007-07-06 19:59 var
[root@tesalia local]# cd ssl/lib
[root@tesalia lib]# ls -la
total 1555
drwxr-xr-x 3 root root      11 2007-06-12 23:20 .
drwxr-xr-x 9 root root      10 2007-03-26 19:01 ..
-r--r--r-- 1 root root    5287 2006-01-30 19:14 fips_premain.c
-r--r--r-- 1 root root      68 2007-01-16 15:06 fips_premain.c.sha1
lrwxrwxrwx 1 root root      14 2007-07-13 20:02 libcrypto.so -> libcrypto.so.0
lrwxrwxrwx 1 root root      18 2007-07-13 20:02 libcrypto.so.0 -> libcrypto.so.0.9.7
-r-xr-xr-x 1 root root 1282624 2007-03-26 19:01 libcrypto.so.0.9.7
lrwxrwxrwx 1 root root      11 2007-07-13 20:02 libssl.so -> libssl.so.0
lrwxrwxrwx 1 root root      15 2007-07-13 20:02 libssl.so.0 -> libssl.so.0.9.7
-r-xr-xr-x 1 root root  236060 2007-03-26 19:01 libssl.so.0.9.7
drwxr-xr-x 2 root root       3 2006-10-03 01:13 pkgconfig

Todo parece funcionar correctamente, pero veamos qué nos dice ZFS:

[root@tesalia share]# zpool status prueba
  pool: prueba
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://www.sun.com/msg/ZFS-8000-9P
 scrub: none requested
config:

        NAME             STATE     READ WRITE CKSUM
        prueba           ONLINE       0     0     4
          /tmp/z//file1  ONLINE       0     0     4
          /tmp/z//file2  ONLINE       0     0     0
errors: No known data errors
Aquí podemos ver como se están detectando errores en el almacenamiento que hemos corrompido, pero los datos de directorio se obtienen de la otra copia. El efecto neto es que a medida que nos movemos por los directorios, se van encontrando errores y se corrigen automáticamente aprovechando la otra réplica, todo de forma transparente y automática.

El detalle importante es el "No known data errors" al final del comando, que nos indica que ZFS está soportando bastante bien el maltrado. Recordemos que estamos corrompiendo un "zpool" al que no hemos especificado ningún tipo de redundancia tipo "mirror" o "RAIDZ".

Veamos qué ocurre ahora si intentamos leer un fichero:

[root@tesalia man1]# pwd
/prueba/local/share/man/man1
[root@tesalia man1]# md5sum * 2>&1|head
28740479fdd82fcb9d99b756e4fa3d5c  a2p.1
506e2e0f5f0297f29e11127c08a06366  autoconf.1
b68a482641c513f34124a6f0c0c6bf8c  autoheader.1
f118e9c0e995d672ba6ab7c6c1cbba9d  autom4te.1
md5sum: autoreconf.1: I/O error
36da8eb47268b03b448524e3f65fb2c2  autoscan.1
md5sum: autoupdate.1: I/O error
md5sum: base64.1: I/O error
52f444040eb2060fdcc89a01f68d3634  basename.1
md5sum: bison.1: I/O error

Como vemos, algunos ficheros se leen correctamente y otros no, dependiendo de si se han grabado en un disco duro u otro. ZFS trocea los ficheros en bloques de 128Kbytes, por defecto, y los graba en un disco duro u otro en función del espacio libre que tenga cada disco, o su nivel de actividad, con una eurística bastante sofisticada. En ficheros grandes (varios megas), es muy normal que los diferentes bloques de 128Kbytes acaben en discos distintos, pero ficheros tan cortitos como los manuales "man", que miden menos de 128Kbytes y, por tanto, solo ocupan un bloque, se graban por completo en un disco duro u otro.

Veamos ahora qué nos dice ZFS:

[root@tesalia man1]# zpool status prueba
  pool: prueba
 state: ONLINE
status: One or more devices has experienced an error resulting in data
        corruption.  Applications may be affected.
action: Restore the file in question if possible.  Otherwise restore the
        entire pool from backup.
   see: http://www.sun.com/msg/ZFS-8000-8A
 scrub: none requested
config:

        NAME             STATE     READ WRITE CKSUM
        prueba           ONLINE       0     0 1.23K
          /tmp/z//file1  ONLINE       0     0 1.23K
          /tmp/z//file2  ONLINE       0     0     0

errors: 166 data errors, use '-v' for a list

Ahora ZFS ya no puede ocultar los errores, ya que el "zpool" no contiene redundancia a nivel de datos de usuario. Podemos salvar los ficheros contenidos completamente en el componente que no hemos corrompido, pero los ficheros grandes, al estar repartidos entre los dos, requerirán recuperar el backup.

Lo que es importante ver, es que en todo momento ZFS ha mantenido la integridad de todas sus estructuras críticas, como los directorios, los nombres de los ficheros e información interna muy delicada, como la lista de sectores libres, la descripción de los "datasets" contenidos en el "zpool", etc. Aquellos de nosotros que hemos perdido grandes segmentos de un árbol de directorios por un único sector dañado en un mal sitio, agradecemos el esfuerzo que ZFS despliega para protegernos al máximo.

Es de señalar, aunque resulte evidente, que estos niveles de redundancia a nivel de metadatos son independientes de la redundancia implícita configurada en el "zpool". Es decir, si nuestro "zpool" está formado por dos discos en espejo, habrá realmente 4 y 6 copias de los metadatos, en vez de 2 y 3.

Otro detalle interesante es que la versión actual de ZFS no protege los metadatos correspondientes a los enlaces simbólicos de más de 56 bytes. Ver bug 6516171 en OpenSolaris.

Historia

  • 13/jul/07: Primera versión de esta página.



Python Zope ©2007 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS