从硬盘到硬盘的完整 DD 复制

osh*_*nen 44 dd cloning hard-disk

原问题:

如果我有2 个具有以下特征的相同硬盘

  • SATA 6.0 Gb/秒
  • 5400转
  • 3TB

完整的 dd 副本需要多长时间才能完成?

到目前为止,它已经运行了 5 个小时,但仍在继续……

我使用的是 Linux Ubuntu 12.04 64bit,我使用的命令是:

dd if=/dev/sdb of=/dev/sdc
Run Code Online (Sandbox Code Playgroud)

更新:1

我现在可以看到进度了,复制 430GB 已经超过 6 个小时了。硬盘是3TB...

没有更快的方法吗?


更新:2

这似乎是很多比以前(感谢更好Groxxda建议):

sudo dd if=/dev/sdb bs=128K | pv -s 3000G | sudo dd of=/dev/sdc bs=128K
Run Code Online (Sandbox Code Playgroud)

3TB 的 ETA 大约需要 9 小时,而在 6 小时后达到 430GB 之前,我猜使用前面的命令大约需要 36 小时。

Gil*_*il' 70

dd在过去人们使用磁带(当块大小很重要时)以及更简单的工具(例如cat可能不是二进制安全的)时很有用。

如今,dd if=/dev/sdb of=/dev/sdc只是一种复杂、容易出错、缓慢的写作方式cat /dev/sdb >/dev/sdc。虽然dd对于一些相对罕见的任务仍然有用,但它的用处远不如提到它的教程数量会让您相信。没有魔法在dd,魔法全在/dev/sdb

你的新命令sudo dd if=/dev/sdb bs=128K | pv -s 3000G | sudo dd of=/dev/sdc bs=128K再次不必要地缓慢和复杂。一次读取 128kB 的数据(这比dd默认的 512B 好,但不如更大的值)。然后在写入之前通过两个管道。

使用更简单、更快的cat命令。(在我几年前在 Linux 下进行的一些基准测试中catcp在不同磁盘之间复制cp要快,并且比dd任何块大小dd都快;当复制到同一个磁盘时,大块大小稍微快一些。)

cat /dev/sdb >/dev/sdc
Run Code Online (Sandbox Code Playgroud)

如果要在 中运行此命令sudo,则需要以 root 身份进行重定向:

sudo sh -c 'cat /dev/sdb >/dev/sdc'
Run Code Online (Sandbox Code Playgroud)

如果您想要一份进度报告,因为您使用的是 Linux,您可以通过记录cat进程的 PID (比如 1234)并查看其输入(或输出)文件描述符的位置来轻松获得。

# cat /proc/1234/fdinfo/0
pos:    64155648 
flags:  0100000
Run Code Online (Sandbox Code Playgroud)

如果你想有一个进度报告和您的UNIX系统没有提供一种简单的方法来获得在文件描述符的位置,就可以安装和使用pv代替cat

  • @Gilles,为了获得进度报告,我是否使用 `sudo sh -c 'pv /dev/sdb >/dev/sdc'` 而不是 `sudo sh -c 'cat /dev/sdb >/dev/sdc'` ? (2认同)
  • @oshirowanen 是的,在需要使用“cat”的地方使用“pv”。 (2认同)

fro*_*utz 10

dd默认情况下使用非常小的块大小(512 字节)。这会导致大量开销(每 512 个字节一个read()write()系统调用)。

当您使用更大的块大小时,它会快得多。最佳速度开始于bs=64k左右。大多数人使用更大的,bs=1M所以它变得人类可读(当dd说它被复制时1234 blocks,你知道它1234 MiB没有做任何数学运算)。使用更大的块大小不太可能导致速度提高,只会增加内存消耗。

所以命令应该是:

dd bs=1M if=/dev/sdb of=/dev/sdc
Run Code Online (Sandbox Code Playgroud)

如果您的dd运行速度已经很慢,您可以中断它并使用更快的dd实例继续运行。为此,重要的是要知道复制已经进行了多远。dd通常在您取消它时打印进度,或者您可以USR1在它运行时向它发送信号以使其打印其进度。

kill -USR1 $(pidof dd)
Run Code Online (Sandbox Code Playgroud)

例如,如果它复制了多个1234MiB,您可以1234MiB使用以下命令在位置恢复:

dd bs=1M seek=1234 skip=1234 if=/dev/sdb of=/dev/sdc
Run Code Online (Sandbox Code Playgroud)

如果复制的数量少于1234MiB,您的副本将不完整。如果它复制了超过1234MiB,它会重新复制一些已经复制的部分,这通常不会造成任何伤害。因此,如果有疑问,您应该选择一个比您认为已经复制的值略小的值。


gro*_*xda 6

获取有关正在进行的 dd 进程的统计信息

您可以使用kill带有适当信号的命令将dd输出统计为标准错误。
从 GNU dd 手册页:

Sending a USR1 signal to a running 'dd' process makes it print I/O statistics to standard error and then resume copying.
      $ dd if=/dev/zero of=/dev/null& pid=$!
      $ kill -USR1 $pid
      18335302+0 records in 18335302+0 records out 9387674624 bytes (9.4 GB)  copied,  34.6279 seconds, 271 MB/s
Run Code Online (Sandbox Code Playgroud)

确保首先检查您的手册页以获取正确的信号,因为它在不同的 dd 实现上可能有所不同:(BSD dd 使用 SIGINFO)。

加快进程

  1. 将每个 HDD 连接到它自己的 SATA 端口,这样数据就可以从一个设备读取并同时写入另一个设备。
  2. 使用bs=参数使用适当的块大小。看看这个关于超级用户的线程并为自己尝试一些值。
  3. 使用单独的dd调用进行读取和写入,并使用管道将它们连接起来 ( dd if=/dev/sda bs=1M | dd of=/dev/sdb bs=1M)。
    如果您这样做并指定块大小,请确保在每次调用时使用相同的块大小。
  4. 您可以尝试其他优化,如direct参数。
  5. 确保您的硬盘未安装,否则可能会导致副本损坏。