编程知识 cdmana.com

计算机原理探险系列(四)-- 磁盘存储探秘

各位读者朋友们大家好,今天我们一起来聊聊关于计算机底层磁盘的读取原理。

磁盘的基本布局

磁盘的基本结构主要包含有以下几点,磁盘盘片,读写磁盘的指针,传动轴,主轴等。

图片

每次用户程序从用户态发送一条指令给到操作系统内核,进行io读取数据的时候,cpu的ring3级别内核便会通过io总线发送一个指令给到读写磁头,然后由读写磁头定位到盘片的指定位置进行数据读写。最后再通过io总线将数据返回给到用户态的程序中。

下边是一张磁盘盘面的大致结构图:

在这里插入图片描述

在磁盘的盘面上通常会布有许多层的磁道,可以理解为图中的同心圆,然后每层磁道上分有不同范围的扇区,数据存储落在这些扇区的范围当中。磁盘指针头通常会落在盘道的一个位置点,然后朝一定方向旋转进行数据的搜索。

内围的磁道数据其实和外围的磁道数据是一样多的,这也就意味着外围的数据密度要比内围的小很多。现如今采用了区位记录的技术,保证了内围的磁道要比外围的磁道少,保证了密度的均匀性
影响磁盘指针定位数据的性能因素

寻道时间
磁盘指针定位到指定的盘道耗时
旋转延迟
指针定位到盘道之后进行旋转读取数据
数据传输
从内核态将数据传输给到用户态的耗时

通常技术人员会通过这么一条公式来推算一块磁盘的读写性能:

iops 指标:磁盘的每秒数据输入输出量,计算思路:1000ms / (数据寻道时间 + 旋转延迟时间 + 数据传输时间) 。

如今的硬件技术开始支持一些分散聚合DMA技术,能够支持将一些原先不连续的磁道数据进行组合读取,效率性更高。由于这种设备支持的磁道信息并不是一定连续的,所以有一个新的概念叫做段。
图片

磁盘毕竟是一个物理硬件层面的东西,那么早期的发明家则通过了一些抽象的概念在程序中对磁盘做访问。下边我们来介绍下经典的文件系统设计。

文件存储

在linux操作系统中,常说的一句话就是“一切皆文件“。
文件系统更像是一周抽象化的数据结构设计,其主要分为了两大模块,inode区和数据区。下边的文章我主要以ext2这种文件系统作为案例进行分析。

在ext2文件系统中磁盘数据通常是以block为单位进行存储的,多个连续的block的组合被称之为BlockGroup。
BlockGroup内部存储的数据较多,主要包含有两个模块:Inode区,Data Block区。Data Block区比较好理解,主要就是存储真实的文件信息,下边主要介绍下Inode区。

Inode区
每一份文件在进行存储的时除了需要记录文件内部的数据外,还会记录一些额外的元数据信息,例如说创建人,创建时间,修改时间,读写权限等。这些基础信息就统一存放在inode里面。
inode区内部主要包含以下内容:

  • 文件的字节数
  • 文件拥有者的User ID
  • 文件的Group ID
  • 文件的读、写、执行权限
  • 文件的时间戳 ,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
  • 链接数,即有多少文件名指向这个inode 文件数据block的位置

OS在实际打开一份文件的时候,其实并不是单纯依靠文件的名称和路径去查询对应数据的存储地址。每份文件在OS内部都会有一个指定编号对应,这个编号我们一般称之为inode 序号。

例如在OS接收用户点击鼠标打开一份word文档的时候,实际上会先根据用户点击文件的所在路径+文件名去查找对应的inode编号,根据这个编号找到inode块,再在inode块找到对应的数据指针,根据数据指针的地址获取到数据的真实信息。

查看inode的相关信息

[[email protected] project]# stat ./log.file
  文件:"./log.file"
  大小:72545648    块:141704     IO 块:4096   普通文件
设备:fd01h/64769d  Inode:1185980     硬链接:1
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
最近访问:2021-03-12 15:48:32.301232824 +0800
最近更改:2021-03-26 07:52:47.916795277 +0800
最近改动:2021-03-26 07:52:47.916795277 +0800
创建时间:

有时候如果文件名称有乱码无法删除的话,可以通过删除inode号来实现删除效果。

数据存储在多个block区域中后,通常是在inode中会有1个数据指针负责多个block的映射,如果数据非常大,就需要有多个映射block的指针,但是inode的空间有限,一般是128kb,所以这里会有一种多级映射的设计,如同下图:
在这里插入图片描述

操作系统在读取数据的时候并不会一个一个扇区去读取数据,这样读取太慢了,通常是一个一个block(通常一个block包含有多个扇区)去读取的。

查看操作系统内部的inode数目

[[email protected] project]# df -i
文件系统         Inode 已用(I) 可用(I) 已用(I)% 挂载点
/dev/vda1      2621440  300043 2321397      12% /
devtmpfs        233122     322  232800       1% /dev
tmpfs           235465       1  235464       1% /dev/shm
tmpfs           235465     391  235074       1% /run
tmpfs           235465      16  235449       1% /sys/fs/cgroup
tmpfs           235465       1  235464       1% /run/user/0

硬连接和软连接

硬连接:每个文件本质都是用inode号码去识别的,所以如果我们用不同的命名指向同一个inode号码也可以达到同样效果。

ln 源文件 目标文件

inode内部有个连接数,就是专门记录有多少个链接指向了自己。使用硬连接的方式需要对目标文件的inode内部连接数做修改+1操作。

[[email protected] project]# ln ./log.file ./log2.file
[[email protected] project]# ls
arthas         echarts.min.js  go             idea-blog.jar.original  log2.file  origin-jar  springboot-docker  stop.sh  test
arthas-output  files           idea-blog.jar  link                    log.file   project     start.sh           tank

软连接可以理解为在源文件A内部注入目标文件B的所在地址。这样就意味着查看A文件的时候就能看到B文件的信息,但是如果B文件被删除,那么A文件就会丢失无法打开。
如何使用命令创建软连接:

ln -s 源文件 目标文件

软连接和硬连接的本质区别:目标文件的链接数是否会增加

磁盘的IO读写

顺序读写和随机读写对于机械硬盘来说为什么性能差异巨大?

顺序读写=读取一个大文件
随机读写=读取多个小文件

顺序读写比随机读写快的原因

①顺序读写,主要时间花费在了传输时间,而这个时间两种读写可以认为是一样的。随机读写,需要多次寻道和旋转延迟。而这个时间可能是传输时间的许多倍。

②顺序读写,磁盘会预读,预读即在读取的起始地址连续读取多个页面
(现在不需要的页面也读取了,这样以后用时就不用再读取,当一个页面用到时,大多数情况下,它周围的页面也会被用到)。而随机读写,因为数据没有在一起,将预读浪费掉了。

③另一个原因是文件系统的overhead。
读写一个文件之前,得一层层目录找到这个文件,以及做一堆属性、权限之类的检查。写新文件时还要加上寻找磁盘可用空间的耗时。对于小文件,这些时间消耗的占比就非常大了。

常见的一些优化写性能的手段:

追加写
每次将数据添加到文件。由于完全是顺序的,所以可以具有非常好的写操作性能。但是这种方式也存在一些缺点:从文件中读一些数据时将会需要更多的时间:需要倒序扫描,直到找到所需要的内容。
文件合并和元数据优化

ext2文件系统在海量的小文件应用下性能表现情况其实并不佳,具体原因如下:

由于小文件数据内容较少,因此元数据的访问性能对小文件访问性能影响巨大。Ext2文件系统中Inode和Data Block分别保存在不同的物理位置上,一次读操作需要至少经过两次的独立访问。在海量小文件应用下,Inode的频繁访问,使得原本的并发访问转变为了海量的随机访问,大大降低了性能。另外,大量的小文件会快速耗尽Inode资源,导致磁盘尽管有大量Data Block剩余也无法存储文件,会浪费磁盘空间。

Ext2在Inode中使用多级指针来索引数据块。对于大文件,数据块的分配会尽量连续,这样会具有比较好的空间局部性。但是对于小文件,数据块可能零散分布在磁盘上的不同位置,并且会造成大量的磁盘碎片,不仅造成访问性能下降,还大量浪费了磁盘空间。数据块一般为1KB、2KB或4KB,对于小于4KB的小文件,Inode与数据的分开存储破坏了空间局部性,同时也造成了大量的随机I/O。

优化的策略
针对数据布局低效,采用小文件合并策略,将小文件合并为大文件。
针对元数据管理低效,优化元数据的存储和管理。针对这两种优化方式,业内也出现了许多优秀的开源软件。

版权声明
本文为[Danny_idea]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Danny_idea/article/details/116067024

Scroll to Top