miércoles, 29 de septiembre de 2010

Disk mirroring en Solaris

El disk mirroring o copia en espejo consiste en proteger la información contenida en un disco manteniendo una copia idéntica en otro disco. A esto también se le conoce como un arreglo RAID 1.

Una de las ventajas mas fuertes de Solaris es que, a partir de la versión 8, es posible crear diferentes tipos de arreglos sin necesidad de adquirir software adicional para esto, esto se logra mediante una aplicación anteriormente llamada Solstice DiskSuite y ahora Solaris Volume Manager (SVM).

El SVM permite crear volúmenes concatenados (concat) y distribuidos (data striping), también permite “espejearlos” (mirror) e incluso el fragmentarlos (soft partition).

Para este tutorial, voy a utilizar un equipo con 2 discos scsi de 20Gb iguales, al cual, le instalé Solaris 10 en el disco 0, dejando un slice libre y suficiente espacio para la metadatabase (esto es un espacio que requiere el SVM para operar), el tamaño del espacio es muy pequeño, yo he trabajado con slices de 50 Mb perfectamente. El disco 1 lo deje vacío.

Por medio de los comando df y swap reviso qué particiones se están utilizando como filesystem y como swap:

df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/dsk/c1t0d0s0      2.9G   450M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.4G   512K   2.4G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/dsk/c1t0d0s4      5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/dsk/c1t0d0s3      2.9G    73M   2.8G     3%    /var
swap                   2.4G   136K   2.4G     1%    /tmp
swap                   2.4G    28K   2.4G     1%    /var/run
/dev/dsk/c1t0d0s6      2.9G   484M   2.4G    17%    /opt
/dev/dsk/c1t0d0s5      2.9G   3.0M   2.9G     1%    /export/home

swap -l
swapfile             dev  swaplo blocks   free
/dev/dsk/c1t0d0s1   32,1       8 4209016 4209016

Podemos observar que estamos utilizando 6 slices del disco c1t0d0.

Para la metadatabase es muy recomendable tener por cada disco, un slice dedicado para este fin, de tal forma que si uno de los discos se daña, siempre podremos contar con otras copias en otros discos. Por lo que procedo a crear una partición nueva con el slice que dejé libre. Utilizo el comando format

format
Searching for disks...done

AVAILABLE DISK SELECTIONS:
       0. c1t0d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@0,0
       1. c1t1d0 <DEFAULT cyl 2608 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@1,0
Specify disk (enter its number):
0
selecting c1t0d0
[disk formatted]
Warning: Current Disk has mounted partitions.
/dev/dsk/c1t0d0s0 is currently mounted on /. Please see umount(1M).
/dev/dsk/c1t0d0s1 is currently used by swap. Please see swap(1M).
/dev/dsk/c1t0d0s3 is currently mounted on /var. Please see umount(1M).
/dev/dsk/c1t0d0s4 is currently mounted on /usr. Please see umount(1M).
/dev/dsk/c1t0d0s5 is currently mounted on /export/home. Please see umount(1M).
/dev/dsk/c1t0d0s6 is currently mounted on /opt. Please see umount(1M).

FORMAT MENU:
        disk       - select a disk
        type       - select (define) a disk type
        partition  - select (define) a partition table
        current    - describe the current disk
        format     - format and analyze the disk
        fdisk      - run the fdisk program
        repair     - repair a defective sector
        label      - write label to the disk
        analyze    - surface analysis
        defect     - defect list management
        backup     - search for backup labels
        verify     - read and display labels
        save       - save new disk/partition definitions
        inquiry    - show vendor, product and revision
        volname    - set 8-character volume name
        !<cmd>     - execute <cmd>, then return
        quit
format> p

PARTITION MENU:
        0      - change `0' partition
        1      - change `1' partition
        2      - change `2' partition
        3      - change `3' partition
        4      - change `4' partition
        5      - change `5' partition
        6      - change `6' partition
        7      - change `7' partition
        select - select a predefined table
        modify - modify a predefined partition table
        name   - name the current table
        print  - display the current table
        label  - write partition map and label to the disk
        !<cmd> - execute <cmd>, then return
        quit
partition>
p
Current partition table (original):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0       root    wm       1 -  390        2.99GB    (390/0/0)   6265350
  1       swap    wu     391 -  652        2.01GB    (262/0/0)   4209030
  2     backup    wm       0 - 2606       19.97GB    (2607/0/0) 41881455
  3        var    wm     653 - 1042        2.99GB    (390/0/0)   6265350
  4        usr    wm    1043 - 1807        5.86GB    (765/0/0)  12289725
  5       home    wm    1808 - 2197        2.99GB    (390/0/0)   6265350
  6 unassigned    wm    2198 - 2587        2.99GB    (390/0/0)   6265350
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition>

Le indico que trabaje con el disco 0, me hace la advertencia de que tiene particiones que se encuentran montadas, le indico que trabajaremos con particiones y que muestre la tabla de partición, observamos que el slice 7 aparece sin espacio asignado y que el último ocupa hasta el cilindro 2587, por lo que tenemos desde el 2588 hasta el 2606 libres, procedemos entonces a crear la partición:

partition> 7
Part      Tag    Flag     Cylinders        Size            Blocks
  7 unassigned    wm       0               0         (0/0/0)           0

Enter partition id tag[unassigned]:
Enter partition permission flags[wm]:
Enter new starting cyl[0]:
2588
Enter partition size[0b, 0c, 2588e, 0.00mb, 0.00gb]: 2606e
partition>
p
Current partition table (unnamed):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0       root    wm       1 -  390        2.99GB    (390/0/0)   6265350
  1       swap    wu     391 -  652        2.01GB    (262/0/0)   4209030
  2     backup    wm       0 - 2606       19.97GB    (2607/0/0) 41881455
  3        var    wm     653 - 1042        2.99GB    (390/0/0)   6265350
  4        usr    wm    1043 - 1807        5.86GB    (765/0/0)  12289725
  5       home    wm    1808 - 2197        2.99GB    (390/0/0)   6265350
  6 unassigned    wm    2198 - 2587        2.99GB    (390/0/0)   6265350
  7 unassigned    wm    2588 - 2606      149.04MB    (19/0/0)     305235
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> label
Ready to label disk, continue? y

partition>

Con esto ya esta listo el disco 0, ahora vamos a preparar al disco 1, como en este caso estoy utilizando Solaris en x86, necesito inicializar el disco 1 con fdisk:

fdisk /dev/rdsk/c1t1d0p0
No fdisk table exists. The default partition for the disk is:

  a 100% "SOLARIS System" partition

Type "y" to accept the default partition,  otherwise type "n" to edit the
partition table.
y

Noten que el dispositivo que indique para que inicializara el disco c1t1d0 es el c1t1d0p0, esto es porque la plataforma x86 permite particionar los discos hasta en 4 particiones principales, a estas particiones Solaris las representa con p1 a p4 y p0 representa a todo el disco duro, por condición, la plataforma x86 requiere que exista por lo menos 1 partición en el disco duro, con el comando fdisk lo que hicimos fue crear esta partición (la p1) con el 100% del espacio disponible en el disco.

Una vez concluido esto vamos a copiar el VTOC del disco 0 en el disco 1, podemos hacerlo a mano con el format, pero en este caso los 2 discos son iguales, por lo que vamos a hacerlo con un atajo:

prtvtoc /dev/rdsk/c1t0d0s2 | fmthard -s - /dev/rdsk/c1t1d0s2
fmthard:  New volume table of contents now in place.

Este atajo también es válido en SPARC.

Cómo último paso para la preparación de este disco, necesitamos configurarlo como “booteable” ya que va a contener los archivos de sistema operativo, para Solaris10 x86 debemos hacer 2 pasos utilizando el comando fdisk y el installgrub:

fdisk -b /usr/lib/fs/ufs/mboot /dev/rdsk/c1t1d0p0

             Total disk size is 2610 cylinders
             Cylinder size is 16065 (512 byte) blocks

                                               Cylinders
      Partition   Status    Type          Start   End   Length    %
      =========   ======    ============  =====   ===   ======   ===
          1       Active    Solaris2          1  2609    2609    100

SELECT ONE OF THE FOLLOWING:
   1. Create a partition
   2. Specify the active partition
   3. Delete a partition
   4. Change between Solaris and Solaris2 Partition IDs
   5. Exit (update disk configuration and exit)
   6. Cancel (exit without updating disk configuration)
Enter Selection: 5

installgrub /boot/grub/stage1 /boot/grub/stage2 /dev/rdsk/c1t1d0s0
stage1 written to partition 0 sector 0 (abs 16065)
stage2 written to partition 0, 272 sectors starting at 50 (abs 16115)

En el caso de la plataforma SPARC se utiliza el comando installboot:

installboot /usr/platform/`uname -i`/lib/fs/ufs/bootblk /dev/rdsk/c1t0d0s0

Ya que nuestros discos están listos procedemos con el SVM, iniciamos creando la metadatabase:

metadb -a -f -c 4 c1t0d0s7 c1t1d0s7

Con esto estamos creando a la metadatabase en las particiones c1t0d0s7 y c1t1d0s7 con 4 copias en cada una, nótese que no requerimos indicar el path completo de los dispositivos.

Ahora vamos a crear un volumen para cada partición del disco 0 en las que tenemos filesystem y swap.

metainit -f d10 1 1 c1t0d0s0
d10: Concat/Stripe is setup
metainit -f d11 1 1 c1t0d0s1
d11: Concat/Stripe is setup
metainit -f d13 1 1 c1t0d0s3
d13: Concat/Stripe is setup
metainit -f d14 1 1 c1t0d0s4
d14: Concat/Stripe is setup
metainit -f d15 1 1 c1t0d0s5
d15: Concat/Stripe is setup
metainit -f d16 1 1 c1t0d0s6
d16: Concat/Stripe is setup

Después creamos los volúmenes espejo, para esto, debemos indicar para cada espejo cuál es el volumen primario, es decir, el que contiene la información que debemos duplicar:

metainit d0 -m d10
d0: Mirror is setup
metainit d1 -m d11
d1: Mirror is setup
metainit d3 -m d13
d3: Mirror is setup
metainit d4 -m d14
d4: Mirror is setup
metainit d5 -m d15
d5: Mirror is setup
metainit d6 -m d16
d6: Mirror is setup

Nota: Hasta aquí, podríamos indicarle que agregue los volúmenes secundarios a los espejos, sin embargo, yo no recomiendo hacerlo en este momento, debido a que debemos reiniciar el sistema operativo para que monte los filesystem utilizando los volúmenes en espejo en lugar de las particiones físicas, si por error reinicio sistema sin que los volúmenes estén sincronizados, nos va a dar un errores de consistencia, por lo que mi recomendación es dejar la sincronización como último paso.

Ahora, vamos a modificar el sistema para que inicie el sistema operativo montando los espejos, por lo que vamos a indicar primero que volumen contiene el filesystem raíz:

metaroot d0

Este comando modifica todos los archivos de configuración necesarios para que monte el volumen d0 como raíz (/), ahora debemos indicar en forma manual el resto de los volúmenes en el archivo /etc/vfstab, al editarlo, lo primero que vamos a observar es que ahora tiene indicado /dev/md/dsk/d0 como /, modificamos los demás sustituyendo a cada partición con el volumen que corresponda. Mi archivo antes de la modificación se encuentra así:

#device         device          mount           FS      fsck    mount   mount
#to mount       to fsck         point           type    pass    at boot options
#
fd      -       /dev/fd fd      -       no      -
/proc   -       /proc   proc    -       no      -
/dev/dsk/c1t0d0s1       -       -       swap    -       no      -
/dev/md/dsk/d0  /dev/md/rdsk/d0 /       ufs     1       no      -
/dev/dsk/c1t0d0s4       /dev/rdsk/c1t0d0s4      /usr    ufs     1       no      -
/dev/dsk/c1t0d0s3       /dev/rdsk/c1t0d0s3      /var    ufs     1       no      -
/dev/dsk/c1t0d0s5       /dev/rdsk/c1t0d0s5      /export/home    ufs     2       yes     -
/dev/dsk/c1t0d0s6       /dev/rdsk/c1t0d0s6      /opt    ufs     2       yes     -
/devices        -       /devices        devfs   -       no      -
sharefs -       /etc/dfs/sharetab       sharefs -       no      -
ctfs    -       /system/contract        ctfs    -       no      -
objfs   -       /system/object  objfs   -       no      -
swap    -       /tmp    tmpfs   -       yes     -

Después de modificar queda así:

#device         device          mount           FS      fsck    mount   mount
#to mount       to fsck         point           type    pass    at boot options
#
fd      -       /dev/fd fd      -       no      -
/proc   -       /proc   proc    -       no      -
/dev/md/dsk/d1  -       -       swap    -       no      -
/dev/md/dsk/d0  /dev/md/rdsk/d0 /       ufs     1       no      -
/dev/md/dsk/d4  /dev/md/rdsk/d4 /usr    ufs     1       no      -
/dev/md/dsk/d3  /dev/md/rdsk/d3 /var    ufs     1       no      -
/dev/md/dsk/d5  /dev/md/rdsk/d5 /export/home    ufs     2       yes     -
/dev/md/dsk/d6  /dev/md/rdsk/d6 /opt    ufs     2       yes     -
/devices        -       /devices        devfs   -       no      -
sharefs -       /etc/dfs/sharetab       sharefs -       no      -
ctfs    -       /system/contract        ctfs    -       no      -
objfs   -       /system/object  objfs   -       no      -
swap    -       /tmp    tmpfs   -       yes     -

Reiniciamos sistema operativo y ahora podemos ver que están montados los espejos en lugar de las particiones físicas:

df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/md/dsk/d0         2.9G   453M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.5G   948K   2.5G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/md/dsk/d4         5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/md/dsk/d3         2.9G    73M   2.8G     3%    /var
swap                   2.5G    40K   2.5G     1%    /tmp
swap                   2.5G    24K   2.5G     1%    /var/run
/dev/md/dsk/d6         2.9G   484M   2.4G    17%    /opt
/dev/md/dsk/d5         2.9G   3.0M   2.9G     1%    /export/home

swap -l
swapfile             dev  swaplo blocks   free
/dev/md/dsk/d1      85,1       8 4209016 4209016

Solo nos resta crear los volúmenes secundarios e iniciar la sincronización, los volúmenes secundarios se crean en la misma forma que los primarios:

metainit d20 1 1 c1t1d0s0
d20: Concat/Stripe is setup
metainit d21 1 1 c1t1d0s1
d21: Concat/Stripe is setup
metainit d23 1 1 c1t1d0s3
d23: Concat/Stripe is setup
metainit d24 1 1 c1t1d0s4
d24: Concat/Stripe is setup
metainit d25 1 1 c1t1d0s5
d25: Concat/Stripe is setup
metainit d26 1 1 c1t1d0s6
d26: Concat/Stripe is setup

Y agregamos cada volumen secundario a cada espejo que corresponde con lo que da inicio la sincronización:

metattach d0 d20
d0: submirror d20 is attached
metattach d1 d21
d1: submirror d21 is attached
metattach d3 d23
d3: submirror d23 is attached
metattach d4 d24
d4: submirror d24 is attached
metattach d5 d25
d5: submirror d25 is attached
metattach d6 d26
d6: submirror d26 is attached

Una vez que concluya la sincronización nuestro servidor se encuentra ya respaldado, el comando para monitorear el progreso es metastat:

metastat
d6: Mirror
    Submirror 0: d16
      State: Okay
    Submirror 1: d26
      State: Resyncing
    Resync in progress: 13 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d16: Submirror of d6
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s6          0     No            Okay   Yes

d26: Submirror of d6
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s6          0     No            Okay   Yes

d5: Mirror
    Submirror 0: d15
      State: Okay
    Submirror 1: d25
      State: Resyncing
    Resync in progress: 71 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d15: Submirror of d5
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s5          0     No            Okay   Yes

d25: Submirror of d5
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s5          0     No            Okay   Yes

d4: Mirror
    Submirror 0: d14
      State: Okay
    Submirror 1: d24
      State: Resyncing
    Resync in progress: 3 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 12289725 blocks (5.9 GB)

d14: Submirror of d4
    State: Okay
    Size: 12289725 blocks (5.9 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s4          0     No            Okay   Yes

d24: Submirror of d4
    State: Resyncing
    Size: 12289725 blocks (5.9 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s4          0     No            Okay   Yes

d3: Mirror
    Submirror 0: d13
      State: Okay
    Submirror 1: d23
      State: Resyncing
    Resync in progress: 38 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d13: Submirror of d3
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s3          0     No            Okay   Yes

d23: Submirror of d3
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s3          0     No            Okay   Yes

d1: Mirror
    Submirror 0: d11
      State: Okay
    Submirror 1: d21
      State: Okay
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 4209030 blocks (2.0 GB)

d11: Submirror of d1
    State: Okay
    Size: 4209030 blocks (2.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s1          0     No            Okay   Yes

d21: Submirror of d1
    State: Okay
    Size: 4209030 blocks (2.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s1          0     No            Okay   Yes

d0: Mirror
    Submirror 0: d10
      State: Okay
    Submirror 1: d20
      State: Resyncing
    Resync in progress: 18 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d10: Submirror of d0
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s0          0     No            Okay   Yes

d20: Submirror of d0
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s0          0     No            Okay   Yes

Device Relocation Information:
Device   Reloc  Device ID
c1t1d0   Yes    id1,sd@n6000c29bb05a74f0966940ff84e13c6a
c1t0d0   Yes    id1,sd@n6000c298a7553d9bfab466ad901ff8d3

Obsérvese que en cada espejo indica sus volúmenes miembro y en que estado se encuentra cada uno, en este caso en casi todo aparece el submirror 1 como resincronizando, esta herramienta debo ejecutarla periódicamente para revisar el estado en el que se encuentra los volúmenes SVM del servidor.

Debemos evitar reiniciar este equipo mientras este sincronizando, también es recomendable no ponerlo en “producción” hasta que termine, debido a que una sincronización de este nivel afecta el desempeño del equipo.

3 comentarios:

lobotmx dijo...

Don Alex, una duda...

Despues de crear el metarrot (corer el comando para copiar los archivos de configuracion en "d0" y posteriormente el SO pueda montarlo como el FS raiz (/)...

Veo que al Crear los volumenes para el resto de los FS's (swap /usr, /var, /export/home, /opt)... usas las particiones fisicas de dichos FS's al momento de asignarles el volumen...

Con lo anterior se omite la copia de informacion???, es decir, no se pierde el contenido previo de los Fs's indicados??? (se supone que dichas particiones fisicas contienen los archivos del SO, despues de que se instalo)...

Espero haberme explicado bien en mi duda...

Gracias!

Unknown dijo...

Precisamente eso es la mejor parte, al crear los volúmenes primarios asociándolos a cada uno con una sola partición no hay pérdida de información porque no hace ninguna escritura sobre la partición. Dicho de otra forma, cada volumen "submirror" es un mapa que representa a una partición física.

La única escritura que se realiza es cuando se hace la sincronización de los espejos, por eso es muy importante mantener siempre el orden de crear los espejos utilizando los volúmenes primarios y después agregar los volúmenes secundarios, es decir, los que no contienen información.

lobotmx dijo...

Orales!!!

Excelente, muchas gracias por el tiempo para disipar la duda Don Alex!

Saludox.