¿Mi comando para clonar una unidad es óptimo?


16

He leído media hora para prepararme para clonar mi disco duro. Tiene múltiples particiones, incluida una partición de Windows. Voy a comprar un disco duro externo muy grande para la copia de seguridad. Me gustaría poder usar este clon para restaurar todo el disco en caso de que algo salga mal (estoy a punto de volver a barajar el sistema operativo). Quiero aprender a hacer esto usando dd, ya que me gustan las herramientas de bajo nivel que no requieren instalar nada.

Encontré el siguiente código útil de los foros de ubuntu (ingresado desde un shell raíz usando un CD en vivo):

dd if=/dev/hda of=/dev/hdb & pid=$!
while kill -USR1 $pid; do sleep 1; done

(Sé que tendré que editar las ubicaciones de entrada y salida). Sin embargo, tengo dos preguntas. El primero es muy novato: este comando se divide en dos líneas. ¿Seguramente cuando presione enter después del signo de exclamación comenzará el proceso?

Dos, en otros sitios, recomendó ingresar el tamaño del bloque. Me gusta esto:

# dd if=/dev/hda conv=sync,noerror bs=64K of=/mnt/sda1/hda.img

No sé nada sobre los tamaños de bloque. ¿Tiene razón 64K? Parece que mi tamaño de bloque es de 512 bytes de lo siguiente, la salida de sudo fdisk -ul:

Disk /dev/sda: 750.2 GB, 750156374016 bytes
255 heads, 63 sectors/track, 91201 cylinders, total 1465149168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disk identifier: 0xc3ffc3ff

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *          63   143364059    71681998+   7  HPFS/NTFS/exFAT
Partition 1 does not start on physical sector boundary.
/dev/sda2       976867328  1465147391   244140032    7  HPFS/NTFS/exFAT
/dev/sda3       143364094   976867327   416751617    5  Extended
Partition 3 does not start on physical sector boundary.
/dev/sda5       143364096   162895871     9765888   82  Linux swap / Solaris
/dev/sda6       162897920   205864959    21483520   83  Linux
/dev/sda7       205867008   976867327   385500160   83  Linux

Partition table entries are not in disk order

Disk /dev/mapper/cryptswap1: 10.0 GB, 10000269312 bytes
255 heads, 63 sectors/track, 1215 cylinders, total 19531776 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disk identifier: 0x433bb3a7

Disk /dev/mapper/cryptswap1 doesn't contain a valid partition table

Gracias.


¿Has probado un simple dd if=/dev/hda of=hdb? Aquí hay una respuesta que muestra algunos detalles, incluido el tiempo de ejecución para 160 GB: askubuntu.com/questions/435694/…
SDsolar

Las versiones recientes de Ubuntu utilizan coreutils v.8.24 o posterior, que ddincluye un interruptor de progreso como se menciona aquí
Elder Geek

Respuestas:


22

Progreso

El comando que enumeraste

dd if=/dev/hda of=/dev/hdb & pid=$!
while kill -USR1 $pid; do sleep 1; done

Es un buen dos líneas para obtener el progreso de ddforma regular. Yo también uso uno muy similar. Se ve bien. ¿Lo encontraste aquí quizás?

Blocksizes con dd: alineación y rendimiento

Puede agregar un tamaño de bloque en el que tienen lugar las operaciones. No importa cuál sea el tamaño de bloque del dispositivo de bloque subyacente para que la operación se realice igualmente bien, pero por razones de rendimiento, es posible que desee elegir uno que se adapte a sus necesidades.

En primer lugar, está la cosa de la alineación . En caso de que su dispositivo de bloque funcione como 512 KB (como lo hacen las unidades flash), sería muy desafortunado ejecutar ddcon bs=512(bytes) ya que esto causará 1024 escrituras (!) Para cada bloque desde la perspectiva del dispositivo. En la práctica, no será tan malo ya que las escrituras se almacenan temporalmente y se almacenan de una vez, pero durante las sincronizaciones aún puede amplificar mucho la cantidad de escrituras.

Luego, también considere la sobrecarga de uso de CPU simple cuando se trata de una gran cantidad de pequeñas operaciones. Es más eficiente tomar megabytes a la vez cuando se copian grandes cantidades de datos.

Mi mejor práctica es comenzar con 1 MB, ya que es un buen múltiplo de la mayoría de las configuraciones, incluidos los tamaños de banda RAID, los tamaños de extensión LVM, etc. En mi computadora portátil con SSD, tiendo a ver una ligera mejora usando 10 MB como tamaño de bloque, mientras que yo ya no lo veo en mi disco duro físico.

Ultimo bloque

No se preocupe si el tamaño de la unidad / volumen no es un múltiplo del tamaño del bloque. El último bloque que ddse copiará se ajustará para que coincida con el último bit de datos que contiene. Puede ver si el último bloque tenía un tamaño diferente mirando la salida.

18335302+0 records out

Los +0medios que se trataba de una coincidencia exacta, unos +1medios que no lo era. No es gran cosa.

Ver también


1
Wow, qué respuesta tan completa. Muchas gracias por tomarse el tiempo para hacerlo. Actualizaré la pregunta original con un enlace a mi fuente. Iré con 1 MB entonces. Entonces mi comando será así, ¿estoy en lo cierto? # dd if=/dev/hda conv=sync,noerror bs=1MB of=/mnt/sda1/hda.img & pid=$! while kill -USR1 $pid; do sleep 1; done
Kit Johnson

2
@oldmankit lo haría, bs=1Mya que es una potencia de 2, en lugar de bs=1MBuna potencia de 10. Pero solo puede ejecutar algunos puntos de referencia en su sistema si puede ver cuál es el mejor.
gertvdijk

44
Tenga en cuenta que, como se menciona aquí desde el lanzamiento de coreutils> = 8.24 (predeterminado en Ubuntu Xenial 16.04 hacia arriba) ya no es necesario kill -USR1 $piddd ahora tiene un informe de progreso disponible al agregar el status=progressinterruptor
Elder Geek

10

Como han dicho otros, no hay un tamaño de bloque universalmente correcto; lo que es óptimo para una situación o una pieza de hardware puede ser terriblemente ineficiente para otra. Además, dependiendo de la salud de los discos, puede ser preferible usar un tamaño de bloque diferente al que es "óptimo".

Una cosa que es bastante confiable en el hardware moderno es que el tamaño de bloque predeterminado de 512 bytes tiende a ser casi un orden de magnitud más lento que una alternativa más óptima. En caso de duda, descubrí que 64K es un valor predeterminado moderno bastante sólido. Aunque 64K generalmente no es EL tamaño de bloque óptimo, en mi experiencia tiende a ser mucho más eficiente que el predeterminado. 64K también tiene un historial bastante sólido de rendimiento confiable: puede encontrar un mensaje de la lista de correo Eug-Lug , alrededor de 2002, que recomienda un tamaño de bloque de 64K.

Para determinar EL tamaño de bloque de salida óptimo, he escrito el siguiente script que prueba escribir un archivo de prueba de 128M con dd en un rango de diferentes tamaños de bloque, desde el predeterminado de 512 bytes hasta un máximo de 64M. Tenga en cuenta que este script usa dd internamente, así que úselo con precaución.

dd_obs_test.sh:

#!/bin/bash

# Since we're dealing with dd, abort if any errors occur
set -e

TEST_FILE=${1:-dd_obs_testfile}
TEST_FILE_EXISTS=0
if [ -e "$TEST_FILE" ]; then TEST_FILE_EXISTS=1; fi
TEST_FILE_SIZE=134217728

if [ $EUID -ne 0 ]; then
  echo "NOTE: Kernel cache will not be cleared between tests without sudo. This will likely cause inaccurate results." 1>&2
fi

# Header
PRINTF_FORMAT="%8s : %s\n"
printf "$PRINTF_FORMAT" 'block size' 'transfer rate'

# Block sizes of 512b 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M 2M 4M 8M 16M 32M 64M
for BLOCK_SIZE in 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864
do
  # Calculate number of segments required to copy
  COUNT=$(($TEST_FILE_SIZE / $BLOCK_SIZE))

  if [ $COUNT -le 0 ]; then
    echo "Block size of $BLOCK_SIZE estimated to require $COUNT blocks, aborting further tests."
    break
  fi

  # Clear kernel cache to ensure more accurate test
  [ $EUID -eq 0 ] && [ -e /proc/sys/vm/drop_caches ] && echo 3 > /proc/sys/vm/drop_caches

  # Create a test file with the specified block size
  DD_RESULT=$(dd if=/dev/zero of=$TEST_FILE bs=$BLOCK_SIZE count=$COUNT conv=fsync 2>&1 1>/dev/null)

  # Extract the transfer rate from dd's STDERR output
  TRANSFER_RATE=$(echo $DD_RESULT | \grep --only-matching -E '[0-9.]+ ([MGk]?B|bytes)/s(ec)?')

  # Clean up the test file if we created one
  if [ $TEST_FILE_EXISTS -ne 0 ]; then rm $TEST_FILE; fi

  # Output the result
  printf "$PRINTF_FORMAT" "$BLOCK_SIZE" "$TRANSFER_RATE"
done

Ver en GitHub

Solo probé este script en un sistema Debian (Ubuntu) y en OSX Yosemite, por lo que probablemente tomará algunos ajustes para que funcione en otros sabores de Unix.

Por defecto, el comando creará un archivo de prueba nombrado dd_obs_testfileen el directorio actual. Alternativamente, puede proporcionar una ruta a un archivo de prueba personalizado proporcionando una ruta después del nombre del script:

$ ./dd_obs_test.sh /path/to/disk/test_file

El resultado del script es una lista de los tamaños de bloque probados y sus respectivas tasas de transferencia de la siguiente manera:

$ ./dd_obs_test.sh
block size : transfer rate
       512 : 11.3 MB/s
      1024 : 22.1 MB/s
      2048 : 42.3 MB/s
      4096 : 75.2 MB/s
      8192 : 90.7 MB/s
     16384 : 101 MB/s
     32768 : 104 MB/s
     65536 : 108 MB/s
    131072 : 113 MB/s
    262144 : 112 MB/s
    524288 : 133 MB/s
   1048576 : 125 MB/s
   2097152 : 113 MB/s
   4194304 : 106 MB/s
   8388608 : 107 MB/s
  16777216 : 110 MB/s
  33554432 : 119 MB/s
  67108864 : 134 MB/s

(Nota: la unidad de las tasas de transferencia variará según el sistema operativo)

Para probar el tamaño óptimo del bloque de lectura, podría usar más o menos el mismo proceso, pero en lugar de leer /dev/zeroy escribir en el disco, leería desde el disco y escribiría /dev/null. Un script para hacer esto podría verse así:

dd_ibs_test.sh:

#!/bin/bash

# Since we're dealing with dd, abort if any errors occur
set -e

TEST_FILE=${1:-dd_ibs_testfile}
if [ -e "$TEST_FILE" ]; then TEST_FILE_EXISTS=$?; fi
TEST_FILE_SIZE=134217728

# Exit if file exists
if [ -e $TEST_FILE ]; then
  echo "Test file $TEST_FILE exists, aborting."
  exit 1
fi
TEST_FILE_EXISTS=1

if [ $EUID -ne 0 ]; then
  echo "NOTE: Kernel cache will not be cleared between tests without sudo. This will likely cause inaccurate results." 1>&2
fi

# Create test file
echo 'Generating test file...'
BLOCK_SIZE=65536
COUNT=$(($TEST_FILE_SIZE / $BLOCK_SIZE))
dd if=/dev/urandom of=$TEST_FILE bs=$BLOCK_SIZE count=$COUNT conv=fsync > /dev/null 2>&1

# Header
PRINTF_FORMAT="%8s : %s\n"
printf "$PRINTF_FORMAT" 'block size' 'transfer rate'

# Block sizes of 512b 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M 2M 4M 8M 16M 32M 64M
for BLOCK_SIZE in 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864
do
  # Clear kernel cache to ensure more accurate test
  [ $EUID -eq 0 ] && [ -e /proc/sys/vm/drop_caches ] && echo 3 > /proc/sys/vm/drop_caches

  # Read test file out to /dev/null with specified block size
  DD_RESULT=$(dd if=$TEST_FILE of=/dev/null bs=$BLOCK_SIZE 2>&1 1>/dev/null)

  # Extract transfer rate
  TRANSFER_RATE=$(echo $DD_RESULT | \grep --only-matching -E '[0-9.]+ ([MGk]?B|bytes)/s(ec)?')

  printf "$PRINTF_FORMAT" "$BLOCK_SIZE" "$TRANSFER_RATE"
done

# Clean up the test file if we created one
if [ $TEST_FILE_EXISTS -ne 0 ]; then rm $TEST_FILE; fi

Ver en GitHub

Una diferencia importante en este caso es que el archivo de prueba es un archivo escrito por el script. ¡No apunte este comando a un archivo existente o el archivo existente se sobrescribirá con datos aleatorios!

Para mi hardware en particular, descubrí que 128K era el tamaño de bloque de entrada más óptimo en un HDD y 32K era más óptimo en un SSD.

Aunque esta respuesta cubre la mayoría de mis hallazgos, he necesitado determinar un tamaño de bloque dd óptimo suficientes veces que escribí una publicación de blog al respecto. Puede encontrar más detalles sobre las pruebas que realicé allí.

Esta publicación de StackOverflow también puede ser útil: dd: ¿Cómo calcular el tamaño de bloque óptimo?


Enseñar a un hombre a pescar = +1
HackSlash

@ tdg5 Este es un gran script, pero se encuentra con errores fatales cuando se ejecuta desde Cygwin en un entorno Windows 7. ¿Hay alguna versión que funcione en Cygwin?
Hashim
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.