jueves, 26 de junio de 2008

Tutorial: Pasar el SWAP a Raid

Este mes tuve unos cuantos eventos de caída de disco en varios servidores. Normalmente, no me preocuparía, dado que es relativamente normal dada la pésima calidad del hardware que se puede adquirir en Uruguay (parece que nos llega la peor basura grado "C" que se fabrica en el mundo), pero me ha pasado que uno de los equipos ha dejado de funcionar correctamente dado que el SWAP no estaba protegido por la configuración Raid, y una vez que el disco que contiene la partición explota, el SWAP de la misma deja de funcionar y el kernel empieza a comportarse como si hubiera salido un sábado a la noche con unos amigos a tomarse todo el stock de vodka y tequila de la Ciudad Vieja, así que se me ocurrió escribir este texto para entretenerme mientras reviso y arreglo los servidores que todavía pueden tener configuraciones como estas (y de paso evitarme horas de "diversión gratuíta"...).

Como espero que mis lectores sepan, el RAID (Redundant Array of Independent Disks, o Redundant Array of Inexpensive Disk, dependiendo de donde se lea) es un mecanismo que permite utilizar varios discos duros independientes en forma agrupada como si fueran uno solo, normalmente con la finalidad de obtener redundancia y tolerancia a fallos, aunque no siempre se lo utiliza con ese fin. A veces se utiliza como una forma de obtener un medio de almacenamiento de un tamaño total igual a la suma del tamaño de los discos que componen el Raid (se le denomina Raid de nivel 0), aunque este método no provée redundancia, y de hecho, no lo recomiendo.

Normalmente utilizo Raid de niveles 1, 5 y derivados de 5 (5E, 5EE, etc.) por hardware o por software, dependiendo de la plataforma de hardware que tenga a mano. Si tengo una controladora de Raid, la utilizo, y si no tengo, simplemente hago las gestiones para instalar Raid por software.

Este tutorial es una "receta" para pasar el SWAP que dejamos sin protección al raid, sin reiniciar el servidor que actualmente se encuentra en producción, bajo Linux.

Recomiendo lectura previa del Software Raid HOWTO y del Manual del mdadm, así como también de toda documentación que ilumine la ruta del iniciado y le evite males peores. No leer los manuales es garantía de desastre y de una vida sexual plagada de insatisfacciones. ¡No digan que no se los avisé!

Let the fun begins! :-)

TUTORIAL: Pasar el SWAP a Raid

Primero, chequeamos las particiones de nuestra "víctima":

root@server:~ # fdisk -l

Disco /dev/sda: 120.0 GB, 120034123776 bytes
255 cabezas, 63 sectores/pista, 14593 cilindros
Unidades = cilindros de 16065 * 512 = 8225280 bytes

Disposit. Inicio Comienzo Fin Bloques Id Sistema
/dev/sda1 * 1 7 56196 83 Linux
/dev/sda2 8 138 1052257+ 82 Linux swap / Solaris
/dev/sda3 139 14592 116101755 fd Linux raid autodetect

Disco /dev/sdb: 120.0 GB, 120034123776 bytes
255 cabezas, 63 sectores/pista, 14593 cilindros
Unidades = cilindros de 16065 * 512 = 8225280 bytes

Disposit. Inicio Comienzo Fin Bloques Id Sistema
/dev/sdb1 1 7 56196 83 Linux
/dev/sdb2 8 138 1052257+ 82 Linux swap / Solaris
/dev/sdb3 139 14592 116101755 fd Linux raid autodetect

Disco /dev/md0: 118.8 GB, 118888071168 bytes
2 cabezas, 4 sectores/pista, 29025408 cilindros
Unidades = cilindros de 8 * 512 = 4096 bytes

El disco /dev/md0 no contiene una tabla de particiones válida
root@server:~ #

Como puede verse, tenemos dos discos idénticos de 120GB, con una partición de 54MB al principio, una partición de 1GB al medio (el SWAP) y una partición de Raid de 118GB al final. Las últimas dos particiones forman parte de una unidad de Raid L1, denominada /dev/md0.

La idea es convertir estas dos particiones de SWAP separadas en una única unidad de Raid L1, la cual pasará a ser luego el SWAP. La única desventaja de esta modificación es que actualmente el servidor cuenta con dos particiones de SWAP independientes, cada una de 1GB, lo cual resulta en un total de 2GB de SWAP efectivo, y cuando hagamos el cambio, asumiendo que vamos a usar Raid L1, el espacio de SWAP disponible quedará reducido a la mitad. Normalmente, esto no resulta ser un problema, y de hecho, es preferible a que el sistema falle porque el disco donde estaba el SWAP aterrizó... así que vamos a ejecutar el procedimiento de todas maneras.

root@server:~ # df -h
S.ficheros Tamaño Usado Disp Uso% Montado en
/dev/md0 109G 90G 14G 87% /
tmpfs 474M 0 474M 0% /dev/shm
/dev/sda1 54M 8,6M 42M 18% /boot
root@server:~ # free
total used free shared buffers cached
Mem: 513740 506508 7232 0 65480 142272
-/+ buffers/cache: 298756 214984
Swap: 2104514 297205 1807309
root@server:~ #

Por lo visto, el uso es intenso, así que tenemos que ser precavidos en lo que vamos a hacer a continuación, ya que es importante evitar consumir todo el espacio disponible con la maniobra de manipulación del SWAP necesaria para poder convertir las particiones a su nuevo formato.

Para lograr esto, debemos crear un archivo vacío que utilizaremos como SWAP temporal, evitando así que el servidor quede sin memoria virtual mientras trabajamos en la conversión de las particiones.
root@server:~ # dd if=/dev/zero of=/swap.tmp bs=1G count=1
1+0 registros leídos
1+0 registros escritos
1073741824 bytes (1,1 GB) copied, 20,356 seconds, 52,7 MB/s
root@server:~ #

Luego, convertimos este archivo en SWAP y lo activamos. Esto agregará más SWAP a la cantidad que tenemos declarada actualmente.
root@server:~ # mkswap /swap.tmp
Configurando espacio de intercambio versión 1, tamaño = 1073737 kB
root@server:~ # swapon /swap.tmp
root@server:~ # free
total used free shared buffers cached
Mem: 513740 506508 7232 0 65480 142272
-/+ buffers/cache: 298756 214984
Swap: 3153082 297205 2855877
root@server:~ #

Ahora, procedemos a desactivar el SWAP que brindan las particiones standard, de manera de poder manipularlas sin destruir el servidor... (créanme, si se manipulan las particiones de SWAP estando activas, el servidor explota). Tengan paciencia, la desactivación del SWAP puede llevar algunos segundos, dado que se transvasa toda la información activa en el SWAP a memoria central y se swapea hacia el nuevo espacio disponible cuando se hace necesario.
root@server:~ # grep "swap" /etc/fstab
/dev/sda2 swap swap pri=42 0 0
/dev/sdb2 swap swap pri=42 0 0
root@server:~ # swapoff /dev/sda2
root@server:~ # swapoff /dev/sdb2
root@server:~ # free
total used free shared buffers cached
Mem: 513740 506508 7232 0 65480 142272
-/+ buffers/cache: 298756 214984
Swap: 1048568 0 1048568
root@server:~ #

Ahora que tenemos las particiones de SWAP desactivadas, podemos proceder a la manipulación de las mismas para convertirlas en una unidad de Raid L1. Tenemos que cambiar el tipo de partición con fdisk, lo cual se hace en un momento.
root@server:~ # fdisk /dev/sda

El número de cilindros para este disco está establecido en 14593.
No hay nada malo en ello, pero es mayor que 1024, y en algunos casos
podría causar problemas con:
1) software que funciona en el inicio (p.ej. versiones antiguas de LILO)
2) software de arranque o particionamiento de otros sistemas operativos
(p.ej. FDISK de DOS, FDISK de OS/2)

Orden (m para obtener ayuda): p

Disco /dev/sda: 120.0 GB, 120034123776 bytes
255 cabezas, 63 sectores/pista, 14593 cilindros
Unidades = cilindros de 16065 * 512 = 8225280 bytes

Disposit. Inicio Comienzo Fin Bloques Id Sistema
/dev/sda1 * 1 7 56196 83 Linux
/dev/sda2 8 138 1052257+ 82 Linux swap / Solaris
/dev/sda3 139 14592 116101755 fd Linux raid autodetect

Orden (m para obtener ayuda): t
Número de partición (1-4): 2
Código hexadecimal (escriba L para ver los códigos): fd
Se ha cambiado el tipo de sistema de la partición 2 por fd (Linux raid autodetect)

Orden (m para obtener ayuda): w
¡Se ha modificado la tabla de particiones!

Llamando a ioctl() para volver a leer la tabla de particiones.

ATENCIÓN: La relectura de la tabla de particiones falló con el
error 16: Dispositivo o recurso ocupado.
El núcleo todavía usa la tabla antigua.
La nueva tabla se usará en el próximo reinicio.
Se están sincronizando los discos.
root@server:~ #

Como puede verse, la manipulación terminó con un error 16, lo cual es normal para un sistema que está en funcionamiento, pero esto no es un problema real, dado que sin importar el tipo de partición que se utilice, el formato interno de la partición es lo que realmente define el tipo de la misma, así que el hecho de que el BIOS crea que sigue teniendo una partición de tipo SWAP es totalmente irrelevante.

Procedemos entonces a ejecutar la misma acción sobre el otro disco, hasta que las dos particiones están preparadas para formar parte del raid.
root@server:~ # fdisk /dev/sdb
[...]
root@server:~ # fdisk -l 2>/dev/null | grep "/dev/sd.2"
/dev/sda2 8 138 1052257+ fd Linux raid autodetect
/dev/sdb2 8 138 1052257+ fd Linux raid autodetect
root@server:~ #

Ahora, consultamos la tabla de estado del raid por software del kernel para verificar la configuración y para obtener el nombre de la próxima unidad (seguramente va a ser /dev/md1, pero es imperativo serciorarnos antes).
root@server:~ # cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 sdb3[1] sda3[0]
116101632 blocks [2/2] [UU]

unused devices:
root@server:~ #

Y finalmente procedemos a crear la unidad de raid correspondiente, para lo cual utilizaremos el comando mdadm (del cual recomiendo leer el manual antes de hacer nada de esto...).
root@server:~ # mdadm --create /dev/md1 --raid-devices=2 --level=1 /dev/sda2 /dev/sdb2
mdadm: array /dev/md1 started.
root@server:~ #

Para confirmar el funcionamiento, volvemos a consultar la tabla de raid del kernel, mediante la cual comprobamos que la nueva unidad está siendo sincronizada. A pesar de no tener nada adentro (o tener más bien restos de basura), la sincronización se realiza siempre que se cree o regenere una unidad de raid.
root@server:~ # cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 sdb2[1] sda2[0]
1052160 blocks [2/2] [UU]
[=>...................] resync = 9.9% (104448/1052160) finish=0.6min speed=26112K/sec
md0 : active raid1 sdb3[1] sda3[0]
116101632 blocks [2/2] [UU]

unused devices:
root@server:~ #

De hecho, sin importar el formato interno de la unidad una vez generada, si corrompemos el filesystem de la misma, la unidad de raid no se quejará ni dará ningún aviso, ni al usuario ni al sistema, dado que su trabajo es conservar en sincronía las particiones que forman parte de la misma, y no le interesa la consistencia de los datos almacenados internamente en el filesystem que la ocupa.

Esto parece algo malo, pero la realidad es que es el filesystem el que se debe ocupar de la consistencia de la información, NO la unidad de raid. Hay que tener eso en cuenta cuando se manipulen datos contenidos en unidades de este tipo.

Y bien, una vez que se termina la sincronización de las particiones, la unidad queda utilizable, con lo cual el próximo paso es formatear la nueva unidad para que pueda utilizarse como SWAP.
root@server:~ # cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 sdb2[1] sda2[0]
1052160 blocks [2/2] [UU]

md0 : active raid1 sdb3[1] sda3[0]
116101632 blocks [2/2] [UU]

unused devices:
root@server:~ # mkswap /dev/md1
Configurando espacio de intercambio versión 1, tamaño = 1077407 kB
root@server:~ #

Luego, procedemos a activar el nuevo espacio de SWAP y a desactivar el SWAP temporal que dejamos en su lugar. Esto puede demandar algunos segundos también si hay algo swapeado (en este caso, no hay uso del SWAP, así que será inmediato).
root@server:~ # swapon /dev/md1
root@server:~ # free
total used free shared buffers cached
Mem: 513740 506508 7232 0 65480 142272
-/+ buffers/cache: 298756 214984
Swap: 2104417 0 2104417
root@server:~ # swapoff /swap.tmp
root@server:~ # free
total used free shared buffers cached
Mem: 513740 506508 7232 0 65480 142272
-/+ buffers/cache: 298756 214984
Swap: 1052160 0 1052160
root@server:~ # rm /swap.tmp
root@server:~ #

Ahora, modificamos el /etc/fstab para reflejar los cambios en la estructura de SWAP del sistema, reemplazando las entradas que están en amarillo:
/dev/md0             /                    ext3       acl,user_xattr        1 1
/dev/sda2 swap swap pri=42 0 0
/dev/sdb2 swap swap pri=42 0 0

/dev/sda1 /boot ext2 acl,user_xattr 1 2
devpts /dev/pts devpts mode=0620,gid=5 0 0
proc /proc proc defaults 0 0
usbfs /proc/bus/usb usbfs noauto 0 0
sysfs /sys sysfs noauto 0 0

por la que está en verde abajo:
/dev/md0             /                    ext3       acl,user_xattr        1 1
/dev/md1 swap swap pri=42 0 0
/dev/sda1 /boot ext2 acl,user_xattr 1 2
devpts /dev/pts devpts mode=0620,gid=5 0 0
proc /proc proc defaults 0 0
usbfs /proc/bus/usb usbfs noauto 0 0
sysfs /sys sysfs noauto 0 0

Para finalizar, y por el bien de la humanidad, del sysadmin olvidadizo y del feliz reboot del servidor, es bueno generar un nuevo /etc/mdadm.conf que refleje los cambios que se han hecho:
root@server:~ # echo "DEVICES /dev/sda2 /dev/sdb2 /dev/sda3 /dev/sdb3" > /etc/mdadm.conf
root@server:~ # mdadm --detail --scan >> /etc/mdadm.conf
root@server:~ # cat /etc/mdadm.conf
DEVICES /dev/sda2 /dev/sdb2 /dev/sda3 /dev/sdb3
ARRAY /dev/md1 level=raid1 num-devices=2 UUID=7c42bfff:4e68b0d2:578afc87:e3831721
devices=/dev/sda2,/dev/sdb2
ARRAY /dev/md0 level=raid1 num-devices=2 UUID=685b0678:9856ccff:50e357fc:db560963
devices=/dev/sda3,/dev/sdb3
root@server:~ #

Con lo cual cerramos este tutorial finalmente, con la tranquilidad y la satisfacción de haber hecho un buen trabajo y de no haber dejado pendiente un problema de esos que te suelen producir el ya consabido síndrome del sysadmin.

Enjoy! :-)

:wq

2 comentarios:

CheLo Inc. & Co..- dijo...

Estimado Gustavo : me gusto mucho tu "Tutorial de como Pasar el SWAP a RAID", y te queria preguntar si se podria (siguiendo el mismo ejemplo) poder pasar un servidor en produccion sin RAID, agregar otro disco y crear un RAID 1 ??? pero sin perder la data del disco 1 !!!

Gustavo Castro Puig dijo...

Chelo:

Me alegro que te haya gustado. :-)

Solo he hecho ese procedimiento de pasar un equipo de un solo disco a raid1 un par de veces, pero sé que se puede hacer sin problemas. Hay que tomarlo con calma y no entrar en pánico si hay problemas.
Ando con poco tiempo como para describir todo el proceso, pero básicamente se trata de esto:

1) Agregar un disco idéntico al actual, como secundario (se puede hacer con discos diferentes, pero no lo recomiendo).

2) Particionar el disco igual a como está el original, solo que las particiones que formarían parte de las unidades de raid, habría que crearlas con tipo FD (Linux Raid Autodetect)

3) Inicializar las unidades de raid SIN CARGAR las particiones del disco original. Estas unidades quedarán degradadas, con solo las particiones del disco secundario activas ([_U]). Formatearlas usando el mismo filesystem usado en las particiones del disco primario (no importa que estén degradadas).

4) Si se hizo todo correcto, se puede perfectamente hacer una copia de los datos de las particiones del disco primario a las unidades raid.

5) Ahora viene la parte "complicada": con las copias hechas, hay que montar las unidades de raid tal cual deberían quedar una vez que el proceso termine, en un directorio /mnt (por ejemplo), se populariza el /mnt/proc (la opción --bind del mount es ideal para esto) y se hace un chroot /mnt.

6) Si todo está correcto, vas a poder instalar el grub en el MBR del disco secundario. Esto es IMPERATIVO.

7) Una vez que todo haya funcionado bien, modificamos los archivos del /etc (dentro del chroot, por supuesto) para que hagan referencia a /dev/mdN en lugar de las particiones /dev/sdaN. Con modificar el /etc/fstab alcanza.

8) Apagamos, sacamos el disco primario y booteamos. Si todo va bien, estamos con el raid L1 funcionando (degradado) y el disco primario intacto. Hasta acá, no corrés ningún peligro. :-)

9) Apagas, montás el disco que era primario como secundario, levantas el sistema de nuevo, modificas las particiones del disco que era primario (ahora es secundario) para que el tipo de particiones sea FD y haces un hot add de esas particiones a las unidades raid correspondientes.

10) ¡Te tomas una cerveza y festejas! :-)

Mas o menos así es el procedimiento, pero espero limpiarlo un poco y poner un tutorial más decente en el blog.

¡¡Espero que lo disfrutes!!

Salu2,
Gustavo

 
Gustavo Castro

Crea tu insignia