【银河麒麟高级服务器操作系统】有关dd及cp测试差异的现象分析详解

news/2024/12/16 20:49:24/

了解更多银河麒麟操作系统全新产品,请点击访问

麒麟软件产品专区:https://product.kylinos.cn

开发者专区:https://developer.kylinos.cn

文档中心:https://documentkylinos.cn


dd现象

使用银河麒麟高级服务器操作系统执行两次dd用例后,表现不一致:

命令用例:/usr/bin/time dd if=/dev/zero of=/home/d.bin bs=2M count=4096

结果如图:

可以发现,在第二次执行dd时,速率只有412MB/S

现象猜测分析

基于上述的现象,猜测第一次dd没有等待数据完全落盘就结束了;而第二次dd是等待数据落盘之后才结束。

可以做如下复现和测试:

系统版本:

  1. Kernel:
  2. 4.19.90-89.11.v2401.ky10.x86_64
  3. Build:
  4. Kylin Linux Advanced Server
  5. release V10 SP3 2403/(Halberd)-x86_64-Build20/20240426

测试步骤:

执行:

  1. /usr/bin/time dd if=/dev/zero of=/home/d.bin bs=2M count=4096

再次执行:

  1. /usr/bin/time dd if=/dev/zero of=/home/d.bin bs=2M count=4096

可复现这个结果:

图1

分析和实验

删除d.bin后rm -rf d.bin,执行:

  1. strace -ttt -T -o strace_output_0.txt dd if=/dev/zero of=/home/d.bin bs=2M count=4096
  2. strace -ttt -T -o strace_output_1.txt dd if=/dev/zero of=/home/d.bin bs=2M count=4096

将生成两次对dd命令的系统调用报告,分析这两个output报告文件,对比close操作时,可以发现,第一次的dd,close耗时短,第二次的dd,close耗时更长

图2 strace系统调用对比

左边是第一次,close操作用不到1秒;

右边是第二次,close操作用了6秒,对比图1结果,第二次与第一次时间差接近6秒。

测试说明这个close()系统调用操作是导致第二次dd慢的原因。问题要从close调用的方向去分析。

根因分析

dd if=/dev/zero of=4G bs=1M count=4096在执行时,会以O_WRONLY|O_CREAT|O_TRUNC的方式打开文件,首次执行时,文件不存在则创建;

第二次执行时O_TRUNC就会发挥作用了,它会先把文件长度给TRUNC到0,然后再写数据;(这是dd程序本身执行的逻辑决定的)

而xfs文件系统,为了数据完整性,对这个这种情况做了加强——即:再检测到这种情况下,会在文件close时触发数据下刷,而且是同步的,就是导致dd性能降低的原因。

  1. 第一次运行时,由于目标文件/home/d.bin不存在,属于纯粹的内存操作,没有实际的磁盘IO开销。
  2. 第二次运行时,由于目标文件已存在且被写入了数据,而需要/dev/zero真实读取数据,并将数据写入磁盘文件。这就引入了额外的磁盘IO操作,成为了新的性能瓶颈。
  3. cpu占用率的差异就是由于落盘操作造成的,第一次dd时,都是操作的内存所以cpu占用率高;
  4. 第二次dd由于数据落盘会有IO等待,cpu占用率就会降下来。

验证猜测

使用watch监测页内存回写到硬盘

使用两个终端,并进行测试与观测,第一次dd

  1. rm -rf d.bin
  2. echo 3 > /proc/sys/vm/drop_caches
  3. time dd if=/dev/zero of=/home/d.bin bs=2M count=4096
  1. watch -n 1 cat /proc/meminfo

图三 第一次dd 的数据回写观测

第二次dd

  1. echo 3 > /proc/sys/vm/drop_caches
  2. time dd if=/dev/zero of=/home/d.bin bs=2M count=4096
  1. watch -n 1 cat /proc/meminfo

图4 第二次dd的数据回写观测

可以发现,第一次dd并没有writeback回写,即:没有从页内存往硬盘落数据,通过ls看到的d.bin的文件数据,是在内存中,只是因为有这个“机制”存在,让用户感觉这个数据落盘了;

第二次dd,由于出现了脏页(因为d.bin存在导致缓存数据不同),内核进行了数据落盘的操作,通过watch命令,观测到了在dd过程中,writeback就有数据流量。

使用sar观测I/O

  1. time dd if=/dev/zero of=/home/d.bin bs=2M count=4096
  1. sar -d 1

第一次dd的情况

图5 第一次dd的I/O情况

第二次dd的情况

图6 第二次dd的I/O情况

可以看到,第二次的磁盘I/O操作比第一次dd多很多,说明有很多I/O落盘的操作,佐证页缓存机制在工作。

如何让dd观测结果稳定?

优化dd测试方法

既然dd的运行逻辑决定了最后观测的结果,那么可以通过指定一些参数,来更准确的进行测试:

通过添加ofag=direct参数,不走系统缓存

测试命令和观测结果如下:

  1. [root@localhost home]# rm -rf d.bin
  2. [root@localhost home]# time dd if=/dev/zero of=/home/d.bin bs=2M count=4096 oflag=direct
  3. 记录了4096+0 的读入
  4. 记录了4096+0 的写出
  5. 8589934592字节(8.6 GB,8.0 GiB)已复制,11.2041 s,767 MB/s
  6. real0m11.205s
  7. user0m0.003s
  8. sys0m0.694s
  9. [root@localhost home]# time dd if=/dev/zero of=/home/d.bin bs=2M count=4096 oflag=direct
  10. 记录了4096+0 的读入
  11. 记录了4096+0 的写出
  12. 8589934592字节(8.6 GB,8.0 GiB)已复制,11.4382 s,751 MB/s
  13. real0m11.443s
  14. user0m0.000s
  15. sys0m0.700s
  16. [root@localhost home]#

图7 dd添加参数后

可以看到,在添加oflag=direct参数后,dd命令不管是第几次都稳定了;

通过观察页内存,可以发现,直接写时,数据落盘,没有通过脏页内存回写。

通过添加conv=notrunc方式,不截断输出文件

默认情况下,如果输出文件已经存在,dd命令会首先将其截断为0字节大小。然后再将输入数据写入该输出文件。

当指定conv=notrunc参数时,dd命令将保留输出文件已有的数据,而只是从输出文件的当前文件结尾处开始覆盖写入数据。

删除生成的d.bin文件

如果每次测试前,都删除d.bin文件,那么每次dd都是通过内存出来,速率也可以稳定

为什么FreeBSD的表现和Linux不同?

freebsd上使用zfs文件系统,而linux上使用了xfs文件系统,他们在数据下刷机制上也存在一些差异:

对于 XFS,代码中的 filemap_flush(VFS_I(ip)->i_mapping) 实际上是调用 VFS(虚拟文件系统)层的通用页高速缓存写入磁盘的操作。

具体来说,它会遍历给定映射(mapping)关联的所有脏页,将这些脏页写入对应的后备存储设备(通常是磁盘)。这个过程是同步执行的,即该函数直到所有脏页都被写入磁盘才会返回。

以上是XFS文件系统特有实现,而zfs实现不同,所以不存在同样的问题。

cp现象

在d6.bin存在的情况下,使用cp d.bin d6.bin进行拷贝,如果使用了truncate -s 0 d6.bin,会使拷贝速度急速上升的。为什么?

现象分析

cp a b慢

truncate -s 0 b; cp a b快

直接cp a b时对b文件打开是带O_TRUNC标志(d6.bin已存在),就会在close的时候进行同步下刷,速度就不会快;

而truncate -s 0 b; cp a b,cp对b的打开同样是带O_TRUNC标志的,但是由于在cp之前,执行了truncate的操作,根据xfs文件系统落盘的机制,在cp的时候O_TRUNC就不起作用了,也就是在close的时候不会进行同步下刷;=》内核会对同样的两次操作进行优化,避免做重复的工作。

xfs文件系统源码

先看紫色字的注释:

如果之前对该文件进行了截断操作,删除了旧的文件数据。我们希望在最后关闭该文件时,提前(early)将数据写出到磁盘。这个问题特别容易在以下情况发生:先截断文件,然后通过缓冲区写入(重写)数据(延迟分配delalloc),接着系统崩溃。我们在这里所做的,实际上是大大缩小了可能遇到这个问题的时间窗口。

所谓空文件问题,是指在截断、重写文件数据的过程中,如果系统崩溃,可能导致原有数据被删除,而新写入的数据还未持久化到磁盘,从而使文件内容变为空或不完整。

为了避免这种情况,XFS会在关闭经过截断和重写的文件时,主动提前将缓冲区数据刷新到磁盘。这样可以最大限度减小系统崩溃导致数据丢失的窗口期,从而提高数据完整性和一致性。

执行过程如下:

判断文件系统状态xfs_is_shutdown,执行以下操作:

a. 判断truncated状态:XFS_ITRUNCATED会把XFS_ITRUNCATED复位,返回true;如果flags里面没有XFS_ITRUNCATED置位,返回false

b. 如果上一步标志被清除(即之前发生了截断),调用 xfs_iflags_clear(XFS_IDIRTY_RELEASE) 清除 XFS_IDIRTY_RELEASE 标志。该标志表示需要在卸载时将延迟写入的元数据写入磁盘。

c. 如果上一步标志被清除,调用 filemap_flush(VFS_I(ip)->i_mapping) 将所有延迟的元数据写入磁盘。(数据下刷

所以手动执行truncate命令时,变量truncated=false,if(truncated)函数就不会执行,也就没有数据下刷的操作,观测结果“看上去”cp速度很快。

验证

这个情况同样可以用sar观测I/O被证实:


http://www.ppmy.cn/news/1555674.html

相关文章

使用docker-compose部署fastApi微服务

制作镜像 准备服务代码man.py 文件夹结构 import os from loguru import logger from fastapi import FastAPI import uvicornapp FastAPI() # 定义日志输出目录 log_directory os.getenv("LOG", "/work/logs/") os.makedirs(log_directory, exist_o…

C++6--析构函数

目录 1.概念 2.特性 1.概念 与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作 2.特性 析构函数是特殊的成员函数,其特征如下…

比特币是否会取代美元(以及其他主权货币)

上图是 Olivier Blanchard 宏观经济学第八版的英文版内容。这里用中文解释。 1. 背景与现状: 比特币的规模与美元相比仍然很小: 截至 2018 年 12 月,比特币的总流通量为 1730 万枚,每枚价值 $3,900,总市值约 $670 亿…

Kubernetes之自动化CI/CD简介

在 Kubernetes 环境下,CI/CD 的实现帮助开发团队自动化整个软件生命周期的流程,从代码提交到应用部署和管理。Kubernetes 作为一个容器编排平台,提供了高效的容器管理、部署、扩展等功能,而结合 CI/CD 流程,能够进一步…

Windows安装elasticsearch、Kibana以及IK分词器

一、下载 1.下载elasticsearch 访问官网Download Elasticsearch | Elastic,下载elasticsearch 2.下载 Kibana 访问Download Kibana Free | Get Started Now | Elastic ,下载 Kibana 3. IK分词器下载 访问Gitee 极速下载/elasticsearch-analysis-ik选…

YOLO模型基础学习

1. 分类回归的特征值类型 2. 传统机器学习和深度学习对比 3. yolo目标检测的特征值类型 在yolo中特征值是中心点和宽高 2. yolo模型主干网路分析

升级Ubuntu 24.04 LTS报错“Oh no! Something has gone wrong.”

强烈建议:升级Ubuntu系统之前先配置好SSH远程访问 最近升级Ubuntu系统(18->24),经历了一些惊魂时刻,复盘下来没有重装系统的最得益于SSH访问。 在升级到24.04版本时,一切似乎表现得很正常,…

【Java学习笔记】JUnit

一、为什么需要 JUnit 二、基本介绍 三、实现方法 第一次添加: 在需要测试的方法处输入 Test注解,快捷键AltInsert选择添加版本(常用JUnit5.4) 出现绿色箭头可进行测试和编译