当前位置: 首页 > news >正文

系统性能优化-4 磁盘

系统性能优化-4 磁盘

磁盘作为计算机中速度最慢的硬件之一,常常是系统的性能瓶颈,优化磁盘一般能得到明显的提升~

文章以如何高效的传输文件来讨论针对磁盘的优化技术,如零拷贝、直接 IO、异步 IO等。

最简单的网络传输

最简单的方式的当然是找到文件存储的路径,创建一个固定的大小的缓冲区,每次读取缓冲区大小的文件内容,再通过网络 API 发送给客户端,重复上述流程直到把文件发送完成。

顺便一提,缓冲区的设置还是有必要的,java 有单字节的读取写入方式(FileInputStream.read()),这样会很慢,缓冲区可以有效的提升读取文件的性能。

但是这样的性能依旧不是很高,原因是这需要进行多次的内容拷贝,会导致大量的上下文切换

image-20250624112007687

  • 每次读取发送都经历了 4 次用户态与内核态的上下文切换
  • 每次发送的缓存区内容被拷贝了 4 次

接下来就从减少上下文切换次数减少内存拷贝次数来进行优化

零拷贝

读取磁盘或者操作网卡都由操作系统内核完成。内核负责管理系统上的所有进程,它的权限最高,工作环境与用户进程完全不同。只要我们的代码执行 read 或者 write 这样的系统调用,一定会发生 2 次上下文切换:首先从用户态切换到内核态,当内核执行完任务后,再切换回用户态交由进程代码执行。

因此如果要减少上下文切换次数,就要减少系统调用次数。解决方案就是把 read 和 write 系统调用合二为一,直接在内核中完成文件的读取和发送,可以把原本的 4 次上下文切换减少为 2 次。

那如何减少内存拷贝次数呢?对于常见的文件下载场景,我们并不需要进程对文件进行处理,如添加公司信息等,那么用户缓冲区就没有存在的必要,直接由 PageCache 拷贝到 Socket 缓冲区就可以,这可以把原本的 4 次内容拷贝缩短为 3 次,

image-20250624112749023

如果 网卡支持 DMA SG-DMA(The Scatter-Gather Direct Memory Access),那么 PageCache 可以直接拷贝到网卡,可以再减少一次内存拷贝。

image-20250624113104692

其实这就是零拷贝技术,它是操作系统提供的新函数,同时接收文件描述符和 TCP socket 作为输入参数,这样执行时就可以完全在内核态完成内存拷贝,既减少了内存拷贝次数,也降低了上下文切换次数。

零拷贝使用户无需关心 socket 缓冲区的大小(因为 socket 缓冲区是动态变化的,它既用于 TCP 滑动窗口,也用于应用缓冲区,还受到整个系统内存的影响)。综合种种优点,零拷贝可以极大的提升文件传输性能。

PageCache 磁盘高速缓存

正常读取文件时,是先把磁盘文件拷贝到 PageCache 上,再拷贝到进程中。原因是磁盘的读取速度是最慢的,而在内存中的 PageCache 速度就会快很多,那选择哪些数据复制到内存呢?根据时间局部性原理(刚被访问的数据在短时间内再次被访问的概率很高),用 PageCache 缓存最近访问的数据,当空间不足时淘汰最久未被访问的缓存(即 LRU 算法)。读磁盘时优先到 PageCache 中找一找,如果数据存在便直接返回,这便大大提升了读磁盘的性能。

对于机械硬盘来说,需要旋转磁头到数据所在的扇区,再开始顺序读取数据。其中,旋转磁头耗时很长,为了降低它的影响,PageCache 使用了预读功能。也就是即使你可能目前只读 32KB 数据,但内核会把后续的部分数据也读取到 PageCache,因为这个读取成本很低,而如果后续一段时间访问到了这些数据,带来的收益是很值得的。

PageCache 在 90% 以上场景下都会提升磁盘性能,但在某些情况下,PageCache 会不起作用,甚至由于多做了一次内存拷贝,造成性能的降低。

先说结论:在读取大文件时,不应使用 PageCache,进而也不应使用零拷贝技术处理。

当用户访问大文件时,内核就会把它们载入到 PageCache 中,这些大文件很快会把有限的 PageCache 占满。一方面这些大文件被再次访问的概率其实很低,耗费 CPU 多拷贝到 PageCache 一次;另一方面大文件占用 PageCache 会导致热点小文件无法被加载到 PageCache 中,读取的速度变慢。

  • 比如视频文件通常按时间顺序播放,播放器只会按需加载一定长度的视频数据。虽然文件本身很大,但只有少部分数据会在某一时间点内被访问到,其余的数据部分在播放过程中可能根本不会被访问到。
  • 某些大数据库文件也是按顺序或按块读取的,而数据库的查询操作通常集中在特定区域或范围内。大文件的其他部分可能在较长时间内不会被访问,导致它们在 PageCache 中的缓存效果差。

那么高并发场景下该怎么处理大文件呢?

异步 IO + 直接 IO

高并发场景处理大文件时,应当使用异步 IO 和直接 IO 来替换零拷贝技术。

当调用 read 方法读取文件时,实际上 read 方法会在磁盘寻址过程中阻塞等待,导致进程无法并发地处理其他任务,如下图所示:

image-20250624132341046

异步 IO(异步 IO 既可以处理网络 IO,也可以处理磁盘 IO,这里我们只关注磁盘 IO)把读操作分为两部分,前半部分向内核发起读请求,但不等待数据就位就立刻返回,此时进程可以并发地处理其他任务。当内核将磁盘中的数据拷贝到进程缓冲区后,进程将接收到内核的通知,再去处理数据,这是异步 IO 的后半部分。如下图所示:

image-20250624132423219

异步 IO 并没有把数据拷贝到 PageCache 中,这其实是异步 IO 实现上的缺陷。经过 PageCache 的 IO 我们称为缓存 IO,它与虚拟内存系统耦合太紧,导致异步 IO 从诞生起到现在都不支持缓存 IO。绕过 PageCache 的 IO 是个新物种,我们把它称为直接 IO。对于磁盘,异步 IO 只支持直接 IO。

直接 IO 的应用场景为:

  • 应用程序已经实现了磁盘文件的缓存,不需要 PageCache 再次缓存,引发额外的性能消耗。比如 MySQL 等数据库就使用直接 IO
  • 高并发下传输大文件

缺点为无法享受 PageCache 造成的性能提升(内核会缓存尽量多的连续IO在 PageCache 中,合并为一个更大的 IO 发给磁盘,减少磁盘的寻址操作;内核也会预读后续的 IO 放在 PageCache 中,减少磁盘操作)

总结

零拷贝技术基于 PageCache(缓存最近读的数据),合并读取和发送的系统调用,能够有效减少传输文件过程中的上下文切换次数和内存拷贝次数,同时最大程度利用 socket 缓冲区。但缺点是用户进程无法对文件做任何修改,比如压缩后再发送。当文件大小超过某个阈值后,PageCache 还可能引发副作用,因此,实践中通常会设定一个文件大小阈值,针对大文件使用异步 IO 和直接 IO,而对小文件使用零拷贝( 例如 Nginx 的 directio 指令)。

文件传输场景中的优化可以大概分为三个方向:

  • 减少磁盘工作量(PageCache)
  • 减少 CPU 工作量 (直接 IO)
  • 提高内存利用率(零拷贝)
http://www.lqws.cn/news/505081.html

相关文章:

  • 【Bluedroid】蓝牙启动之 bta_dm_enable 流程梳理 源码解析
  • 【AI落地应用实战】Chaterm:重新定义终端操作的AI智能工具
  • C# WinForm跨平台串口通讯实现
  • ffmpeg下载地址
  • 数组题解——移除元素​【LeetCode】
  • Windows驱动开发最新教程笔记2025(一)名词解释
  • Nginx SSL/TLS协议栈中配置深度解析与实践指南-优雅草卓伊凡
  • From Tranformer to Decoder ONLY
  • 云原生周刊:Argo CD v3.1 正式发布
  • PyEcharts教程(009):PyEcharts绘制水球图
  • 【HTTP】取消已发送的请求
  • Leaflet面试题200道
  • C++修炼:智能指针
  • 自然语言处理入门
  • centos7 rpm 包升级openssh至10.0版本
  • 解码成都芯谷金融中心文化科技产业园:文化+科技双轮驱动
  • 枫清科技受邀参加2025数据智能大会
  • 如何通过nvm切换本地node环境详情教程(已装过node.js更改成nvm)
  • Vue3+el-table-v2虚拟表格大数据量多选功能详细教程
  • 字节跳动开源了一款 Deep Research 项目
  • YOLO、VOC、COCO数据集格式
  • C++中的数学计算库Eigen
  • LT8311EX一款适用于笔记本电脑,扩展坞的usb2.0高速运转芯片,成对使用,延伸长度达120米
  • EXCEL中实用的一些手段——BOM汇总查询
  • 【Datawhale组队学习202506】YOLO-Master task04 YOLO典型网络模块
  • 桥头守望者
  • 《前端资源守卫者:SRI安全防护全解析》
  • LangChain4j之会话功能AiServices工具类的使用(系列二)
  • 【WCF】单例模式的线程安全缓存管理器实现,给你的WebApi加入缓存吧
  • 【DeepSeek实战】3、Ollama实战指南:LobeChat+多网关架构打造高可用大模型集群