为什么linux cp命令不消耗磁盘IO?

为什么linux cp命令不消耗磁盘IO?

操作系统:centos7

测试文件:a.txt 1.2G

监控命令:iostat -xdm 1

The first scene:
cp a.txt b.txt        #b.txt is not exist

在此输入图像描述

The second scene: 
cp a.txt b.txt        #b.txt is exist

在此输入图像描述

为什么第一个场景不消耗IO,而第二个场景却消耗IO?

答案1

很可能数据在第一次cp操作期间并未刷新到磁盘,而是在第二次操作期间刷新到磁盘。

尝试设置vm.dirty_background_bytes为较小的值,例如 1048576 (1 MiB),看看是否是这种情况; run sysctl -w vm.dirty_background_bytes=1048576,然后你的第一个cp场景应该显示 I/O。

这里发生了什么?

除了同步和/或直接 I/O 的情况外,对磁盘的写入都会在内存中缓冲,直到达到阈值,此时它们开始在后台刷新到磁盘。该阈值没有正式名称,但它由vm.dirty_background_bytes和控制vm.dirty_background_ratio,因此我将其称为“脏背景阈值”。来自内核文档

vm.dirty_background_bytes

包含后台内核刷新器线程将开始写回的脏内存量。

笔记: dirty_background_bytes是 的对应项dirty_background_ratio。一次只能指定其中之一。当写入一个 sysctl 时,会立即考虑评估脏内存限制,而另一个 sysctl 在读取时显示为 0。

dirty_background_ratio

包含(以包含空闲页和可回收页的总可用内存的百分比)后台内核刷新器线程将开始写出脏数据的页数。

总可用内存不等于总系统内存。

vm.dirty_bytesvm.dirty_ratio

除了这个门槛之外,还有第二个门槛。嗯,与其说是阈值,不如说是限制,它由vm.dirty_bytes和控制vm.dirty_ratio。同样,它没有正式名称,因此我们将其称为“脏限制”。一旦足够的数据被“写入”,但未提交到底层块设备,进一步的尝试将write必须等待写入 I/O 完成。 (我不清楚他们必须等待哪些数据的确切细节,可能是 I/O 调度程序的函数。我不知道。)

为什么?

磁盘速度很慢。旋转锈尤其如此,因此当磁盘上的读/写头移动以满足读取请求时,在读取请求完成并且可以开始写入请求之前,无法处理写入请求。 (反之亦然)

效率

这就是为什么我们在内存中缓冲写入请求并缓存我们读取的数据;我们将工作从慢速磁盘转移到更快的内存。当我们最终将数据提交到磁盘时,我们有大量的数据可供使用,我们可以尝试以最小化寻道时间的方式写入它。 (如果您使用的是 SSD,请用 SSD 块的重新刷新来代替磁盘寻道时间的概念;重新刷新会消耗 SSD 的寿命,并且是一个缓慢的操作,SSD 试图通过自己的写入来隐藏该操作(取得了不同程度的成功)缓存。)

vm.dirty_background_bytes我们可以使用和调整内核尝试将数据写入磁盘之前缓冲的数据量vm.dirty_background_ratio

缓冲写入数据过多!

如果您写入的数据量对于其到达磁盘的速度来说太大,您最终将耗尽所有系统内存。首先,您的读取缓存将消失,这意味着从内存提供服务的读取请求将减少,并且必须从磁盘提供服务,从而进一步减慢写入速度!如果您的写入压力仍然没有减轻,最终内存分配将不得不等待您的写入缓存释放一些,这将更具破坏性。

所以我们有vm.dirty_bytes(和vm.dirty_ratio);它让我们说:“嘿,等一下,我们真的是时候将数据写入磁盘了,以免情况变得更糟。”

数据仍然太多

不过,对 I/O 进行硬停止是非常具有破坏性的;从读取过程来看磁盘已经很慢了,可能需要几秒到几秒的时间分钟以便刷新该数据;考虑vm.dirty_bytes默认值为 20。如果您的系统具有 16GiB RAM 并且没有交换区,则在等待 3.4GiB 数据刷新到磁盘时,您可能会发现 I/O 被阻塞。在具有 128GiB RAM 的服务器上?当您等待 27.5GiB 数据时,服务将会超时!

因此,保持vm.dirty_bytes(或者vm.dirty_ratio,如果您愿意的话)相当低是有帮助的,这样如果您这个硬门槛,只会对您的服务造成最小程度的破坏。

什么是好的价值观?

通过这些可调参数,您始终在吞吐量和延迟之间进行权衡。缓冲太多,您将获得巨大的吞吐量,但延迟却很糟糕。缓冲区太少,吞吐量会很差,但延迟会很大。

在只有单个磁盘的工作站和笔记本电脑上,我喜欢设置vm.dirty_background_bytes为 1MiB 左右,以及vm.dirty_bytes8MiB 和 16MiB 之间。我很少发现单用户系统的吞吐量超过 16MiB,但对于 Web 浏览器数据存储等任何同步工作负载来说,延迟挂起可能会变得非常糟糕。

在任何带有条带奇偶校验数组的东西上,我发现数组条带宽度的一些倍数是一个很好的起始值vm.dirty_background_bytes;它减少了在更新奇偶校验时需要执行读/更新/写序列的可能性,从而提高了阵列吞吐量。

对于vm.dirty_bytes,这取决于您的服务可能遭受多少延迟。我自己喜欢计算块设备的理论吞吐量,用它来计算它在 100 毫秒左右可以移动多少数据,并进行vm.dirty_bytes相应的设置。 100 毫秒的延迟是巨大的,但它并不是灾难性的(在我的环境中)。

不过,所有这些都取决于您的环境;这些只是寻找最适合您的方法的起点。

相关内容