Ma commande pour cloner un lecteur est-elle optimale?

16

J'ai fait une demi-heure de lecture pour me préparer à cloner mon disque dur. Il a plusieurs partitions, dont une partition Windows. Je vais acheter un très gros disque dur externe pour la sauvegarde. J'aimerais pouvoir utiliser ce clone pour restaurer l'intégralité du disque en cas de problème (je suis sur le point de faire un remaniement du système d'exploitation). Je veux apprendre à le faire en utilisant dd, car j'aime les outils de bas niveau qui ne nécessitent rien d'installation.

J'ai trouvé le code utile suivant sur les forums ubuntu (entré à partir d'un shell racine à l'aide d'un CD live):

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

(Je sais que je devrai modifier les emplacements d'entrée et de sortie.) Cependant, j'ai deux questions. La première est très noobie: cette commande est répartie sur deux lignes. Sûrement, lorsque j'appuierai sur Entrée après le point d'exclamation, cela lancera le processus?

Deuxièmement, sur d'autres sites, il a recommandé de saisir la taille du bloc. Comme ça:

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

Je ne connais rien à la taille des blocs. 64K a-t-il raison? Il semble que ma taille de bloc soit de 512 octets à partir de ce qui suit, la sortie 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

Je vous remercie.

Kit Johnson
la source
Avez-vous essayé un simple dd if=/dev/hda of=hdb? Voici une réponse qui montre quelques détails, y compris le temps d'exécution pour 160 Go: askubuntu.com/questions/435694/…
SDsolar
Les versions récentes d'Ubuntu utilisent coreutils v.8.24 ou version ultérieure, qui ddinclut un commutateur de progression comme mentionné ici
Elder Geek

Réponses:

22

Le progrès

La commande que vous avez répertoriée

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

est un joli bi-liner pour suivre la progression de ddfaçon régulière. J'en utilise aussi un très similaire. Cela semble bon. Je l'ai trouvé ici peut-être?

Blocksizes avec dd : alignement et performance

Vous pouvez ajouter une taille de bloc dans laquelle les opérations ont lieu. Peu importe la taille de bloc du périphérique de bloc sous-jacent pour que l'opération se déroule aussi bien, mais pour des raisons de performances, vous pouvez choisir celui qui convient à vos besoins.

Tout d'abord, il y a la chose d'alignement . Dans le cas où votre périphérique de bloc fonctionne comme 512 Ko (comme le font les lecteurs flash), il serait très malheureux de fonctionner ddavec bs=512(octets) car cela entraînera 1024 écritures (!) Pour chaque bloc du point de vue du périphérique. En pratique, ce ne sera pas si grave que les écritures sont mises en mémoire tampon et prises en une seule fois, mais pendant les synchronisations, cela peut encore amplifier le nombre d'écritures.

Tenez également compte de la surcharge d'utilisation du processeur lorsque vous traitez une très grande quantité de petites opérations. Il est juste plus efficace de prendre des mégaoctets à la fois lors de la copie de grandes quantités de données.

Ma meilleure pratique est de commencer avec 1 Mo car c'est un bon multiple de la plupart des configurations, y compris les tailles de bande RAID, les tailles d'étendue LVM, etc. Sur mon ordinateur portable avec SSD, j'ai tendance à voir une légère amélioration en utilisant 10 Mo comme taille de bloc, alors que je ne le vois plus sur mon disque dur physique.

Dernier bloc

Ne vous inquiétez pas si la taille du lecteur / volume n'est pas un multiple de la taille du bloc. Le dernier bloc ddcopié sera ajusté pour correspondre au dernier bit de données qu'il contient. Vous pouvez voir si le dernier bloc avait une taille différente en regardant la sortie.

18335302+0 records out

Les +0moyens qu'il était une correspondance exacte, un +1moyen qu'il était pas. Pas grave.

Voir également

gertvdijk
la source
1
Wow, quelle réponse complète. Merci beaucoup d'avoir pris le temps de le faire. Je mettrai à jour la question d'origine avec un lien vers ma source. J'irai alors avec 1 Mo. Donc ma commande sera comme ça, ai-je raison? # 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 du
2
@oldmankit Je ferais bs=1Mcomme c'est une puissance de 2, plutôt que d' bs=1MBêtre une puissance de 10. Mais lancez juste quelques repères sur votre système si vous pouvez voir ce qui est le meilleur.
gertvdijk
4
Notez que comme mentionné ici depuis la sortie de coreutils> = 8.24 (par défaut dans Ubuntu Xenial 16.04 vers le haut), il n'est plus nécessaire de kill -USR1 $piddd a maintenant un rapport d'avancement disponible en ajoutant le status=progresscommutateur
Elder Geek
10

Comme d'autres l'ont dit, il n'y a pas de taille de bloc universellement correcte; ce qui est optimal pour une situation ou une pièce de matériel peut être terriblement inefficace pour une autre. En outre, en fonction de la santé des disques, il peut être préférable d'utiliser une taille de bloc différente de celle qui est "optimale".

Une chose qui est assez fiable sur le matériel moderne est que la taille de bloc par défaut de 512 octets a tendance à être presque un ordre de grandeur plus lente qu'une alternative plus optimale. En cas de doute, j'ai trouvé que 64K est un défaut moderne assez solide. Bien que 64 Ko ne soit généralement pas LA taille de bloc optimale, d'après mon expérience, il a tendance à être beaucoup plus efficace que la valeur par défaut. 64K a également une histoire assez solide d'être performant de manière fiable: vous pouvez trouver un message dans la liste de diffusion Eug-Lug , vers 2002, recommandant une taille de bloc de 64K.

Pour déterminer LA taille de bloc de sortie optimale, j'ai écrit le script suivant qui teste l'écriture d'un fichier de test de 128M avec dd à une plage de tailles de bloc différentes, de la valeur par défaut de 512 octets à un maximum de 64M. Soyez averti, ce script utilise dd en interne, alors utilisez-le avec prudence.

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

Voir sur GitHub

J'ai seulement testé ce script sur un système Debian (Ubuntu) et sur OSX Yosemite, donc il faudra probablement quelques ajustements pour faire fonctionner les autres versions d'Unix.

Par défaut, la commande crée un fichier de test nommé dd_obs_testfiledans le répertoire courant. Vous pouvez également fournir un chemin d'accès à un fichier de test personnalisé en fournissant un chemin d'accès après le nom du script:

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

La sortie du script est une liste des tailles de blocs testées et leurs taux de transfert respectifs comme suit:

$ ./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

(Remarque: L'unité des taux de transfert variera selon le système d'exploitation)

Pour tester la taille optimale du bloc de lecture, vous pouvez utiliser plus ou moins le même processus, mais au lieu de lire /dev/zeroet d'écrire sur le disque, vous devez lire à partir du disque et écrire /dev/null. Un script pour ce faire pourrait ressembler à ceci:

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

Voir sur GitHub

Une différence importante dans ce cas est que le fichier de test est un fichier écrit par le script. Ne pointez pas cette commande sur un fichier existant ou le fichier existant sera écrasé avec des données aléatoires!

Pour mon matériel particulier, j'ai trouvé que 128K était la taille de bloc d'entrée la plus optimale sur un disque dur et 32K était la plus optimale sur un SSD.

Bien que cette réponse couvre la plupart de mes conclusions, j'ai dû déterminer une taille de bloc dd optimale suffisamment de fois pour écrire un blog à ce sujet. Vous pouvez trouver plus de détails sur les tests que j'ai effectués là-bas.

Ce post StackOverflow peut également être utile: dd: Comment calculer la taille de bloc optimale?

tdg5
la source
Apprenez à un homme à pêcher = +1
HackSlash
@ tdg5 Il s'agit d'un excellent script, mais il rencontre des erreurs fatales lorsqu'il est exécuté à partir de Cygwin sur un environnement Windows 7. Y en a-t-il une version qui fonctionnera sur Cygwin?
Hashim