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

Solaris 10 y ZFS: Separación de un ZPOOL unificado en producción, en ZPOOLs de "sistema" y "datos"

Última Actualización: 10 de enero de 2012

Desde que Solaris 10 permite arrancar el sistema desde un "zpool", mis servidores tienen un "zpool" llamado "datos", que contiene TODO. Las ventajas fundamentales de tener un "zpool" unificado son:

  • Todo el disco está disponible para todos los "datasets". No nos encontraremos con que un "zpool" está lleno mientras otro tiene espacio. Esto es especialmente importante si utilizamos "Live Upgrade", opción que recomiendo encarecidamente.

  • Cuando hacemos un "snapshot" recursivo, todos los snapshots generados son simultaneos y sincronizados. En cambio si tenemos varios "zpools", los snapshots de "zpools" diferentes no estarán sincronizados. Esto puede ser importante o no, según nuestra configuración y lo que tengamos montado encima.

  • Los procedimientos de backup y recuperación catastrófica de sistemas son diferentes. En realidad tener el sistema y los datos separados en "zpools" diferentes puede facilitar la tarea de recuperación, pero lo cierto es que ahora mismo supone modificar todos mis procedimientos.

La gran ventaja de tener el sistema separado en su propio "zpool" es que existen restricciones en la configuración de un "zpool" "root". Por ejemplo, no se permite utilizar RAIDZ/Z2/Z3, o un ZIL separado en su propio dispositivo SSD. O podemos hacer cosas como tener una versión "zpool" baja, compatible con un GRUB antiguo y con cosas como OpenSolaris u OpenIndiana, mientras que los datos en sí residen en otro "zpool" utilizando la última versión de ZFS.

En este artículo voy a describir cómo dividir un "zpool" unificado en dos, uno para el sistema operativo y otro para los datos. En una máquina en producción.

Esta máquina tiene dos discos duros en "mirror" ZFS, formando un "zpool" unificado. También tiene dos SSD utilizados como L2ARC y sistema de recuperación catastrófico. También se usarán como ZIL en cuanto divida el "zpool", porque no se puede usar un ZIL separado en un "zpool" "root". De hecho éste es el motivo para dividir el "zpool".

[root@XXX /]# zpool remove datos c4t0d0s2
[root@XXX /]# zpool create sistema c4t0d0s2
[root@XXX /]# zfs set compression=on sistema
[root@XXX /]# cat datos/boot/grub/menu.lst
[...]
title Solaris10u10FLASH
#findroot (BE_Solaris10u10,0,a)
root (hd0,0,c)
bootfs sistema/ROOT/Solaris10u10
kernel$ /platform/i86pc/multiboot -B $ZFS-BOOTFS
module /platform/i86pc/boot_archive

title Solaris10u10FLASH failsafe
#findroot (BE_Solaris10u10,0,a)
root (hd0,0,c)
bootfs sistema/ROOT/Solaris10u10
kernel /boot/multiboot -s 
module /boot/amd64/x86.miniroot-safe

title Solaris10u10
#findroot (BE_Solaris10u10,0,a)
root (hd2,0,a)
bootfs datos/ROOT/Solaris10u10
kernel$ /platform/i86pc/multiboot -B $ZFS-BOOTFS
module /platform/i86pc/boot_archive

title Solaris10u10 failsafe
#findroot (BE_Solaris10u10,0,a)
root (hd2,0,a)
bootfs datos/ROOT/Solaris10u10
kernel /boot/multiboot -s 
module /boot/amd64/x86.miniroot-safe

[root@XXX /]# zfs snapshot datos@FLASH; zfs snapshot -r datos/ROOT@FLASH
[root@XXX /]# zfs send datos@20110801-14:26 | zfs receive -Fduv sistema
receiving full stream of datos@20110801-14:26 into sistema@20110801-14:26
received 172MB stream in 4 seconds (43.0MB/sec)
[root@XXX /]# zfs send -I @20110801-14:26 datos@FLASH | zfs receive -Fduv sistema
[...]
[root@XXX /]# zfs send -R datos/ROOT@FLASH | time zfs receive -Fduv sistema
[...]
real    17:29.8
user        0.0
sys      1:24.9
[root@XXX /]# zpool set bootfs=sistema/ROOT/Solaris10u10 sistema
[root@XXX /]# zpool set failmode=continue sistema
[root@XXX /]# init 6
[...]

Lo primero que hacemos es quitar uno de los SSD del servicio L2ARC y crear el nuevo "zpool" "sistema" en él. Activar la compresión por defecto (usa LZJB) nos permite ganar un poco de espacio manteniendo un "zpool" compatible con el arranque vía GRUB y con una carga de CPU despreciable. A continuación configuramos el "menu.lst" para permitir arrancar desde la SSD (la máquina está hospedada de forma remota, pero tenemos acceso por KVM, teclado, video y ratón virtuales).

El siguiente paso es hacer un "snapshot" del sistema operativo y enviarlo a la SSD. Como se puede ver, la operación es bastante rápida, 17 minutos, y la máquina sigue en producción todo el tiempo. Gracias al uso de "snapshots", sabemos que la copia que estamos haciendo va a ser consistente, aunque la copia lleve un tiempo y el disco se sigue modificando.

El último paso consiste en configurar un par de propiedades del "zpool" y reiniciar el servidor. Y cruzar los dedos, claro

En el menú de arranque GRUB seleccionaremos "Solaris10u10FLASH". Si hubiese cualquier tipo de problema, bastaría arrancar de forma normal, "Solaris10u10", arrancando del disco duro. Hasta ahora no hemos hecho nada irreversible.

El arranque funciona a la primera, y nos aseguramos de que estamos cargando el sistema operativo desde el nuevo "dataset" "sistema". Bien.

Sigamos...

[root@XXX /]# zfs destroy -r datos@FLASH
[root@XXX /]# zpool scrub datos
[root@XXX /]# zpool status datos
  pool: datos
 state: ONLINE
 scan: scrub in progress since Sat Jan  7 09:11:58 2012
    5.14M scanned out of 1.20T at 478K/s, (scan is slow, no estimated time)
    5.14M scanned out of 1.20T at 478K/s, 747h14m to go
    0 repaired, 0.00% done
config:

        NAME          STATE     READ WRITE CKSUM
        datos         ONLINE       0     0     0
          mirror-0    ONLINE       0     0     0
            c4t2d0s0  ONLINE       0     0     0
            c4t3d0s0  ONLINE       0     0     0
        cache
          c4t1d0s2    ONLINE       0     0     0

errors: No known data errors

(Esperamos a que el "scrub" se complete. En mi caso supone unas 8 horas)

[root@XXX /]# format

(Reconfiguramos los "slices" Solaris del disco duro)

[root@XXX /]# zpool attach sistema c4t0d0s2 c4t2d0s0
Make sure to wait until resilver is done before rebooting.
[root@XXX /]# zpool status sistema
  pool: sistema
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scan: resilver in progress since Sat Jan  7 09:21:53 2012
    981M scanned out of 12.0G at 39.2M/s, 0h4m to go
    981M scanned out of 12.0G at 39.2M/s, 0h4m to go
    980M resilvered, 7.97% done
config:

        NAME          STATE     READ WRITE CKSUM
        sistema       ONLINE       0     0     0
          mirror-0    ONLINE       0     0     0
            c4t0d0s2  ONLINE       0     0     0
            c4t2d0s0  ONLINE       0     0     0  (resilvering)

errors: No known data errors

(Esperamos a que el "resilvering" termine)

[root@XXX< /]# zpool status sistema
  pool: sistema
 state: ONLINE
 scan: resilvered 12.0G in 0h7m with 0 errors on Sat Jan  7 09:28:58 2012
config:

        NAME          STATE     READ WRITE CKSUM
        sistema       ONLINE       0     0     0
          mirror-0    ONLINE       0     0     0
            c4t0d0s2  ONLINE       0     0     0
            c4t2d0s0  ONLINE       0     0     0

errors: No known data errors
[root@XXX /]# zfs destroy -r datos/ROOT
[root@XXX /]# cat /sistema/boot/grub/menu.lst
[...]
title Solaris10u10
#findroot (BE_Solaris10u10,0,a)
root (hd2,0,a)
bootfs sistema/ROOT/Solaris10u10
kernel$ /platform/i86pc/multiboot -B $ZFS-BOOTFS
module /platform/i86pc/boot_archive

title Solaris10u10 failsafe
#findroot (BE_Solaris10u10,0,a)
root (hd2,0,a)
bootfs sistema/ROOT/Solaris10u10
kernel /boot/multiboot -s 
module /boot/amd64/x86.miniroot-safe

(Editamos el entorno de "Live Upgrade", en "/etc/lu/ICF.*" y "/etc/lutab")

A continuación borramos los "snapshots" origen, que ya no necesitamos. Lo que haremos a continuación es romper el "mirror" ZFS. Esto, claro, siempre me pone nervioso (con razón), así que lo primero que hago es realizar un "scrubbing" del "mirror", de forma que estamos seguros de que ambos discos duros funcionan bien y todos los datos son correctos en AMBOS. Si hubiese cualquier tipo de error en un disco, se corregiría con el contenido el otro. El tiempo necesario para que esta operación se complete depende del volumen de datos que tengamos en el disco, no de su capacidad. En mi caso, este proceso termina en unas ocho horas. Ambos discos están bien.

El riesgo que conjuramos aquí es romper el "mirror" y luego encontrarnos con que el disco que nos queda contiene errores que YA no es posible corregir, porque no tiene "mirror". Haciendo un "scrub" nos aseguramos de que todo va bien. La única ventana de error ahora entonces es que el disco que queda desarrolle errores en las horas que tardaremos en completar el procedimiento, y antes de volver a asociarle un "mirror". Es un riesgo calculado. Instintivamente compruebo, poniéndome en el peor de los casos, que mis backups son recientes y funcionan, y echo cuentas mentales de cuánto tardaría en recuperar el servicio en el improbable pero posible caso de que ocurra un fallo hardware del disco duro durante esta ventana.

Una vez que hemos hecho lo posible para evitar problemas, rompemos el "mirror". Ahora "datos" reside solo en uno de los discos, el otro está "libre". Lo "formateamos", creando dos "slices" Solaris que ocupan todo el disco duro. El primer "slice", de unos 27 GB, lo pongo en la parte exterior del disco duro, donde la transferencia es más rápida. Ese tamaño es el tamaño del "zpool" "sistema" que creamos en el SSD. El resto del disco duro lo asigno a otro "slice", que contendrá un futuro "zpool" llamado "datos".

Pongo el sistema en la parte rápida del disco duro porque el "zpool" del sistema no va a tener cacheo L2ARC (lectura) ni ZIL (escritura).

Añadimos a "sistema" el "slice" que acabamos de crear, como "mirror". Solaris empezará a copiar a toda la velocidad el contenido de la SSD al disco duro. Copiar 12 GB tarda 7 minutos (salen unos 28MB/s).

Ahora que tenemos "sistema" en "mirror" en la SSD y uno de los discos duros, borramos el sistema operativo de "datos" (estas dos versiones no se "pegan" entre sí, porque sus "datasets" están configurados para no ser montados por defecto, sino que solo se monta automáticamente al arrancar el sistema el "dataset" que efectivamente hemos seleccionado en el GRUB). Reconfiguramos el GRUB de nuevo para arrancar desde el disco duro (que ahora contiene uno de los "mirrors" de "sistema"). Osea, lo dejamos como al principio, cambiando "datos" por "sistema".

Como uso "Live Upgrade", me toca editar a mano un par de ficheros de configuración. Los cambios deberían ser evidentes, y se trata de ficheros de texto pequeños.

Por supuesto, la máquina sigue en producción TODO el tiempo (salvo los reinicios que se indican).

[root@XXX /]# zpool create datos2 c4t2d0s1
[root@XXX /]# umount /datos2
[root@XXX /]# zfs snapshot -r datos@CONVERSION
[root@XXX /]# zfs send -R datos@CONVERSION | time zfs receive -Fduv datos2
[...]
real  6:08:55.3
user        0.2
sys     23:33.1
[root@XXX /]# zfs snapshot -r datos@CONVERSION2
[root@XXX /]# zfs send -R -I @CONVERSION datos@CONVERSION2 | time zfs receive -Fduv datos2
[...]
real     7:17.7
user        0.2
sys         9.9

(Paramos las zonas Solaris)

[root@XXX /]# zfs snapshot -r datos@CONVERSION3
[root@XXX /]# zfs send -R -I @CONVERSION2 datos@CONVERSION3 | time zfs receive -Fduv datos2
real     3:19.3
user        0.1
sys         1.2

(Entramos al servidor vía KVM)
(Reiniciamos el servidor y entramos en modo "failsafe")

# mkdir z
# zpool import -f -R /tmp/root/z datos
# zpool destroy datos
# zpool import -f -R /tmp/root/z datos2 datos
# init 6

El siguiente paso es replicar "datos" en el disco B en el segundo "slice" del disco A. Creo un "zpool" llamado "datos2", hago un "snapshot" de los datos originales y los copio en "datos2". Es más de un terabyte de datos, así que lleva un buen rato. La máquina sigue en producción, todo el tiempo, haciendo cambios en el disco (bases de datos, correo, logs, etc), pero como hemos hecho un "snapshot", sabemos que la copia será consistente.

Por supuesto los cambios que se produzcan en el disco duro original no se propagan a la copia. Normal, estamos mandando un "snapshot". Así que tras duplicar los datos originales, unas seis horas, hacemos un segundo "snapshot" y enviamos los cambios INCREMENTALES que se han producido en estas seis horas. Esa transferencia supone unos siete minutos. Ahora paramos las "zonas" Solaris, que son las que están haciendo cambios en el disco. Como todos mis servicios están en zonas Solaris, si dejamos funcionando solo la zona "global", los cambios en el disco son mínimos y limitados al sistema operativo, que ya hemos separado en "sistema". A efectos prácticos, "datos" ya no se modifica, o no en formas que nos importe conservar. Ahora hacemos un tercer "snapshot" y lo transferimos en tres minutos.

En este momento, "datos" y "datos2" contienen lo mismo.

Ahora llega la parte delicada: arrancamos el ordenador en el modo a prueba de fallos, donde no se monta apenas nada, ni se arranca ningún servicio. Destruimos "datos" y renombramos "datos2" a "datos". Obśervese cómo se renombra un "zpool": se renombra haciendo un "import" indicando un nombre de importación explícito. No lo sabía, he tenido que buscarlo :-).

Reiniciamos y cruzamos los dedos. Todo funciona a la perfección.

Continuemos...

[root@XXX /]# format

(Reconfiguramos los "slices" Solaris en el segundo disco duro de forma idéntica al primer disco duro)

[root@XXX /]# zpool attach sistema c4t2d0s0 c4t3d0s0
Make sure to wait until resilver is done before rebooting.
[root@XXX /]# zpool status sistema
  pool: sistema
 state: ONLINE
 scan: resilvered 12.2G in 0h7m with 0 errors on Sat Jan  7 18:08:43 2012
config:

        NAME          STATE     READ WRITE CKSUM
        sistema       ONLINE       0     0     0
          mirror-0    ONLINE       0     0     0
            c4t0d0s2  ONLINE       0     0     0
            c4t2d0s0  ONLINE       0     0     0
            c4t3d0s0  ONLINE       0     0     0

errors: No known data errors
[root@XXX /]# zpool detach datos c4t0d0s2
[root@XXX /]# zfs destroy -r sistema@FLASH
[root@XXX /]# zfs destroy -r datos@CONVERSION
[root@XXX /]# zfs destroy -r datos@CONVERSION2
[root@XXX /]# zfs destroy -r datos@CONVERSION3
[root@XXX /]# zpool add datos cache c4t0d0s2
[root@XXX /]# zpool add datos cache c4t1d0s2
[root@XXX /]# zpool add datos log mirror c4t0d0s1 c4t1d0s1
[root@XXX /]# zpool attach datos c4t2d0s1 c4t3d0s1
[root@XXX /]# zpool status datos
  pool: datos
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scan: resilver in progress since Sat Jan  7 18:16:13 2012
    623M scanned out of 1.18T at 13.5M/s, 25h25m to go
    623M scanned out of 1.18T at 13.5M/s, 25h25m to go
    623M resilvered, 0.05% done
config:

        NAME          STATE     READ WRITE CKSUM
        datos         ONLINE       0     0     0
          mirror-0    ONLINE       0     0     0
            c4t2d0s1  ONLINE       0     0     0
            c4t3d0s1  ONLINE       0     0     0  (resilvering)
        logs
          mirror-1    ONLINE       0     0     0
            c4t0d0s1  ONLINE       0     0     0
            c4t1d0s1  ONLINE       0     0     0
        cache
          c4t0d0s2    ONLINE       0     0     0
          c4t1d0s2    ONLINE       0     0     0

errors: No known data errors

(Esperamos a que termine la sincronización del "mirror")

[root@XXX /]# zpool status datos
  pool: datos
 state: ONLINE
 scan: resilvered 1.18T in 3h54m with 0 errors on Sat Jan  7 22:11:10 2012
config:

        NAME          STATE     READ WRITE CKSUM
        datos         ONLINE       0     0     0
          mirror-0    ONLINE       0     0     0
            c4t2d0s1  ONLINE       0     0     0
            c4t3d0s1  ONLINE       0     0     0
        logs
          mirror-1    ONLINE       0     0     0
            c4t0d0s1  ONLINE       0     0     0
            c4t1d0s1  ONLINE       0     0     0
        cache
          c4t0d0s2    ONLINE       0     0     0
          c4t1d0s2    ONLINE       0     0     0

errors: No known data errors

Ahora que hemos destruido el "zpool" "datos", el segundo disco duro está vació. Lo formateamos con una configuración idéntica al primer disco (dos "slices" Solaris, el pequeño en la parte exterior y rápida del disco duro). Añado un tercer "mirror" al "zpool" "sistema". Ahora tenemos una copia en cada disco duro y en una "SSD".

Una vez que la reconstrucción del tercer componente del "mirror" termina, quitamos la SSD del "mirroring", liberándola. Nos quedamos con un "mirror" de dos componentes, los dos discos duros. Es de señalar que durante la reconstrucción del disco duro B, dos tercios de los datos provienen de la SSD, y un tercio del otro disco duro.

Luego hacemos limpieza, eliminando los "snapshots" que creamos para transferir la información.

El siguiente paso es añadir las SSD como L2ARC y ZIL, tal y como explico en "ZFS y SSD's".

Por último, añadimos el "slice" grande del segundo disco al "zpool" "datos" y esperamos a que la sincronización del "mirror" se complete.

El resultado es la separación completa de un "zpool" unificado a dos "zpools": sistema operativo y datos. De forma rápida, limpia y segura.

Un par de detalles:

  • El reinicio final, para destruir "datos" y "datos2", sería innecesario si pudiésemos exportar "datos" con la máquina arrancada. Y deberíamos. El problema es que tengo "/usr/local" en "datos", que siempre está en uso, y no puedo exportar el "zpool". Si no fuese así, podríamos evitarnos un reinicio y un acceso por KVM.

  • Dado que toda la estructura de disco ha cambiado, tengo que actualizar los scripts de backups, procedimientos de recuperación catastrófica, documentación, etc.

  • "swap" y "dump" están en "datos". Funciona bien.

  • Solaris activa la caché de escritura de disco duro si detecta que estamos usando todo el disco para ZFS. Antes tenía un único "slice" Solaris en cada disco. Ahora tengo dos. Compruebo si tengo la caché de disco activada:
    [root@XXX z]# cat cache_display.txt
    disk
    2
    cache
    read_cache
    display
    quit
    write_cache
    display
    quit
    quit
    
    disk
    3
    cache
    read_cache
    display
    quit
    write_cache
    display
    quit
    quit
    
    [root@XXX z]# format -e <cache_display.txt
    Searching for disks...done
    [...]
    Specify disk (enter its number): selecting c4t2d0
    [disk formatted]
    /dev/dsk/c4t2d0s0 is part of active ZFS pool sistema. Please see zpool(1M).
    /dev/dsk/c4t2d0s1 is part of active ZFS pool datos. Please see zpool(1M).
    [...]
    read_cache> Read Cache is enabled
    [...]
    write_cache> Write Cache is enabled
    [....]
    Specify disk (enter its number)[2]: selecting c4t3d0
    [disk formatted]
    /dev/dsk/c4t3d0s0 is part of active ZFS pool sistema. Please see zpool(1M).
    /dev/dsk/c4t3d0s1 is part of active ZFS pool datos. Please see zpool(1M).
    [...]
    read_cache> Read Cache is enabled
    [...]
    write_cache> Write Cache is enabled
    

    Si no fuese el caso, habría que escribir un script SMF para activar la caché de escritura de forma manual al reiniciar el ordenador. En este caso Solaris es lo bastante inteligente como para decidir que es seguro activar la caché de escritura (ZFS envía "cache flush" cuando es necesario).


Historia

  • 10/ene/12: Publicación del documento.

  • 07/ene/12: Primera versión de esta página.



Python Zope ©2012 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS