dd的一种用法

• 本文约 887 字,阅读大致需要 2 分钟 | *nix and Win32 Kernel | #dd | #shell | #Performance | #ZFS | #CLI

这个方法我最早是在 佐藤広生第13回FreeBSD勉強会 上做的《ZFSの活用とチューニング》演示幻灯片上看到的,当时没想太明白,而后来想明白了也没记下来。今天想起来了就先记上一笔,备忘。

一般来说,如果有很多不同的资源,那么尽量让不相关的资源同时去完成不同的任务有助于改善系统的利用率并提高吞吐量。而Unix上的大部分工具在设计时都是设计成阻塞的,或者说它们很大程度上能够高效地利用一种资源,而在完成一系列相互关联的任务时往往就不那么有效了。

举例来说,发送ZFS快照到另外一个网络的服务器上,假定发送ZFS快照本身在本地可以以较快的速度持续进行,但带宽比较受限,那么很显然的一个想法便是引入压缩。另一方面,在接收一侧,解压缩之后的数据写盘的速度可能没那么快,而且让压缩程序直接挤牙膏似的吐出数据给ssh或者nc往往也不能十分有效地利用带宽。在这个场景中,在发送端我们可以看到以下几个任务:

  • 发送ZFS快照(很快、产生很多数据)
  • 压缩(较慢、产生较少数据;由于吃满了CPU,因此防止上一环节阻塞的意义不大)
  • 将压缩数据传到对端的机器上(较慢,很可能引起阻塞)

对应的,在接收端我们也可以看到与之对应的任务:

  • 从远端接收数据(较慢,GIGO)
  • 解压缩(较快、产生许多数据)
  • 将ZFS快照写盘(略慢,很可能引起阻塞)

在这样一个链条中,如果全部使用标准的Unix命令行工具的话,任何一个环节的阻塞都可能会直接向前反馈,从而影响整个系统的吞吐量。很明显,在对方由于任何原因暂时来不及接收数据的时候,压缩操作可以继续进行,这事通过编程不难实现,但实际上我们需要的只是引入两个dd进程,即将发送端变成:

  • 发送ZFS快照(很快、产生很多数据)
  • 压缩(较慢、产生较少数据;由于吃满了CPU,因此防止上一环节阻塞的意义不大)
  • dd obs=16m
  • dd obs=16m
  • 将压缩数据传到对端的机器上(较慢,很可能引起阻塞)

在新的场景中,接收端的阻塞将导致第二个dd的输出阻塞,而此时第一个dd仍然可以再吃下16MB的数据流(这个16MB需要根据具体的应用来调整,原则上它应该大于远端一次阻塞到完全恢复这段时间上游能够产生的数据量)。通过dd所做的reblock,也使发出数据采用较大的块尺寸,从而进一步节省带宽。