Últimos Cambios |
||
Blog personal: El hilo del laberinto |
Última Actualización: 28 de octubre de 2009 - Miércoles
Llevo unos cuantos años usando "rdiff-backup" para hacer la copia diaria de mis sistemas contra mi servidor de backup. En general la experiencia ha sido buena, pero "rdiff-backup" tiene una serie de problemas serios:
Debido a estos problemas, actualmente restrinjo "rdiff-backup" a los backups diarios, de directorios seleccionados (no discos completos, aunque son backups bastante extensivos). Esto es así porque esos backups se usan como protección contra errores, pero no nos interesan para conservar de forma indefinida, así que borrarlos de vez en cuando por alguna inconsistencia no me supone ningún problema.
Tengo un segundo nivel de backup, realizado mensualmente, usando "rsync" y la funcionalidad añadida recientemente de "--link-dest". Básicamente con esa opción, creamos un segundo directorio en el que los ficheros que no hayan cambiado respecto a otro directorio simplemente se enlazan con un "hardlink".
Algunas ventajas son:
Pero este sistema tiene también sus desventajas:
Además, todos estos sistemas de backup requieren revisar el disco duro entero, aunque no haya habido ningún cambio.
Mi ideal sería utilizar ZFS de forma nativa, ya que una de sus incontables ventajas es su capacidad para identificar instantáneamente los cambios realizados desde la última copia de seguridad, independientemente del volumen de datos de los discos duros. En un mundo de discos duros de terabytes, esta funcionalidad es impagable.
Lamentablemente tengo muchas máquinas que no trabajan bajo Solaris, y necesito acomodarlas en mi sistema de backup. Así que hace unos meses decidí emplear una estrategia mixta: rsync junto a ZFS. La idea es la siguiente:
Normalmente "rsync", cuando detecta que un fichero ha cambiado, empieza a descargar la versión nueva de forma incremental, usando para ello el fichero ya existente. Pero dicha versión nueva se descarga con otro nombre y, cuando la descarga se ha completado, se renombra para ocupar el lugar del fichero original.
Usando "--inplace", le decimos a "rsync" que queremos que sobreescriba el fichero original, en vez de crear un fichero nuevo y renombrarlo al final. De esta forma aprovechamos mucho mejor la potencia de los "snapshots" de ZFS.
Las ventajas son muchas:
Algunas desventajas son:
En mi backup mensual tengo un disco externo USB, que está desconectado y en un cajón de mi casa (por si cae un rayo, o hay un incendio o lo que sea). Una vez al mes lo traigo a la oficina (con cuidado) y lo enchufo a mi servidor de backup Solaris. Lo monto como
[root@tesalia /]# zpool import pool: backup id: 15905228473802620720 state: ONLINE action: The pool can be imported using its name or numeric identifier. config: backup ONLINE c3t0d0 ONLINE [root@tesalia /]# zpool import backup
Eso me crea un directorio "/backup" en mi jerarquía de ficheros. Seguidamente ejecuto los scripts de backup mensuales para mis máquinas. Por ejemplo, el script de mi máquina personal es:
rsync --numeric-ids -a -H --inplace --delete --delete-excluded --stats --progress -v --itemize-changes \ --rsync-path=/usr/local/bin/rsync \ --exclude "/proc/**" \ --exclude "/sys/**" \ --exclude "/media/*/**" \ --exclude "/tmp/**" \ --exclude "/home/jcea/.thumbnails/**" \ --exclude "/home/jcea/.googleearth/Cache/*" \ --exclude "/home/jcea/.mozilla/firefox/**/Cache/*" \ --exclude "/home/jcea/mnt/particion_1/k3b_image.iso" \ --exclude "/home/jcea/mnt/particion_1/*.ecc" \ --exclude "/home/jcea/mnt/amule/**" \ --exclude "/home/jcea/mnt/Yolco/**" \ --exclude "/home/jcea/mnt/Cólquide/**" \ --exclude "/home/jcea/mnt/Tesalia/**" \ --exclude "/var/tmp/**" \ / SERVIDOR.BACKUP:/backup/castor/
Esto sincroniza mi disco duro, salvo unos directorios que no me interesan, en el directorio "/backup/castor" del servidor (en realidad, un "dataset"), que se corresponde al disco duro externo. Ese directorio está compuesto, además, por diferentes "datasets": sistema, mi "home", el directorio de imágenes de disco de "virtualBox" y mi directorio de correo. De esta forma, manteniendo "datasets" separados, puedo borrar "snapshots" viejos de mi correo, manteniendo en cambio las imágenes mensuales de "VirtualBox", por ejemplo (que solo ocupan lo que hayan cambiado).
Tener "datasets" separados me permite también, por ejemplo, el desactivar la compresión en el "dataset" de imágenes "VirtualBox", ya que se comprime poco y mal y no quiero consumir CPU para nada. En cambio la compresión es muy útil en mi correo electrónico, por ejemplo. ¡¡Usa varios "datasets" según su perfil de uso y tus necesidades de conservación!!.
Una vez que el backup se ha completado (si se corta o lo que sea, se puede relanzar sin problemas), hacemos un "snapshot" ZFS en el sistema con:
# zfs snapshot -r backup/castor@20091028
Cuando se nos llena el disco duro y hay que borrar "snapshots" antiguos, tiramos de nuestra política particular. En mi caso los backups recientes me interesa quedarme con uno al mes, y los antiguos con uno cada tres meses o, incluso, con uno al año. Por supuesto, cada "dataset" es un caso distinto. No hace falta conservar un histórico detallado del correo electrónico si eres de los que no borra nada, porque en cada versión nueva se mantendrán también los mensajes anteriores.
A la hora de decidir qué backup eliminar, puede ser muy conveniente ver cuánto ocupa cada uno. Lo normal es borrar los más grandes:
# zfs list -r -o name,compressratio,used -s used backup | grep -i @
Una vez que completamos todos los backups, desmontamos/exportamos el disco de backup, lo desenchufamos y nos lo llevamos a casa de nuevo.
# zpool export backup
A la hora de recuperar ficheros puntuales, basta con enchufar el disco duro, importar el "pool" y acceder al "snapshot" ZFS que nos interesa.
Si lo que queremos es recuperar particiones enteras, podemos seguir las instrucciones de indicadas hace tres años.
Como ya he dicho, tengo dos sistemas de backup (en realidad más, pero no son relevantes): diario y mensual. El diario va con "rdiff-backup" y conservo el último par de semanas o así. El mensual iba antes con "rsync" con la opción de "--link-dest", y ahora va con "rsync" con "--inplace" y ZFS. Me interesa migrar estos backups antiguos al sistema nuevo.
El disco de backup mide 500 GB, y me acabo de poner un disco duro de 750 GB en mi máquina, así que puedo copiar los datos de un lado a otro sin problema. Pero copiar 500 gigas en cientos de millones de ficheros enlazados con enlaces "hard" es un proceso que consume mucho tiempo y memoria (el "rsync" debe mantener los inodes en memoria, para localizar los enlaces "hard"), así que decido hacerlo de otra manera:
En vez de copiar los ficheros en el backup externo a mi disco duro interno mediante "cp" o similar (perdiendo la información de enlaces "hard" y expandiendo los datos varios órdenes de magnitud) o mediante "rsync" (que mantiene los enlaces "hard" a costa de gastar memoria para llevar "la cuenta" de los mismos), decido -aprovechando que uso LVM (Logical Volume Manager) en mi Linux- crear un nuevo volumen lógico y copiar el disco duro externo sector a sector. Esto es mucho más rápido que leer fichero a fichero, y no pierde ninguna información:
castor:/home/jcea/mnt/rdiff-backup # fdisk /dev/sdb The number of cylinders for this disk is set to 60563. There is nothing wrong with that, but this is larger than 1024, and could in certain setups cause problems with: 1) software that runs at boot time (e.g., old versions of LILO) 2) booting and partitioning software from other OSs (e.g., DOS FDISK, OS/2 FDISK) Command (m for help): p Disk /dev/sdb: 500.1 GB, 500107862016 bytes 256 heads, 63 sectors/track, 60563 cylinders Units = cylinders of 16128 * 512 = 8257536 bytes Device Boot Start End Blocks Id System /dev/sdb1 1 60563 488380000+ 83 Linux Command (m for help): q castor:/home/jcea/mnt/rdiff-backup # lvcreate -L510G --name backup LVM2 Logical volume "backup" created castor:/home/jcea/mnt/rdiff-backup # dd if=/dev/sdb1 of=/dev/LVM2/backup bs=65536 7630937+1 records in 7630937+1 records out 500101120512 bytes (500 GB) copied, 26824.6 seconds, 18.6 MB/s castor:/home/jcea/mnt/rdiff-backup # mount /dev/LVM2/backup /mnt castor:/home/jcea/mnt/rdiff-backup # cd /mnt/snapshots/ castor:/mnt/snapshots # dir total 73 drwxr-xr-x 72 jcea users 2432 Mar 17 19:10 . drwxrwxrwx 5 root root 160 Mar 17 17:33 .. drwxr-xr-x 22 root root 584 Apr 8 2007 20070410-castor drwxr-xr-x 25 root root 752 Apr 9 2007 20070410-colquide drwxr-xr-x 47 root root 2272 Mar 26 2007 20070410-tesalia drwxr-xr-x 22 root root 648 Jan 18 2007 20070410-yolco drwxr-xr-x 22 root root 584 May 28 2007 20070601-castor drwxr-xr-x 24 root root 728 May 29 2007 20070601-colquide drwxr-xr-x 50 root root 2264 May 30 2007 20070601-tesalia drwxr-xr-x 22 root root 648 May 31 2007 20070601-yolco drwxr-xr-x 22 root root 584 Jun 26 2007 20070701-castor drwxr-xr-x 24 root root 728 Jun 23 2007 20070701-colquide drwxr-xr-x 49 root root 2264 Jun 28 2007 20070701-tesalia drwxr-xr-x 22 root root 648 Jun 22 2007 20070701-yolco drwxr-xr-x 22 root root 584 Sep 3 2007 20070903-castor drwxr-xr-x 24 root root 728 Aug 6 2007 20070903-colquide drwxr-xr-x 49 root root 2304 Jul 31 2007 20070903-tesalia drwxr-xr-x 22 root root 648 Sep 3 2007 20070903-yolco drwxr-xr-x 22 root root 584 Oct 1 2007 20071001-castor drwxr-xr-x 24 root root 728 Aug 6 2007 20071001-colquide drwxr-xr-x 49 root root 2552 Sep 28 2007 20071001-tesalia drwxr-xr-x 22 root root 648 Sep 3 2007 20071001-yolco drwxr-xr-x 22 root root 584 Jan 2 2008 20080103-castor drwxr-xr-x 24 root root 728 Oct 16 2007 20080103-colquide drwxr-xr-x 50 root root 2656 Dec 28 2007 20080103-tesalia drwxr-xr-x 22 root root 648 Dec 4 2007 20080103-yolco drwxr-xr-x 22 root root 584 Jan 25 2008 20080201-castor drwxr-xr-x 24 root root 728 Jan 10 2008 20080201-colquide drwxr-xr-x 51 root root 2704 Feb 1 2008 20080201-tesalia drwxr-xr-x 22 root root 648 Jan 3 2008 20080201-yolco drwxr-xr-x 22 root root 584 Feb 13 2008 20080301-castor drwxr-xr-x 24 root root 728 Jan 10 2008 20080301-colquide drwxr-xr-x 52 root root 2656 Feb 28 2008 20080301-tesalia drwxr-xr-x 22 root root 648 Jan 3 2008 20080301-yolco drwxr-xr-x 22 root root 584 Mar 24 2008 20080401-castor drwxr-xr-x 25 root root 760 Mar 16 2008 20080401-colquide drwxr-xr-x 52 root root 2824 Mar 31 2008 20080401-tesalia drwxr-xr-x 23 root root 680 Mar 15 2008 20080401-yolco drwxr-xr-x 22 root root 584 Apr 4 2008 20080505-castor drwxr-xr-x 25 root root 760 Mar 16 2008 20080505-colquide drwxr-xr-x 52 root root 2880 May 1 2008 20080505-tesalia drwxr-xr-x 23 root root 680 Mar 15 2008 20080505-yolco drwxr-xr-x 22 root root 584 Apr 4 2008 20080602-castor drwxr-xr-x 25 root root 760 May 14 2008 20080602-colquide drwxr-xr-x 54 root root 2896 Jun 1 2008 20080602-tesalia drwxr-xr-x 23 root root 680 May 14 2008 20080602-yolco drwxr-xr-x 22 root root 584 Jun 25 2008 20080701-castor drwxr-xr-x 25 root root 736 Jun 23 2008 20080701-colquide drwxr-xr-x 54 root root 2992 Jun 30 2008 20080701-tesalia drwxr-xr-x 23 root root 680 Jun 12 2008 20080701-yolco drwxr-xr-x 22 root root 584 Sep 1 2008 20080905-castor drwxr-xr-x 25 root root 736 Aug 7 2008 20080905-colquide drwxr-xr-x 54 root root 3080 Sep 3 2008 20080905-tesalia drwxr-xr-x 23 root root 680 Sep 1 2008 20080905-yolco drwxr-xr-x 22 root root 584 Nov 4 19:47 20081104-castor drwxr-xr-x 25 root root 736 Oct 6 21:43 20081104-colquide drwxr-xr-x 54 root root 3408 Nov 4 20:54 20081104-tesalia drwxr-xr-x 23 root root 680 Oct 2 22:43 20081104-yolco drwxr-xr-x 22 root root 584 Nov 4 19:47 20081201-castor drwxr-xr-x 25 root root 736 Oct 6 21:43 20081201-colquide drwxr-xr-x 56 root root 3552 Nov 24 18:04 20081201-tesalia drwxr-xr-x 23 root root 680 Oct 2 22:43 20081201-yolco drwxr-xr-x 22 root root 584 Dec 9 00:50 20090102-castor drwxr-xr-x 25 root root 736 Dec 12 01:13 20090102-colquide drwxr-xr-x 56 root root 3552 Dec 29 18:37 20090102-tesalia drwxr-xr-x 23 root root 680 Dec 12 02:26 20090102-yolco drwxr-xr-x 22 root root 584 Dec 9 00:50 20090202-castor drwxr-xr-x 25 root root 736 Dec 12 01:13 20090202-colquide drwxr-xr-x 56 root root 3552 Feb 2 17:44 20090202-tesalia drwxr-xr-x 23 root root 680 Dec 12 02:26 20090202-yolco
Aquí podemos ver que comprobamos el tamaño del disco duro externo, seguidamente creamos un volumen lógico lo bastante grande como para contenerlo, y luego copiamos el disco "a lo bestia", sector a sector. Por último comprobamos que, efectivamente, los datos están en el disco duro.
A continuación desenchufamos el disco duro externo de backup y lo conectamos al servidor de backup. Hay que localizarlo en sus USBs:
[root@tesalia z2]# cfgadm Ap_Id Type Receptacle Occupant Condition sata0/0::dsk/c1d0 disk connected configured ok sata0/1::dsk/c5t1d0 disk connected configured ok sata1/0 sata-port empty unconfigured ok sata1/1 sata-port empty unconfigured ok usb0/1 unknown empty unconfigured ok usb0/2 unknown empty unconfigured ok usb0/3 unknown empty unconfigured ok usb0/4 unknown empty unconfigured ok usb0/5 unknown empty unconfigured ok usb0/6 unknown empty unconfigured ok usb0/7 unknown empty unconfigured ok usb0/8 unknown empty unconfigured ok usb1/1 unknown empty unconfigured ok usb1/2 unknown empty unconfigured ok usb1/3 unknown empty unconfigured ok usb1/4 unknown empty unconfigured ok usb1/5 unknown empty unconfigured ok usb1/6 unknown empty unconfigured ok usb1/7 usb-storage connected configured ok usb1/8 unknown empty unconfigured ok [root@tesalia /]# iostat -En c0t0d0 Soft Errors: 2 Hard Errors: 0 Transport Errors: 0 Vendor: MATSHITA Product: DVD-ROM SR-8178 Revision: PZ16 Serial No: Size: 0.00GB <0 bytes> Media Error: 0 Device Not Ready: 0 No Device: 0 Recoverable: 0 Illegal Request: 2 Predictive Failure Analysis: 0 c3t0d0 Soft Errors: 2 Hard Errors: 0 Transport Errors: 0 Vendor: ST350063 Product: 0AS Revision: Serial No: Size: 500.11GB <500107862016 bytes> Media Error: 0 Device Not Ready: 0 No Device: 0 Recoverable: 0 Illegal Request: 2 Predictive Failure Analysis: 0 c5t0d0 Soft Errors: 8 Hard Errors: 0 Transport Errors: 0 Vendor: ATA Product: ST3250823AS Revision: 3.03 Serial No: Size: 250.06GB <250059349504 bytes> Media Error: 0 Device Not Ready: 0 No Device: 0 Recoverable: 0 Illegal Request: 8 Predictive Failure Analysis: 0 c5t1d0 Soft Errors: 8 Hard Errors: 0 Transport Errors: 0 Vendor: ATA Product: WDC WD7500AAKS-0 Revision: 4G30 Serial No: Size: 750.16GB <750156373504 bytes> Media Error: 0 Device Not Ready: 0 No Device: 0 Recoverable: 0 Illegal Request: 8 Predictive Failure Analysis: 0 [root@tesalia /]# rmformat Looking for devices... 1. Logical Node: /dev/rdsk/c0t0d0p0 Physical Node: /pci@0,0/pci-ide@6/ide@0/sd@0,0 Connected Device: MATSHITA DVD-ROM SR-8178 PZ16 Device Type: DVD Reader 2. Logical Node: /dev/rdsk/c3t0d0p0 Physical Node: /pci@0,0/pci108e,5348@2,1/storage@7/disk@0,0 Connected Device: ST350063 0AS Device Type: Removable [root@tesalia /]# zpool create backup c3t0d0 [root@tesalia /]# zpool list backup NAME SIZE USED AVAIL CAP HEALTH ALTROOT backup 464G 94K 464G 0% ONLINE - [root@tesalia backup]# zfs set compression=gzip-9 backup [root@tesalia colquide]# zfs set atime=off backup [root@tesalia colquide]# zfs create backup/reserva_de_espacio-NO_USAR [root@tesalia colquide]# zfs set reservation=64M backup/reserva_de_espacio-NO_USAR
Localizamos el disco duro externo y creamos el "pool" ZFS "backup" en él. Obviamente estos pasos solo son necesarios la primera vez. Una vez creado el "pool", lo activamos y desactivamos con "zpool import" y "zpool export", y Solaris ya se encarga de buscar el "pool" en cuestión entre todos los discos duros conectados, locales o externos.
Activamos la compresión más agresiva y desactivamos el "atime", que no tiene sentido para backups y que nos permitirá ahorrar algo de espacio (si el "atime" no se modifica, no hace falta guardar una copia en los "snapshots") y de tiempo al hacer el backup (porque no hay que actualizar los "atimes" en el disco duro).
Obsérvese que creo un "dataset" con una reserva de espacio. Esto es así porque ZFS es un sistema de ficheros COW (Copy On Write), y requiere espacio extra (durante un momento) para cosas como borrar un fichero. Es decir, que si tenemos el disco absolutamente lleno y queremos borrar un fichero, no podremos, porque no tenemos espacio para el COW correspondiente. Reservando un poco de espacio (despreciable frente al total) desde el principio, nos despreocupamos de ésto. Es posible que las versiones recientes de ZFS ya no tengan este problema, pero mejor curarse en salud.
A continuación crearíamos los "datasets" correspondientes, en este caso uno por máquina protegida:
[root@tesalia backup]# zfs create backup/tesalia [root@tesalia backup]# zfs create backup/yolco [root@tesalia backup]# zfs create backup/colquide
Mi máquina personal es un caso especial, porque me interesa tener diferentes "datasets" con diferentes políticas:
[root@tesalia backup]# zfs create backup/castor [root@tesalia backup]# zfs create backup/castor/jcea [root@tesalia backup]# zfs mountpoint=/backup/castor/home/jcea backup/castor/jcea [root@tesalia backup]# zfs create backup/castor/jcea/correo [root@tesalia backup]# zfs mountpoint=/backup/castor/home/jcea/.thunderbird backup/castor/jcea/correo [root@tesalia backup]# zfs create backup/castor/jcea/virtualbox [root@tesalia backup]# zfs set mountpoint=/backup/castor/home/jcea/mnt/virtualbox backup/castor/jcea/virtualbox [root@tesalia backup]# zfs set compression=off backup/castor/jcea/virtualbox
Una vez creada la estructura, copiamos los backups viejos, en mi ordenador, al sistema nuevo. Usamos "rsync":
castor:/mnt/snapshots # rsync -a -H --delete --numeric-ids --stats --progress \ --force --rsync-path=/usr/local/bin/rsync \ --exclude rdiff-backup-data --inplace \ 20070410-colquide/ SERVIDOR.BACKUP:/backup/colquide/
A medida que vamos moviendo cada versión vieja de los backups, hacemos "snapshot" ZFS en el servidor:
[root@tesalia backup]# zfs snapshot -r backup/colquide@20070410
Una vez que terminamos de mover todos los backups, desmontamos el "pool":
[root@tesalia /]# zpool export backup
En mi máquina destruyo el volumen lógico que contiene el backup histórico que ya hemos convertido:
castor:/ # lvremove /dev/LVM2/backup Do you really want to remove active logical volume "backup"? [y/n]: y Logical volume "backup" successfully removed
Más información sobre los OpenBadges
Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS