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

ZFS y errores

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

Esta mañana hemos perdido uno de los discos duros que uso de "mirror" para mi "pool". En principio el asunto no tiene mayor complicación: dado que el "pool" ZFS es redundante, basta con reemplazar el disco duro defectuoso y añadir el disco duro nuevo al "pool" como un nuevo componente del "mirror". Una vez tecleados los comandos, solo hay que esperar a que la replicación termine. Simple e indoloro.

Pero la pesadilla de cualquier "resilvering" es que ocurra un error en el disco que queda. Al no haber completado aún la replicación, no cuenta con redundancia y habremos perdido datos.

En otros sistemas, un error durante la replicación puede detenerla de forma catastrófica (siendo incapaz de reconstruir el "mirror" y dejándonos sin redundancia) o bien el sector defectuoso se copia con un valor arbitrario (todo a ceros, por ejemplo). Una vez completada la replicación, empieza la tarea de revisar el log de sectores erroneos e intentar asociarlos a su fichero correspondiente, para poder recuperarlos del backup (haces backups con frecuencia, ¿verdad?). Este caso es grave, pero si el sector dañado estaba libre, habremos perdido el tiempo y nos habrá subido la tensión sanguínea a límites estratosféricos, para nada.

En ZFS la replicación sigue el árbol de objetos, de forma que solo se copian los sectores con datos, no el espacio vacío. En este sentido hacer un "resilvering" supone un tiempo proporcional a los datos que contiene el disco duro, no al tamaño del mismo. Una ventaja adicional es que si los sectores erroneos no están en uso, nos ahorramos el susto. Como contrapartida, si el disco está muy lleno, la replicación será más lenta que en el caso tradicional, porque el copiado se realiza siguiendo un árbol (y moviendo el cabezal del disco duro) en vez de copiar grupos de bloques enteros consecutivos. Ésta es un área de estudio actual de los ingenieros ZFS de Sun.

¿Qué ocurre si los sectores dañados sí están en el árbol?. Entonces sí veremos errores reales. Hay tres casos:

  1. El error está en los datos: Es el caso más habitual, dado que la mayor parte de la información almacenada en el disco duro son datos del usuario. En este caso ZFS no puede hacer milagros, porque no dispone de redundancia, y nos indicará que existen errores que no ha podido corregir. Pero a diferencia de las herramientas de "mirror" tradicionales, ZFS sí sabe qué ficheros se ven afectados, y nos proporciona sus datos con el comando "zpool status -v". Con los ficheros identificados de forma tan simple, solo queda borrarlos (porque están corruptos) y recuperarlos del backup, si es necesario y apropiado en este caso concreto.

  2. El error está en los metadatos de un sistema de ficheros del "pool" ZFS: Ya hemos dicho que ZFS hace la copia siguiendo el árbol de objetos. La estructura de dicho árbol viene determinada por los metadatos, que contienen también información sobre los directorios, punteros a los datos, etc. Si un error nos impide explorar un sub-árbol perderíamos mucha información que está correcta pero inaccesible.

    Para evitar este problema, ZFS guarda dos copias de todos los metadatos, si es posible en discos distintos y, si no puede ser, en lugares "distantes" del disco. Esta replicación "interna" es independiente de la replicación del "pool" en sí. Es decir, si usamos un disco duro, se guardarán dos copias de los metadatos, en lugares lejanos. Si usamos dos discos duros pero sin redundancia (tipo RAID 0), se guardarán dos copias también, cada una en un disco duro distinto. Si empleamos dos discos duros, pero en espejo (RAID 1), se guardarán cuatro copias, dos en cada disco duro.

    En ese sentido, si el disco tiene sectores dañados pero una de las copias de metadatos es legible (por eso se graban separadas), podremos seguir recorriendo el árbol. Es más, podemos usar la copia para reconstruir el sector dañado y recuperar la redundancia duplicada.

    Normalmente el porcentaje de disco utilizado por los metadatos es muy pequeño comparado con los datos en sí, por lo que esta redundancia apenas supone coste alguno.

  3. El error está en los metadatos del propio "pool": El propio "pool" ZFS contiene información adicional crítica, como el espacio libre el disco, e información sobre los sistemas de ficheros que contiene. Un error aquí es hipercrítico, ya que puede hacer que el "pool" entero quede inaccesible. Por ello, estos datos se almacenan por triplicado, siguiendo los mismos principios que en el caso anterior: intentar utilizar discos diferentes y, si no es posible, desperdigarlos en un mismo disco duro, para reducir el riesgo de que un error de disco localizado afecte a todas las copias.

    Nuevamente, esta replicación es independiente de la propia replicación que estemos usando en el "pool" ZFS.

Ejemplo práctico

Como ya he dicho, esta mañana me ha fallado un disco duro "mirror" de uno de mis "pools" ZFS. Pero lo que ha motivado que escribiese esta página web es que durante la reconstrucción el único disco que me quedaba ha dado errores:

[root@tesalia z]# zpool status
  pool: datos
 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: resilver completed with 2 errors on Thu Jun 14 18:55:46 2007
config:

        NAME        STATE     READ WRITE CKSUM
        datos       ONLINE       0     0     4
          mirror    ONLINE       0     0     4
            c1d0s4  ONLINE       0     0     8
            c2d0s4  ONLINE       0     0     8

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

Pidiéndole información adicional sobre los ficheros afectados, tal y como nos sugiere el propio comando, me muestra:

errors: The following persistent errors have been detected:

          DATASET  OBJECT  RANGE
          ae       4093d   lvl=0 blkid=0
          ae       586db   lvl=0 blkid=0

Estoy usando Solaris 10 Update 3, que muestra información "interna" sobre los ficheros afectados, poco útil. La próxima actualización de Solaris debería mostrar directamente el "path" de los ficheros.

Como todavía no disponemos de esa ayuda, es necesario realizar la búsqueda "a mano". Lo primero es localizar el sistema de ficheros problemático. En este caso los dos ficheros pertenecen al mismo "dataset" o sistema de ficheros: "ae". Ese valor está en hexadecimal y debemos pasarlo a decimal. En este caso, el valor decimal es 174. Para sacar el nombre del "dataset" o sistema de ficheros, hacemos "zdb datos | grep 'ID 174, '". "datos" es el nombre de mi "pool" ZFS. Obtenemos:

Dataset datos/libros [ZPL], ID 174, cr_txg 1462257, last_txg 2415696, 6.99G, 803781 objects

Lo siguiente es identificar los ficheros en cuestión:

[root@tesalia z]# zdb -vvv datos/libros 0x4093d
Dataset datos/libros [ZPL], ID 174, cr_txg 1462257, last_txg 2415696, 6.99G, 803781 objects, rootbp [L0 DMU objset] 400L/200P DVA[0]=<0:58216de00:200> DVA[1]=<0:130068c600:200> DVA[2]=<0:1e08435e00:200> fletcher4 lzjb LE contiguous birth=2415696 fill=803781 cksum=b3c41a191:49df133ff66:f7aa04881e36:2347e58bfa8237

    Object  lvl   iblk   dblk  lsize  asize  type
    264509    1    16K  7.50K  7.50K  3.50K  ZFS plain file
                                 264  bonus  ZFS znode
        path    /media-nf.librosgratisweb.com/html/geier-chester/la-ciudad-oculta/pg_0089.htm
        atime   Fri Jun  1 19:16:26 2007
        mtime   Sat Apr 28 15:11:44 2007
        ctime   Thu May 31 20:49:02 2007
        crtime  Thu May 31 20:49:02 2007
        gen     2303049
        mode    100644
        size    7435
        parent  74963
        links   1
        xattr   0
        rdev    0x0000000000000000

[root@tesalia z]# zdb -vvv datos/libros 0x586db
Dataset datos/libros [ZPL], ID 174, cr_txg 1462257, last_txg 2415696, 6.99G, 803781 objects, rootbp [L0 DMU objset] 400L/200P DVA[0]=<0:58216de00:200> DVA[1]=<0:130068c600:200> DVA[2]=<0:1e08435e00:200> fletcher4 lzjb LE contiguous birth=2415696 fill=803781 cksum=b3c41a191:49df133ff66:f7aa04881e36:2347e58bfa8237

    Object  lvl   iblk   dblk  lsize  asize  type
    362203    1    16K  10.0K  10.0K  5.00K  ZFS plain file
                                 264  bonus  ZFS znode
        path    /media-nf.librosgratisweb.com/html/efremov-ivan/olgoi-jorjoi/pg_0066.htm
        atime   Fri Jun  1 20:54:54 2007
        mtime   Sat Apr 28 06:12:24 2007
        ctime   Fri Jun  1 20:54:54 2007
        crtime  Fri Jun  1 20:54:54 2007
        gen     2319163
        mode    100644
        size    9854
        parent  76982
        links   1
        xattr   0
        rdev    0x0000000000000000

Dado que los identificadores de ficheros fallidos están en hexadecimal, debemos ponerles el "0x" delante.

Vemos que los dos ficheros que han fallado no tienen mayor importancia. De hecho de esa partición ni siquiera hago backups. Pero en una situación normal, borraríamos esos ficheros y los recuperaríamos del backup.

Comprobemos que efectivamente esos ficheros están mal:

[root@tesalia z]# cd /datos/libros/media-nf.librosgratisweb.com/html/efremov-ivan/olgoi-jorjoi/
[root@tesalia olgoi-jorjoi]# md5sum pg_0065.htm
f0577d9f836270d42cc8b84b43f16cea  pg_0065.htm    (¡bien!)
[root@tesalia olgoi-jorjoi]# md5sum pg_0067.htm
653b1b9089755ae3f07b48cadab6cf4e  pg_0067.htm    (¡bien!)
[root@tesalia olgoi-jorjoi]# md5sum pg_0066.htm
md5sum: pg_0066.htm: I/O error    (¡el fichero erroneo!)

Una vez completados todos los pasos, limpiemos los errores del "pool" ZFS con el comando "zpool clear datos". Este comando pone a cero los contadores de errores, pero mantiene la lista de ficheros corruptos (aunque ya los hemos borrado). Para hacer limpieza por completo y, además, asegurarnos de que todo está correcto, hacemos "zpool scrub datos". Este comando limpiará el log y leerá todos los datos de ambos discos duros (ya que ya hemos recuperado el "mirror") para asegurarse de que todo está correcto. Como se puede imaginar, este comando es bastante lento, ya que lee todos los datos de todos los discos duros del "pool" "datos".

En mi caso, tras casi dos horas, veo un maravilloso:

[root@tesalia /]# zpool status
  pool: datos
 state: ONLINE
 scrub: scrub completed with 0 errors on Thu Jun 14 21:57:50 2007
config:

        NAME        STATE     READ WRITE CKSUM
        datos       ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            c1d0s4  ONLINE       0     0     0
            c2d0s4  ONLINE       0     0     0

errors: No known data errors

Detalles a tener en cuenta

  • La búsqueda de los ficheros que han dado errores será innecesaria en el inminente Solaris 10 Update 4. A partir de esa versión tendremos los "path" de forma directa.

  • Una versión futura de Solaris (aún por determinar) permitirá seleccionar el nivel de redundancia de datos por sistema de ficheros, además de por "pool". Eso permitirá tener redundancia selectiva dentro de un mismo "pool", aunque tengamos un único disco duro. El valor máximo será TRES (tres copias). La réplica de metadatos del sistema de ficheros será una más que el nivel de replicación de datos para ese sistema de ficheros, hasta un máximo de tres. El nivel de replicación de metadatos del "pool" siempre será TRES.

    Por supuesto esta replicación se añadirá a la propia replicación del "pool".

  • Es un error muy común pensar que como tenemos dos discos duros en "mirror" ya estamos protegidos de problemas de discos. Eso es falso, como acabamos de ver. Los hechos son los siguientes:

    • Si un disco duro empieza a tener sectores defectuosos, sólo los ves cuando intentas leerlos. Por lo tanto, un disco duro puede tener muchos errores indetectados si hay datos que leemos infrecuentemente.

    • En consecuencia, puedes tener errores en los discos que el "mirror" no ha detectado simplemente porque no los has leído. Si intentas leerlos el sistema detectará el error y se recuperará leyendo del otro disco duro. Esto funcionará mientras dispongamos de los dos discos en espejo y no tengamos la mala suerte de que fallan en los mismos sectores.

    • Como resultado de todo esto, es relativamente fácil tener errores en una reconstrucción de un "mirror", precisamente en un momento donde no disponemos de redundancia para hacerles frente. ¡¡La política de backups es crucial!!.

    Todo lo dicho plantea las siguientes recomendaciones:

    • Si puedes permitirte tener un "mirror" de más de dos copias, tanto mejor.

    • En vez de romper un "mirror" para sustituir un disco duro, es preferible, si la máquina dispone de espacio suficiente o podemos utilizar un disco remoto (iSCSI, por ejemplo) o un USB2/Firewire local, crear un "mirror" a tres bandas. La idea es reducir el riesgo de encontrarnos con un error irrecuperable. Una vez que la replicación se ha completado (puede ser una tarea muy lenta), podemos quitar el disco duro antiguo y hacer que el nuevo disco replicado ocupe su lugar. Durante todo este proceso, siempre tendremos un "mirror" de, al menos, dos discos duros.

    • Si el disco duro que utilizamos para el tercer "mirror" no se puede dejar en producción en la máquina (por ejemplo, es un USB2 removible), entonces, una vez completado el "mirror" a tres bandas, retiramos el disco viejo (nos quedamos con solo dos copias), insertamos el disco nuevo y lo añadimos al "mirror". Cuando se complete la replicación, tendremos redundancia triple. En ese momento podemos retirar el disco "temporal", dejando un "mirror" normal de dos copias. Este procedimiento copia los datos dos veces, con el consiguiente tiempo de espera y pérdida de rendimiento.

    • Si te resulta imposible conectar tres discos duros a la vez, antes de extraer el disco duro a sustituir haz un "zpool scrub" para asegurarte de que ZFS revisa ambos discos por completo (las partes en uso) y corrige cualquier deficiencia antes de perder (temporalmente) la redundancia. Si es necesario, repite el proceso varias veces, hasta que estés razonablemente seguro de que cualquier error ha sido subsanado. Este proceso te asegura que solo vas a tener que enfrentarte a errores desarrollados durante el proceso de "scrubbing" y de regeneración del "mirror", no a un sector defectuoso aparecido en el disco duro hace tres meses y que no has detectado porque o bien el fichero en cuestión se usa muy poco o se usa tanto que permanece permanentemente en caché. ¡¡HAZ BACKUP Y PREPÁRATE PARA LO PEOR!!. Uno de mis dichos habituales es "nunca pasa nada... hasta que pasa...".

      En este caso concreto no había hecho el "zpool scrub", pero antes de reemplazar el disco duro hice un backup (y me aseguré de que estaba bien hecho y era utilizable). El disco falló en datos que no valoro lo bastante como para hacer copia de seguridad; me los puedo bajar de nuevo de Internet con un simple comando. Si no hubiera sido así, hubiera estado preparado con la copia de seguridad. Me resulta rentable porque el backup lo hago de todas formas y hacer un "scrubbing" antes del "resilvering" duplica el tiempo necesario y penaliza notablemente el rendimiento de la máquina.

    • Dado que podemos perder un disco en cualquier momento, y que hay datos a los que se accede con muy poca frecuencia (o con mucha, y permanecen en caché), es buena idea realizar un análisis de disco de forma habitual o cuando ZFS empieza a dar errores de disco (corregidos con el "mirror") de forma rutinaria. Por ejemplo, un "zpool scrub" semanal puede ser una política a tener en cuenta.

      Hay que valorar que el "scrubbing" es una tarea costosa en tiempo y recursos de máquina, así que la política relevante debe tener en cuenta estos hechos.

    • Por el mismo motivo, es preferible usar un RAID6 a un RAID5 (en el contexto ZFS, hablamos de RAIDZ y RAIDZ2).


Historia

  • 13/jul/07: Añado lo de RAIDZ2.

  • 14/jun/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