专栏首页人人都是极客聊聊Linux IO(上)

聊聊Linux IO(上)

写在前面

在开始正式的讨论前,我先抛出几个问题:

  • 谈到磁盘时,常说的HDD磁盘和SSD磁盘最大的区别是什么?这些差异会影响我们的系统设计吗?
  • 单线程写文件有点慢,那多开几个线程一起写是不是可以加速呢?
  • write(2)函数成功返回了,数据就已经成功写入磁盘了吗?此时设备断电会有影响吗?会丢失数据吗?
  • write(2)调用是原子的吗?多线程写文件是否要对文件加锁?有没有例外,比如O_APPEND方式?
  • 坊间传闻,mmap(2)的方式读文件比传统的方式要快,因为少一次拷贝。真是这样吗?为什么少一次拷贝?

如果你觉得这些问题都很简单,都能很明确的回答上来。那么很遗憾这篇文章不是为你准备的,你可以关掉网页去做其他更有意义的事情了。如果你觉得无法明确的回答这些问题,那么就耐心地读完这篇文章,相信不会浪费你的时间。受限于个人时间和文章篇幅,部分议题如果我不能给出更好的解释或者已有专业和严谨的资料,就只会给出相关的参考文献的链接,请读者自行参阅。

言归正传,我们的讨论从存储器的层次结构开始。

存储器的金字塔结构

受限于存储介质的存取速率和成本,现代计算机的存储结构呈现为金字塔型[1]。越往塔顶,存取效率越高、但成本也越高,所以容量也就越小。得益于程序访问的局部性原理[2],这种节省成本的做法也能取得不俗的运行效率。从存储器的层次结构以及计算机对数据的处理方式来看,上层一般作为下层的Cache层来使用(广义上的Cache)。比如寄存器缓存CPU Cache的数据,CPU Cache L1~L3层视具体实现彼此缓存或直接缓存内存的数据,而内存往往缓存来自本地磁盘的数据。

本文主要讨论磁盘IO操作,故只聚焦于Local Disk的访问特性和其与DRAM之间的数据交互。

无处不在的缓存

如图,当程序调用各类文件操作函数后,用户数据(User Data)到达磁盘(Disk)的流程如图所示[3]。图中描述了Linux下文件操作函数的层级关系和内存缓存层的存在位置。中间的黑色实线是用户态和内核态的分界线。

从上往下分析这张图,首先是C语言stdio库定义的相关文件操作函数,这些都是用户态实现的跨平台封装函数。stdio中实现的文件操作函数有自己的stdio buffer,这是在用户态实现的缓存。此处使用缓存的原因很简单——系统调用总是昂贵的。如果用户代码以较小的size不断的读或写文件的话,stdio库将多次的读或者写操作通过buffer进行聚合是可以提高程序运行效率的。stdio库同时也支持fflush(3)函数来主动的刷新buffer,主动的调用底层的系统调用立即更新buffer里的数据。特别地,setbuf(3)函数可以对stdio库的用户态buffer进行设置,甚至取消buffer的使用。

系统调用的read(2)/write(2)和真实的磁盘读写之间也存在一层buffer,这里用术语Kernel buffer cache来指代这一层缓存。在Linux下,文件的缓存习惯性的称之为Page Cache,而更低一级的设备的缓存称之为Buffer Cache. 这两个概念很容易混淆,这里简单的介绍下概念上的区别:Page Cache用于缓存文件的内容,和文件系统比较相关。文件的内容需要映射到实际的物理磁盘,这种映射关系由文件系统来完成;Buffer Cache用于缓存存储设备块(比如磁盘扇区)的数据,而不关心是否有文件系统的存在(文件系统的元数据缓存在Buffer Cache中)。

综上,既然讨论Linux下的IO操作,自然是跳过stdio库的用户态这一堆东西,直接讨论系统调用层面的概念了。对stdio库的IO层有兴趣的同学可以自行去了解。从上文的描述中也介绍了文件的内核级缓存是保存在文件系统的Page Cache中的。所以下篇的讨论基本上是讨论IO相关的系统调用和文件系统Page Cache的一些机制。

(未完待续...)

本文分享自微信公众号 - 人人都是极客(rrgeek)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-09-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 聊聊Linux IO(中)

    结合这个图,想想Linux系统编程里用到的Buffered IO、mmap(2)、Direct IO,这些机制怎么和Linux IO栈联系起来呢?上面的图有点复...

    刘盼
  • ZLG深度解析——语音识别技术

    语言作为人类的一种基本交流方式,在数千年历史中得到持续传承。近年来,语音识别技术的不断成熟,已广泛应用于我们的生活当中。语音识别技术是如何让机器“听懂”人类语言...

    刘盼
  • 第四课:模型的使用

    上一节我们创建了模型对象,也导入了测试集,可以说实现了一个简单机器学习的apk环境和核心代码。这一节我们一起看下开发一个完整的人工智能应用程序需要哪些步骤和代码...

    刘盼
  • 浅墨: 聊聊Linux IO(上)

    如果你觉得这些问题都很简单,都能很明确的回答上来。那么很遗憾这篇文章不是为你准备的,你可以关掉网页去做其他更有意义的事情了。如果你觉得无法明确的回答这些问题,那...

    Linux阅码场
  • JAVA架构 | Redis分布式缓存原理分析

    1引言 Redis是Remote Dictionary Server(Redis) 的缩写,或许光听名字你就能猜出它大概是做什么的。不错,它是一个由Salvat...

    码神联盟
  • Redis使用指南

    使用Redis做K-V存储,一定要注意过期时间的把控,任何K-V的存储都要设置过期时间,不管多长时间。一般在封装Redis操作工具类时提供默认使用系统公共超时时...

    编程大道
  • ehcache.xml参数配置说明

    ehcache.xml参数配置说明: <?xml version="1.0" encoding="UTF-8"?> <ehcache updateCheck="...

    小柒2012
  • Spring Cache For Redis.

    一、概述 缓存(Caching)可以存储经常会用到的信息,这样每次需要的时候,这些信息都是立即可用的。      常用的缓存数据库: Redis   使用内存...

    JMCui
  • SpringBoot系列之缓存使用教程

    介绍SpringBoot项目中使用缓存,之前先介绍一下Spring的缓存抽象和JSR107,本博客是我在学习尚硅谷视频和参考其它博客之后做的笔记,仅供学习参考

    用户1208223
  • 缓存穿透、缓存雪崩、缓存热点

    摘要:本文主要讲解在使用缓存的过程中,经常出现的三个问题:缓存穿透、缓存雪崩、缓存热点。

    IT云清

扫码关注云+社区

领取腾讯云代金券