我有一块 320GB 的硬盘,它有坏扇区,并且由于读取错误而导致磁盘故障,报告通过。为了尽可能多地保存数据,我想在这个磁盘上smartctl
执行dd
/ 。ddrescue
ddrescue
默认设置(300kB/s)下的读取速度从一开始就非常慢,而且我也没时间尝试其他设置,所以就选择了。关于如何提升 ddrescue 速度dd
的话题,暂时先不谈。
我使用dd
命令,复制到具有 >1TB 可用空间的 SSD:
dd if=/dev/sda of=recovery.img conv=noerror,sync iflag=fullblock status=progress
问题是,时间越长dd
,速度就越慢。一开始速度是 10MB/s,然后迅速降到 5MB/s,并且持续变慢。读取坏块时速度变慢并出现读取错误是可以理解的,但速度却始终无法恢复,即使在读取了好几 GB 的数据后仍然没有任何错误。示例输出:
36571460608 bytes (37 GB, 34 GiB) copied, 7521 s, 4.9 MB/s
dd: error reading '/dev/sda': Input/output error
71428640+0 records in
71428640+0 records out
36571463680 bytes (37 GB, 34 GiB) copied, 7522.87 s, 4.9 MB/s
[a lot of read errors here]
163873310720 bytes (164 GB, 153 GiB) copied, 55200 s, 3.0 MB/s
dd: error reading '/dev/sda': Input/output error
320065087+1 records in
320065088+0 records out
163873325056 bytes (164 GB, 153 GiB) copied, 55202.2 s, 3.0 MB/s
[a lot of read errors here]
180528095744 bytes (181 GB, 168 GiB) copied, 105746 s, 1.7 MB/s
dd: error reading '/dev/sda': Input/output error
352593785+152 records in
352593937+0 records out
180528095744 bytes (181 GB, 168 GiB) copied, 105748 s, 1.7 MB/s
184232141312 bytes (184 GB, 172 GiB) copied, 115892 s, 1.6 MB/s
184232509952 bytes (184 GB, 172 GiB) copied, 115893 s, 1.6 MB/s
192463561216 bytes (192 GB, 179 GiB) copied, 138368 s, 1.4 MB/s
211374223872 bytes (211 GB, 197 GiB) copied, 190337 s, 1.1 MB/s
dd: error reading '/dev/sda': Input/output error
412840143+153 records in
412840296+0 records out
211374231552 bytes (211 GB, 197 GiB) copied, 190342 s, 1.1 MB/s
211374232064 bytes (211 GB, 197 GiB) copied, 190342 s, 1.1 MB/s
dd: error reading '/dev/sda': Input/output error
412840143+154 records in
412840297+0 records out
211374232064 bytes (211 GB, 197 GiB) copied, 190344 s, 1.1 MB/s
在上面的例子中,181GB 到 211GB 之间没有读取错误,所以很多扇区应该没问题,但速度始终没有提升到起始的 10MB/s 左右,而是一直在下降。前 37GB 也没有读取错误(因此没有输出),但这里由于缓存耗尽和磁盘故障,速度下降是可以理解的。
hdparm 使用最佳设置来提高磁盘速度。iostat 报告磁盘利用率为 100%:
r/s rkB/s rrqm/s %rrqm r_await rareq-sz Device
89.50 358.0k 0.00 0.0% 11.12 4.0k sda
w/s wkB/s wrqm/s %wrqm w_await wareq-sz Device
0.00 0.0k 0.00 0.0% 0.00 0.0k sda
d/s dkB/s drqm/s %drqm d_await dareq-sz Device
0.00 0.0k 0.00 0.0% 0.00 0.0k sda
f/s f_await aqu-sz %util Device
0.00 0.00 0.99 99.5% sda
我的问题是,为什么会出现这种情况?即使没有坏块导致的读取错误,硬盘的读取速度也随着时间的推移越来越慢,这是怎么回事?为什么速度一直上不去?
问题的第二部分:是否有可能比良好扇区的ddrescue
速度更快?dd
您看到的“速度”数值似乎与您想象的并不相符。您仔细查看的数值实际上是总体吞吐量值;它是传输的总字节数除以总耗时所得的商。这些值是累积的,而不是瞬时的。
例如:
36571 MB / 7523 秒 = 4.86 MB/秒
和
211374 MB / 190344 秒 = 1.11 MB/秒
这些计算使用累积值来报告平均值。
读取错误会导致重试读取操作。这会增加时间部分,并降低吞吐量。
将这些吞吐量数字称为“速度”可能会造成误导。
它们并不表示任何接口上的实际数据传输速率。
您没有正确分析这些结果;输出根本不具有周期性。
前 164 GB 的传输只有2 个报告,但接下来的 48 GB 产生了11 个报告。
最后 10 GB(48 GB 中的)的传输产生了 5 个(11 个中的)报告。
平均吞吐量下降是因为读取重试和/或坏块发生的频率更高!
附录
也许您认为的“好扇区”并不准确。
仅仅没有“错误”并不能作为数据完整性和/或驱动器健康状况的良好或可靠的指标。存储设备(采用 ECC)中的
“错误”并非非黑即白;既有可纠正的错误,也有不可纠正的错误。
通常,只有在驱动器执行N次重试且数据仍然无法纠正后,读取请求才会被视为错误(即失败)。正是这些反复尝试读取扇区的操作增加了运行时间(每次重试至少需要盘片旋转一圈),并降低了吞吐量,这也是为什么“速度”这个概念可能并不适用的原因。
如果其中一次读取重试成功,或者(更有可能)存在可纠正的错误(使用 ECC),则读取操作被视为完成且成功。主机会收到指示扇区数据是否需要更正的状态信息,但我不知道是否返回了重试计数。
无论如何,对于返回有效扇区数据的读取请求,即使获取该数据需要较长时间, dd也不会报告任何错误。
因此,通过需要重试且不会生成任何错误消息的“慢速”读取,可以将缩减的吞吐量数字保持在较低水平(或进一步降低)。
您可以使用(更小的)传输来更好地了解驱动器的健康状况和吞吐能力。
无需添加整个驱动器,只需读取一小部分选定的块即可。
其中
<start> 是传输开始的 LBA(“扇区”号),
<len> 是要传输的块/扇区数,例如 16 甚至 1。
另请参阅驱动器的 SMART 属性,了解已更正和未更正的读取错误统计信息。
三个因素: