Car*_*ong 5 linux bash command-line dd pipe
当我在 *NIX 中寻找管道缓冲工具时,我看到了使用buffer、mbuffer或的建议pv。然而,前两者并不总是在发行版的官方存储库中(例如 Arch),而pv(从 1.6.0 开始)有一个错误阻止了此功能。在其他几个问题中,我看到提到dd用作缓冲区,我想探索它,因为dd它总是存在。然而,没有一个足够详细以具有真正的意义,所以在这里我要求一种“正确”的使用方式。
提到的问题dd包括https://unix.stackexchange.com/questions/345072/can-dd-be-used-to-add-a-buffer-to-a-pipe和https://unix.stackexchange.com/questions /21918/管道中无限制数据量缓冲区的实用程序
为了便于测试,我在下面提供了一个测试脚本,以及一些关于我自己的实验的评论。详细信息将在代码清单后解释。运行前请确保您已pv安装且内存至少256M!
#!/bin/sh
producer() {
while [ 1 ]; do
dd if=/dev/zero bs=64M count=1 iflag=fullblock status=none
sleep 4
done
}
buffer() {
# Works, but long
# Must at least fill 32M before consumer starts
# So, must choose small obs and chain more to look
# more like a proper "buffer"
dd obs=32M status=none | \
dd obs=32M status=none| \
dd obs=32M status=none| \
dd obs=32M status=none
# Doesn't work, producer rate limited
#dd bs=128M status=none
# Doesn't work, producer must fill buffer, then
# must wait until buffer is empty
#dd obs=128M status=none
# Doesn't work, producer rate limited
#dd ibs=128M status=none
# Doesn't work, producer must fill buffer, then
# must wait until buffer is empty
#dd bs=128M status=none iflag=fullblock
}
consumer() {
pv --rate-limit 1M -q | dd of=/dev/null status=none
}
producer | pv -cN produce | buffer | pv -cN consume | consumer
Run Code Online (Sandbox Code Playgroud)
这里,生产者每 4 秒产生 64MB 的数据,具有 128MB 的缓冲区,而消费者以恒定的 1MB/s 速率消费。当然,这意味着缓冲区很快就会溢出,但这是为了清楚地显示效果。理想情况下,在缓冲区填满之前(在第三次生产时),我们应该看到恒定的 1MB/s 消耗,以及每次产生 64MB 数据的突发生产。“正确”的输出如下所示:
produce: 128MiB 0:00:07 [ 0 B/s] [ <=> ]
consume: 7.25MiB 0:00:07 [1.01MiB/s] [ <=> ]
Run Code Online (Sandbox Code Playgroud)
这里,工作解决方案如下所示:
dd obs=32M status=none | \
dd obs=32M status=none| \
dd obs=32M status=none| \
dd obs=32M status=none
Run Code Online (Sandbox Code Playgroud)
这是通过将所需的 128MB 缓冲区分成 4 个块来构建的。是的,在数据传递到下一级之前,每个块都必须填满,但由于 32MB 小于 64MB 突发,因此它适用于此测试,就好像它是真正的缓冲区一样。现在,存在一些问题。
dd命令dd if=test.txt| dd obs=1M | dd obs=1M | dd of=test2.txt并比较了结果。事实证明这不是问题。因此,使用它进行备份不会损坏数据。脚本中还包含一些其他尝试,但它们不起作用,如评论中所述。我尝试过使用 FIFO + 后台进程,这会产生相同的结果。
附言。正如您所知,在将 A 备份到 B 时,缓冲管道非常有用,尤其是当 A 是具有寻道时间的 HDD 时。所以我会做这样的事情:
tar cSpf - <path> -C <root path> | <a large buffer> | <some parallel compressor> \
| <small buffer if compressor is generally slow and B have seek time> \
| dd bs=<several GB if B is not an SSD> iflag=fullblock oflag=direct of=<archive.tar.??>
Run Code Online (Sandbox Code Playgroud)
我正在输入我自己的答案。它可能不是最好的,但还可以。
这是经过多次测试才写在前面的。
不要链接太多 DD 进行缓冲,否则所有 CPU 核心都可能阻塞 IO,并且即使您还有大量内存,您的计算机也会死机!
如果您有一些损坏的慢速外部 USB 驱动器,并且还需要荒谬的 IO 强度来进行读/写,则尤其有毒。
我基本上用尽了DD选项的所有组合。单个 DD 似乎不可能完成此任务,因为它无法执行异步 IO。否则,在 DD-buffer 链中,必须先填充最大的块,然后才能开始像 FIFO 一样工作。因此,如果您不关心填充管道时的初始延迟...两个 dd 的工作链。我希望其他人可以提供更优雅的解决方案,但这里有一个示例用法。
示例 1:将所有文件从严重碎片化的 HDD A(响应时间抖动)压缩到严重碎片化的 HDD B(抖动),并行使用 XZ 作为压缩算法(慢)(如果您实际使用计算机,则会出现抖动)(免责声明:我是凭自己的想法写的,所以一些小细节可能是错误的。使用风险由您自己承担):
tar -cpSf - -C /mnt/A . | \
dd obs=1024M | dd obs=1024M | \
xz -T 0 -c | \
dd obs=1024M | dd obs=1024M | \
dd bs=512M iflag=fullblock of=/mnt/B/A.tar.xz
Run Code Online (Sandbox Code Playgroud)
添加pv以查看速度。这里,xz只有从A读取1GB数据后才开始(除非小于1GB,则结束)。同样,只有在 xz 输出 1GB 数据后,才会开始向 B 写入磁盘。tar此代码在和 之间提供 2GB 缓冲区xz,在 和 之间提供 2GBxz写入缓冲区。最后的bs=512M并不是真正必要的,但我发现大的(> 64M)块大小可以提供更好的平均写入速度,尤其是在 USB 硬盘上。我想如果驱动器 B 正在使用(未确认),它也会产生更少的碎片。
示例2。目标:将一个巨大的文件从碎片严重的磁盘 A 复制到碎片严重的磁盘 B。
dd if=/mnt/A/file obs=<half of cache you want> | dd bs=<half of cache> iflag=fullblock oflag=direct of=/mnt/B/file
Run Code Online (Sandbox Code Playgroud)
这是我能找到的最简单的形式之一。如果文件足够大,则用于填充缓存的初始时间应该可以忽略不计。同时,它异步读取/写入,并希望将足够的写入组合在一起以获得一些顺序性能。不过,我想 SSD 不会关心块大小。
示例3。感谢卡米尔·马乔罗夫斯基 (Kamil Maciorowski),我的 中现在有以下内容.zshrc:
buffer() {
if [ "$2" -gt 0 ] ; then
dd status=none obs="$1" | buffer "$1" $(($2-1))
else
cat
fi
}
Run Code Online (Sandbox Code Playgroud)
现在,如果您需要 3 个 512M 缓冲区块,请链接buffer 512M 3到您的管道中。一般来说,如果您的作业对于吞吐量来说足够大(例如,平均以 100MB/s 的速度复制/压缩 100GB+ 数据),则较小的块除了更快地填充管道之外没有任何优势(这是无关紧要的,因为这个时间很短) 。我观察到,如果放入太多块,CPU 可能会因 IO 过于繁忙而导致该命令冻结整个计算机。
现在,示例 1 变为
tar -cpSf - -C /mnt/A . | \
buffer 1024M 2 | \
xz -T 0 -c | \
buffer 1024M 2 | \
dd bs=512M iflag=fullblock of=/mnt/B/A/tar.xz
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4611 次 |
| 最近记录: |