Linux性能优化-文件系统和磁盘I/O原理

目录

索引节点和目录项

虚拟文件系统

文件系统I/O

磁盘

通用块层

磁盘性能指标

参考


 

索引节点和目录项

文件系统,本身是对纯粹设备上的文件,进程组织管理的机制,组织方式不同,就会形成不同的文件系统
Linux中一切皆文件,普通文件和目录,还有设备快,套接字,管道,都是统一用文件系统来管理的
为了方便管理,Linux文件系统为每个文件都分配两个数据结构,索引节点(index node)和目录项(directory entry),他们主要用来记录文件的元信息和目录结构

  1. 索引节点,inode用来记录文件的元数据,比如inode编号,文件大小,访问权限,修改日期,数据的位置等,索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中,索引也会占磁盘空间
  2. 目录项,dentry,用来记录文件的名字,索引节点指针和其他目录项的关联关系,多个关联的目录,构成了文件系统的目录结构,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以也叫目录项缓存
  3. 逻辑块,用连续磁盘扇区构成的最小读写单元,用来存储文件数
  4. 超级块,用来记录文件系统的状态,如索引节点和逻辑块的使用情况等

其中,目录项是一个内存缓存,而超级块,索引节点,逻辑块,都是存储在磁盘中的持久化数据

索引节点是每个文件的卫衣标志,而目录维护的是文件系统的树状结构,目录项和索引节点的关系是多对一,也就是一个文件可以由多个别名
比如通过硬链接为文件创建的别名,就会对应不同的目录项,不过这些目录项本质上还是链接同一个文件,索引他们的索引节点相同

磁盘读写的最小单位是扇区,512字节,文件系统把连续的扇区组成逻辑块,每次都以逻辑块为最小单位,来管理数据,常见的逻辑块大小为4KB,也就是8个连续的扇区
下图展示了 目录项,索引节点,文件数据的关系

Linux性能优化-文件系统和磁盘I/O原理_第1张图片


注意

  1. 目录项本身就是一个内存换出,索引节点则是存储在磁盘中的数据,比如Buffer和Cache就是为了缓解磁盘和CPU之间的性能差异出现的,将文件内容缓存到Cache中
  2. 磁盘在执行文件系统格式化时,会被分成三个存储区域,超级块,索引节点,数据块区

超级块,    存储整个文件系统的状态
索引节点区,存储索引节点
数据块区,  存储文件数据
 

 

虚拟文件系统

目录项,索引节点,逻辑块,超级块,构成了Linux文件系统的四大基本要素,为了支持各种不同的文件系统,Linux内核在用户进程和文件系统的中间,又引入了一个抽象层,叫虚拟文件系统VFS(Virtual File System)
VFS定义了一组所有文件系统都支持的数据结构和标准接口,当用户进程和内核中的其他子系统只需要跟VFS提供的统一接口进行交互就可以了,而不需要再关心底层各种文件系统的实现细节
关于Linux文件系统的架构图,文件系统调用,VFS,缓存,文件系统以及块存储之间的关系 如下

Linux性能优化-文件系统和磁盘I/O原理_第2张图片

这张图,在VFS下方,Linux支持各种各样的文件系统,如Ext4,XFS,NFS等,按照存储位置的不同,这样文件系统可以分为三类

  1. 基于磁盘的文件系统,也就是把数据直接存储在计算机本地挂在的磁盘中,如Ext4,XFS,OverlayFS等
  2. 基于内存的文件系统,也就是虚拟文件系统,这类文件系统,不需要任何磁盘分配存储空间,但会占用内存,/proc就是虚拟文件系统,/sys也属于这一类,主要向用户空间导出层次化的内核对象
  3. 网络文件系统,也就是用来访问其他计算机书籍的文件系统,比如NFS,SMB,iSCSI等

这些文件系统,要先挂在到VFS目录树种的某个子目录(称为挂载点),然后才能访问其中的文件,比如第一类基于磁盘的文件系统,在安装时要先挂载一个根目录/,在根目录下再把其他文件系统(比如其他的磁盘分区,/proc文件系统,/sys文件系统,NFS等)挂载进来

VFS定义了一组所有文件系统都支持的数据结构和标准接口,这样用户和内核中的其他子系统,就只需要跟VFS提供的统一接口进行交换就可以了
为了降低慢速磁盘对性能的影响文件系统又通过页缓存,目录项以及索引节点缓存,缓解磁盘延迟对应用程序的影响

通过df查看磁盘容量
df也可以查看inode

df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        482M     0  482M   0% /dev
tmpfs           493M     0  493M   0% /dev/shm
tmpfs           493M  424K  493M   1% /run
tmpfs           493M     0  493M   0% /sys/fs/cgroup
/dev/vda1        50G   13G   34G  28% /
tmpfs            99M     0   99M   0% /run/user/0

df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
devtmpfs        123275    350  122925    1% /dev
tmpfs           126117      1  126116    1% /dev/shm
tmpfs           126117    405  125712    1% /run
tmpfs           126117     17  126100    1% /sys/fs/cgroup
/dev/vda1      3276800 253595 3023205    8% /
tmpfs           126117      1  126116    1% /run/user/0

free输出的Cache,是页缓存和可回收Slab缓存的和,可以从meminfo中得到他们的大小

cat /proc/meminfo | grep -E "SReclaimable|Cache"
Cached:           524500 kB
SwapCached:            0 kB
SReclaimable:      45668 kB

具体到每一种Slab缓存,可以查看slabinfo文件,通过下面命令可以得到所有目录项和各种文件系统索引节点的缓存情况
dentry行表示目录项缓存,inode_cache行表示VFS索引节点缓存,其余的则是各种文件系统的索引节点缓存

cat /proc/slabinfo | grep -E '^#|dentry|inode'
# name                 : tunables    : slabdata   
ext4_inode_cache   15675  15675   1072   15    4 : tunables    0    0    0 : slabdata   1045   1045      0
mqueue_inode_cache      9      9    896    9    2 : tunables    0    0    0 : slabdata      1      1      0
hugetlbfs_inode_cache     13     13    608   13    2 : tunables    0    0    0 : slabdata      1      1      0
sock_inode_cache     120    120    640   12    2 : tunables    0    0    0 : slabdata     10     10      0
shmem_inode_cache    805    805    688   23    4 : tunables    0    0    0 : slabdata     35     35      0
proc_inode_cache    1433   1488    656   12    2 : tunables    0    0    0 : slabdata    124    124      0
inode_cache        10710  10710    584   14    2 : tunables    0    0    0 : slabdata    765    765      0
dentry             65751  65751    192   21    1 : tunables    0    0    0 : slabdata   3131   3131      0

使用slabtop观察缓存情况,slabtop按c后按照缓存大小排序的结果

 Active / Total Objects (% used)    : 227740 / 229249 (99.3%)
 Active / Total Slabs (% used)      : 8713 / 8713 (100.0%)
 Active / Total Caches (% used)     : 95 / 132 (72.0%)
 Active / Total Size (% used)       : 55541.06K / 56073.59K (99.1%)
 Minimum / Average / Maximum Object : 0.01K / 0.24K / 8.00K

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME                   
 15675  15675 100%    1.05K   1045       15     16720K ext4_inode_cache
 65856  65856 100%    0.19K   3136       21     12544K dentry
 10724  10724 100%    0.57K    766       14      6128K inode_cache     
 54600  54600 100%    0.10K   1400       39      5600K buffer_head
  5320   5320 100%    0.57K    380       14      3040K radix_tree_node
 13890  13890 100%    0.13K    463       30      1852K kernfs_node_cache
   296    296 100%    4.00K     37        8      1184K kmalloc-4k

slabtop按c后按照活跃对象数排序

 Active / Total Objects (% used)    : 227766 / 229249 (99.4%)
 Active / Total Slabs (% used)      : 8713 / 8713 (100.0%)
 Active / Total Caches (% used)     : 95 / 132 (72.0%)
 Active / Total Size (% used)       : 55547.56K / 56073.59K (99.1%)
 Minimum / Average / Maximum Object : 0.01K / 0.24K / 8.00K

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME                   
 65856  65856 100%    0.19K   3136       21     12544K dentry
 54600  54600 100%    0.10K   1400       39      5600K buffer_head
 15675  15675 100%    1.05K   1045       15     16720K ext4_inode_cache
 13890  13890 100%    0.13K    463       30      1852K kernfs_node_cache
 12036  11520  95%    0.04K    118      102       472K Acpi-Namespace
 10724  10724 100%    0.57K    766       14      6128K inode_cache
  8772   8772 100%    0.04K     86      102       344K ext4_extent_status
  5320   5320 100%    0.57K    380       14      3040K radix_tree_node

 

 

文件系统I/O

把文件系统挂载到挂载点后,就能通过挂载点,再去访问它管理的文件了,VFS提供了一组标准的文件访问接口,这些接口以系统调用的方式,提供给应用程序使用
比如cat 一个文件,首先调用open()打开一个文件,再调用read()读取内存,最后调用write()把文件内容输出到控制台标准输出中

int open(const char *pathname, int flags, mode_t mode);
ssize_t read(int fd, void *buf,size_t count);
ssize_t write(int fd, const void *buf, size_t count);

文件读写方式的各种差异,导致I/O的分类有很多,常见的有 缓冲与非缓冲I/O,直接与非直接I/O,阻塞与非阻塞I/O,同步与异步I/O
 

第一种,根据是否利用标准库缓存,可以把文件I/O分为缓冲I/O与非缓冲I/O

  • 缓冲I/O,是指利用标准库缓存来加速文件的访问,而标准库内部再通过系统调用访问文件
  • 非缓冲I/O,是指通过系统调用来访问文件,不再经过标准库缓存

注意,这里的 缓冲,是指标准库内部实现的缓存,比如很多程序到换行时才真正输出,而换行之前是被标准库暂时缓存起来了

第二种,根据是否利用操作系统的页缓存,可以把文件I/O分为直接I/O和非直接I/O

  • 直接I/O,是指跳过操作系统页缓存,直接跟文件系统交互来访问文件
  • 非直接I/O,在文件读写时,先经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘

要实现直接I/O,需要在系统调用中指定O_DIRECT标志,不设置默认是非直接I/O
注意,直接I/O和非直接I/O本质上还是和文件系统交互,如果在数据库等场景中,可以跳过文件系统读写磁盘的情况,就是裸I/

第三种,根据应用程序是否阻塞自身运行,可以把文件I/O分为阻塞I/O和非阻塞I/O

  • 阻塞I/O,是指应用程序执行I/O操作后,如果没有获得响应,就会阻塞当前线程,自然不能执行其他任务
  • 非阻塞I/O,是指应用程序执行I/O操作后,不会阻塞当前的线程,可以继续执行其他的人物,随后再通过轮询或者事件通知的形式,获取调用的结果

比如访问管道或者网络套接字时,设置O_NONBLOCK标志,就表示用非阻塞方式访问,默认是阻塞访问

第四种,根据是否等待项羽结果,可以把文件I/O分为同步和异步I/O

  • 同步I/O,是指应用程序执行I/O操作后,要一直等到整个I/O完成后,才能获得I/O响应
  • 异步I/O,是指应用程序执行I/O操作后,不用等待完成和完成后的响应,而是继续执行就可以,等到这次I/O完成后,响应会用事件通知的方式,告诉应用程序

比如访问管道或网络套接字时,设置了O_ASYNC选项后,相应的I/O就是异步I/O,这样内核再通过SIGIO或者SIGPOLL,来通知进程文件是否可读写

以上很多概念都来自网络编程,比如非阻塞I/O,通常跟select/poll配合,用在网络套接字的I/O中
所以Linux一切皆文件的深刻含义,无论是普通文件和块设备,还是网络套接字和管道等,都可以通过统一的VFS接口来访问

 

 

磁盘

磁盘可以是支持华存储的设备,根据存储介质的不同,常见磁盘可以分为机械磁盘,固态磁盘

1.机械磁盘,也成为硬盘驱动器(Hard Disk Driver),通常缩写为HDD,机械磁盘主要由盘片和读写磁头组成,数据就存储在盘片的环状磁道中,在读写数据前,需要移动读写磁头,定位到数据所在的磁道,然后才能访问数据
如果I/O请求刚好连续,就不需要磁道寻址,自然可以获得最佳性能,这其实就是我们熟悉的,连续I/O工作原理,与会对应的就是随机I/O,它需要不停的移动磁头,来定位数据位置,所以读写速度就比较慢

2.固态硬盘(Solid State Disk),通常缩写为SSD,由固态电子元器件组成,固态磁盘不需要磁道寻址,所以不管是连续I/O,还是随机I/O的性能,都比机械磁盘要好得多

无论机械盘还是固态磁盘,相同磁盘的随机I/O都要比连续I/O慢很多

  • 对机械磁盘来说,由于随机I/O需要更多的磁头晕倒和盘片旋转,它的性能自然比连续I/O慢
  • 对于固态磁盘,虽然它的随机性能比机械硬盘好很多,但同样存在“先擦除再写入”的限制,随机读写会导致大量的垃圾回收,导致随机I/O的性能比连续I/O还是差了很多
  • 连续I/O还可以通过预读取的方式,来减少I/O请求的次数,这也是其性能优异的一个原因,很多性能优化的方案,都会从这个角度出发,来优化I/O性能

机械磁盘和固态硬盘还有一个最小的读写单位

  • 机械磁盘的最小读写单位是扇区,一般为512字节
  • 固态硬盘的最小读写单位是页,通常大小是4KB,8KB等

由于每次读写512字节这么小的单位效率很低,所以文件系统会把连续的扇区,组成逻辑块,然后以逻辑快作为最小单位来管理数据,常见的逻辑块大小是4KB,也就是连续8个扇区,或者一个独立的页,都可以组成一个逻辑块

除了按照存储介质分类,另一种常见的分类方法,是按照接口来分类,比如把硬盘分为

  • IDE(Integrated Drive Electronics),
  • SCSI(Small Computer System Interface),
  • SAS(Serial Attached SCSI),
  • SATA(Serial ATA),
  • FC(Fibre Channel)

不同的接口,往往分配不同的设备名称,比如IDE设备会分配一个hd前缀的设备名,SCSI和SATA设备会分配一个sd前缀的设备名,或者是多块同类型的磁盘,就会按照a,b,长凳的字母顺序来编号
除了磁盘本身的分类外,当把磁盘介入服务器后,按照不同的使用方法,又可以把他们划分为多种不同的架构
最简单的,就是直接作为独立磁盘设备来使用,这些磁盘往往还会根据需要,划分为不同的逻辑分区,每个分区再用数字编号,比如
/dev/sda,还可以分成两个分区
/dev/sda1/,/dev/sda2

另一个比较常用的架构,是把多块磁盘组合成一个逻辑磁盘,构成冗余独立磁盘阵列,也就是RAID(Redundant Array of Independent Disks),从而可以提高数据访问性能,并且增强数据存储的可靠性
根据容量,性能和可靠性的不同,RAID一般分为多个级别,RAIDO,RAID1,RAID5,RAID10等

  • RAID0 有最优的读写性能,但不能提供数据冗余的功能
  • 而其他级别的RAID,在提供数据冗余的基础上,对读写性能也有一定程度的优化
     


网络存储
将这些磁盘组合成一个网络存储集群,再通过NFS,SMB,iSCSI等网络存储协议,暴露给服务器使用

在Linux中,磁盘实际上是作为一个块设备来管理的,也就是以块为单位读写数据,并且支持随机写,每个块设备都会被赋予两个设备号,分别是主,次设备号,主设备号用在驱动程序中,用来区分设备类型,次设备号则是用来给多个同类设备编号

 

通用块层

跟虚拟文件系统VFS类型, 为了减小不同块设备的差异带来的影响,Linux通过一个统一的通用块层,来管理不同的快设备
通用块层,处在文件系统和磁盘驱动中间的一个块设备层,主要有两个功能
跟虚拟文件系统的功能类似,向上,为文件系统和应用程序,提供访问块设备的标准接口,向下,把各种异构的磁盘设备抽象为统一的块设备,并提供统一框架来管理这些设备的驱动程序
通用块层还会给文件系统和应用程序发来的I/O请求排队,并通过重新排序,请求合并等方式,提高磁盘读写的效率

对于I/O请求排序的过程,也就是I/O调度,Linux内核支持四种I/O调度算法,分别是NONE,NOOP,CFQ,DeadLine

  1. None,这个并不能算法I/O调度算法,因为它完全不适用任何I/O调度器,对文件系统和应用程序I/O其实不做任何处理,常用在虚拟机中(此时磁盘I/O调度完全由物理机负责)
  2. Noop,最简单的一种I/O调度算法,它是一个先入先出的队列,只做一些最基本的请求合并,常用于SSD磁盘
  3. CFQ(Completely Fair Scheduler),也成为完全公平调度,是现在很多发行版的默认I/O调度器,它为每个进程维护了一个I/O调度队列,并按照时间片来均匀分布每个进程的I/O请求,类似于进程CPU调度,CFQ还支持进程I/O的优先级调度,所以它适用于运行大量进程的系统,像桌面环境,多媒体应用等
  4. DeadLine,分别为读,写请求创建了不同的I/O队列,可以提高机械磁盘的吞吐量,并确保达到最终期限(deadline)的请求被优先处理,此调度算法多用在I/O压力比较重的场景,如数据库等
     

Linux存储系统的I/O,从上倒下分为三个层次,分别是文件系统层,通用块层,设备层
这三个I/O层的关系如下图,也是Linux存储系统的I/O战全景图
Linux性能优化-文件系统和磁盘I/O原理_第3张图片

根据这张I/O栈的全景图,可以更清楚的理解,存储系统I/O的工作原理

  • 文件系统层,包括虚拟文件系统和其他各种文件系统的具体实现,它为上层的应用程序,提供标准的文件访问接口,对下会通过通用块层,来存储和管理磁盘数据
  • 通用块层,包括块设备I/O队列和I/O调度器,它会对文件系统的I/O请求队列进行排队,再通过重新排序和请求合并,然后才要发送给下一级的设备层
  • 设备层,包括存储设备和相应的驱动程序,负责最终物理设备的I/O操作

存储系统的I/O,通常是整个系统最慢的一环,所以Linux通过多种缓存机制来优化I/O效率
比如为了优化文件访问的性能,会使用页缓存,索引节点缓存,目录项缓存等多种缓存机制,以减少对下层设备的直接调用
同样,为了优化块设备的访问效率,会使用缓冲区,来缓存块设备的数据

 

 

磁盘性能指标

  • 使用率,是指磁盘处理I/O的时间百分比,过高的使用率(比如超过80%),通产意味着磁盘I/O存在性能瓶颈
  • 饱和度,是指磁盘处理I/O的繁忙程度,过高的饱和度,意味着磁盘存在严重的性能瓶颈,当饱和度为100%时,磁盘无法接受新的I/O请求
  • IOPS(Input/Output Per Second),是指每秒的I/O请求数
  • 吞吐量,是指每秒的I/O请求大小
  • 响应时间,是指I/O请求从发出到收到响应的间隔时间

注意,使用率只考虑有没有I/O,而不考虑I/O的大小,换句话说,当使用率是100%的时候,磁盘依然有可能接受新的I/O请求
不要孤立的去比较某一个非指标,而要结合读写比列,I/O类型(随机还是连续),以及I/O大小综合分析
比如,在数据库,大量小文件等这些类随机读写比较多的场景中,IOPS更能反映系统的整体性能
在多媒体等顺序读写较多的场景中,吞吐量才更能反映系统的整体性能

我们在位应用程序的服务器选型时,要限度磁盘的I/O性能进行基准测试,以便可以准确评估,磁盘性能是否可以满足应用程序的需求,可选的性能测试工具是 fio,来测试磁盘的IOPS,吞吐量以及响应时间等核心指标,在基准测试时,一定要注意跟进应用程序的I/O特点,来具体评估指标

需要测试出,不同I/O大小(一般是512B 到 1MB中间的某若干值)分别在随机读,顺序读,随机写,顺序写等各种场景下的性能情况
用性能工具得到这些指标,可以作为后续分析应用程序性能的依据,一旦发生性能问题,可以把他们作为磁盘性能的极限值,进而评估磁盘I/O的使用情况

iostat是最常用的磁盘I/O性能观测工具,它提供了每个磁盘的使用率,IOPS,吞吐量等各种常见的性能指标,当然这些指标实际上来自 /proc/diskstats
iostat的一些参数解释

              Device:
                     This column gives the device (or partition) name as listed in the /dev directory.

              tps
                     Indicate  the  number  of  transfers  per  second that were issued to the device. A transfer is an I/O request to the device. Multiple logical
                     requests can be combined into a single I/O request to the device. A transfer is of indeterminate size.

              Blk_read/s (kB_read/s, MB_read/s)
                     Indicate the amount of data read from the device expressed in a number of blocks (kilobytes, megabytes) per second. Blocks are  equivalent  to
                     sectors and therefore have a size of 512 bytes.

              Blk_wrtn/s (kB_wrtn/s, MB_wrtn/s)
                     Indicate the amount of data written to the device expressed in a number of blocks (kilobytes, megabytes) per second.

              Blk_read (kB_read, MB_read)
                     The total number of blocks (kilobytes, megabytes) read.

              Blk_wrtn (kB_wrtn, MB_wrtn)
                     The total number of blocks (kilobytes, megabytes) written.

              rrqm/s
                     The number of read requests merged per second that were queued to the device.

              wrqm/s
                     The number of write requests merged per second that were queued to the device.

              r/s
                     The number (after merges) of read requests completed per second for the device.

              w/s
                     The number (after merges) of write requests completed per second for the device.

              rsec/s (rkB/s, rMB/s)
                     The number of sectors (kilobytes, megabytes) read from the device per second.

              wsec/s (wkB/s, wMB/s)
                     The number of sectors (kilobytes, megabytes) written to the device per second.

              avgrq-sz
                     The average size (in sectors) of the requests that were issued to the device.

              avgqu-sz
                     The average queue length of the requests that were issued to the device.

              await
                     The  average  time (in milliseconds) for I/O requests issued to the device to be served. This includes the time spent by the requests in queue
                     and the time spent servicing them.

              r_await
                     The average time (in milliseconds) for read requests issued to the device to be served. This includes the time spent by the requests in  queue
                     and the time spent servicing them.

              w_await
                     The average time (in milliseconds) for write requests issued to the device to be served. This includes the time spent by the requests in queue
                     and the time spent servicing them.

              svctm
                     The average service time (in milliseconds) for I/O requests that were issued to the device. Warning! Do not trust this field any  more.   This
                     field will be removed in a future sysstat version.

              %util
                     Percentage  of  elapsed  time  during  which  I/O requests were issued to the device (bandwidth utilization for the device). Device saturation
                     occurs when this value is close to 100%.

iostat提供了非常丰富的性能指标,第一列的Device表示磁盘设备的名字,其他各列指标参考下图

Linux性能优化-文件系统和磁盘I/O原理_第4张图片

上图的这些指标中

  • %util,就是磁盘I/O使用率
  • r/s + w/s,就是IOPS
  • rkB/s + wkB/s,就是吞吐量
  • r_await + w_await,就是响应时间

在观测指标时,还要结合请求的大小(rareq-sz 和 wareq-sz)一起分析
从iostat并不能直接得到磁盘饱和度,饱和度通常也没有其他简单的观测方法,但可以把观测到的,平均请求队列长度或者读写请求完成的等待时间,跟基准测试的结果(比如通过fio)进行对比,综合评估磁盘的饱和情况

可以通过pidstat观察每个进程的I/O情况,包括如下内容
用户ID(UID)和进程ID(PID)
每秒读取的数据大小(kB_rd/s),单位是KB
每秒发出的写请求数据大小(kB_wr/s),单位是KB
每秒取消的写请求数据大小(kB_ccwr/s),单位是KB
块I/O延迟(iodelay),包括等待同步块I/O和换入块I/O结束的时间,单位是时钟周期

其他I/O工具还有 iotop
它的输出包括了进程的磁盘读写大小总数,磁盘真实的读写大小总数
因为缓存,缓冲区,I/O合并等因素的影响,它们可能并不相等,剩下的部分,是从各个角度来分别表示进程的I/O情况,包括线程ID,I/O优先级,每秒读写磁盘的大小,换入和等待I/O的时钟百分比等
这两个工具是分析磁盘I/O性能时最常用到的
 

 

 

参考

Ext4文件系统的超级块

磁盘相关命令

RAID总结

Linux_Storage_Stack_Diagram

 

 

你可能感兴趣的:(系统)