September 27th, 2014
《大话存储》存储技术系列笔记

存储技术如今已经越来越重要,而且在云计算时代,涌现出了很多专注于云存储的厂商。存储技术本身也十分复杂,从硬件到协议到软件到接口几乎覆盖计算机科学的方方面面。笔者借助《大话存储II》这本书,开始了这块知识空白的补充。本文的图片均来源于网络。

卷管理(Volume Manager)

卷管理的原理

RAID在硬件层面提高了物理磁盘的性能、可靠性和利用率,它提供给上层操作系统虚拟的磁盘,在操作系统看来是物理磁盘。但是,随之带来的问题是,如果某块虚拟的磁盘哪一天不够用了怎么办?无法动态的添加容量。为了解决这个问题,在操作系统和RAID(或直接的磁盘控制器)之间产生了一种叫卷管理器(Volume Manager)的软件。

卷管理器将RAID提交上来的磁盘进行再划分和再重组,使得操作系统可以自由的对卷进行管理。为了理解卷管理,首先来看几个概念:

  • PV(Physical Volume):即是RAID提交上来的虚拟磁盘(对于卷管理器而言它是物理磁盘),只是换个名词,提交上来几个虚拟磁盘就有几个PV
  • PE(Physical Extends):将PV进行等大小划分出来的物理区块,每个PE都代表着PV上从几号扇区到几号扇区,PE是分割和合并的最小单位,可以在卷管理中设置
  • VG(Volume Group):卷管理器将PE进行组合,组成逻辑上的大的容器池,称为VG
  • LV(Logical Volume):从VG中将若干数量的PE组合成逻辑卷。在Linux中,一个逻辑卷就可以被挂在到相应的目录。

下面的图可以说明上述的概念之间的关系:

卷管理通过划分PE,将物理的磁盘分割,并进行再重组。这样就可以在某个逻辑卷空间不足时将其他逻辑卷的PE搬一些过来使用。所以对于上层操作系统而言,逻辑卷是灵活多了。但是,这些关系是如此的繁杂,卷管理需要维护这些对应关系,所以需要在磁盘上保存卷配置信息,比如PE大小、初始偏移、PV的数量和信息、排列顺序等。存储这个配置信息的区域叫做VGDA(Volume Group Descriptor Area)。当卷管理器初始化时需要从VGDA上加载信息,并生成映射公式,当上层系统发起IO请求时,卷管理器需要换算成实际磁盘及物理扇区位置(当然这些磁盘和物理扇区本身可能都是虚拟的),并通过驱动程序告知下层的控制器如何存取磁盘。

卷管理器甚至还具有软RAID功能,可以将逻辑卷看成物理磁盘,组成RAID。

分区

分区实际上也可以看成一种简单的卷管理,是操作系统自带的卷管理程序,但是只能管理单个磁盘,不能将多个磁盘组合成虚拟卷再划分,不具备灵活的功能。我们通常见到的C:D:E:…盘就是通过分区得到的逻辑卷。操作系统可以针对分区(逻辑卷)进行格式化。

BIOS在进行引导时,总是会执行LBA1扇区上的指令,以加载操作系统,这个扇区称为MBR(Master Boot Recorder),其中还保存着分区表。通常第一条指令都是跳转到活动分区读取操作系统的代码并执行。在修改了分区设置的后,分区表会被更新。

卷管理程序同样需要遵从BIOS和MBR,只不过它除了各个磁盘上写入VGDA外,也要更新MBR中的分区表,划分出一个小分区,将启动操作系统的代码放在这个分区中,并表明bootable类型。在Linux中,这个分区就是/boot分区,其中包含有操作系统的启动代码,大约只需要100MB。

BIOS执行的第一条指令位置总是LBA1,这是固定的。现在提出的新的EFI规范,可以配置第一条指令的所在扇区

在Linux中,每一个硬件设备都映射到一个系统的文件,对于硬盘、光驱等 IDE 或 SCSI 设备也不例外。Linux 把各种IDE设备分配了一个由hd前缀组成的文件;而对于各种SCSI设备,则分配了一个由sd前缀组成的文件。例如,第一个IDE设备,Linux就定义为hda;第二个IDE设备就定义为hdb;下面以此类推。而SCSI设备就应该是sdasdb等。每一个硬盘设备最多能有4个主分区(其中包含扩展分区)构成,任何一个扩展分区都要占用一个主分区号码,也就是在一个硬盘中,主分区和扩展分区一共最多是4个。主分区的作用就是计算机用来进行启动操作系统的,因此每一个操作系统的引导程序,都应该存放在主分区上。扩展分区可以进一步划分为逻辑分区。以第一个IDE硬盘为例说明,主分区(或者扩展分区)占用了hda1hda2hda3hda4,而逻辑分区占用了hda5hda16等12个号码。因此,Linux下每一个硬盘总共最多有16个分区。下面是一个分区的例子:

从图中我们解读到如下信息:

  • 上图是一块SCSI设备硬盘,大小320G,被映射到/dev/sda
  • 划分了一个主分区用于装系统本身,大小41G左右,分区号1
  • 剩余的空间划分了一个逻辑分区,分区号2,5-10号的逻辑分区都是由这个扩展分区划分出来的
  • 5-10是逻辑分区,有多种文件系统类型

文件系统

扇区是存储的最小单位。然而,如果应用程序直接以扇区为单位进行存取,不但大大增加了复杂度,而且还增加了安全隐患。所以,需要由操作系统提供同一个管理接口,应用程序通过调用接口来完成数据的存取。也就是说,操作系统实际上就是在裸(Raw)设备的基础上,对磁盘进行逻辑上的结构化调整,并向上提供操作接口。这样的东东就是文件系统。文件系统对磁盘不同的组织方式就形成了不同的文件系统。例如FAT32NTFSEXT

从磁盘的角度,读写的最小单位是扇区,但是如果读取文件都以扇区为单位的话,效率将是低下的。因为,扇区的只有512字节,读取较大体积的文件将极大增加IO的次数。于是,有了逻辑块的概念,也就是文件系统中的最小存储单元。一般,逻辑块的大小为4KB,这样比以扇区为单位读写数据要减少了8倍的IO数量。不过,由于逻辑块是文件系统的最小存储单位,所以,如果存储的文件小于4KB,也必须占用完整的4KB,因此,逻辑块也不是越大越好,太大的话会导致空间利用率下降。

EXT2文件系统

ext2文件系统是Linux使用的默认文件系统。在ext2文件系统中,文件的属性和内容被分开存放。其中,文件的属性存放在inode中,而文件的内容放在逻辑块中。一个文件有可能占用一个或多个逻辑块(block),但是一个文件仅仅对应一个inode,下面介绍inode

  • inode好比文件的索引,除了记录文件的属性外,还要记录文件内容所在地逻辑块号。因此,读取文件时必须从inode中得到文件的块号
  • inode本身大小有限,如果文件比较大,inode的数据结构无法容纳所有的逻辑块号的话,就需要借用逻辑块来存放
  • inode的数量决定了文件的最大数量
  • 目录也要占用一个inode,一个目录最少需要一个inode和一个block,在block中存放相关的文件或目录。因此如果要查找一个目录下的文件,需要从根目录的inode开始,一层层往下找

参考:EXT2 文件系统

inode/block示意图

较大的文件需要动用block来记录块号

文件系统的IO类型

文件系统的IO类型分为同步IO异步IO阻塞/非阻塞IO和Direct IO。这些分类不是同一层次的,需要分开讨论:

对于应用程序而言,需要调用操作系统文件系统的接口,这种接口可以分为同步IO和异步IO:

  • 同步IO是指应用程序的线程发起IO请求后,会被操作系统挂起,直到IO完成后,重新唤醒线程并把结果告知线程。此时,线程会处于等待状态,无法继续执行。
  • 异步IO是指操作系统不会挂起发起请求的线程,而是会继续执行该线程,当IO完成后跑到线程的回调函数中,以处理完成的IO结果。异步IO下,线程得以继续执行而不会等待。

阻塞/非阻塞IO是个广义的概念,是指普遍意义上的上层程序向下层程序发起IO请求后是否等待下层程序:

  • 阻塞IO情况下上层程序会等待下层程序的返回才继续执行后面的代码
  • 非阻塞IO情况下上层程序不会等待下层程序,而是继续执行自己的代码,直到下层程序发起完成通知

同步IO是阻塞IO的一种,异步IO是非阻塞IO的一种。

文件系统具有自己的缓存系统和缓存算法,以实现写速度的提升和“预读”。Direct IO就是告诉文件系统不使用缓存,而是直接将数据写入磁盘。数据库应用是使用Direct IO的典型应用,因为数据库自己有实现一套数据缓存和Flush算法。比如Oracle甚至有独立的进程DBWR来完成数据的Flush。


1块2块也是钱,小额赞助