曾经作嵌入式开发的我,如今作服务器开发,不少思路要转变。今天学习了服务器高性能IO设计,同时本身也还发散开去学习了其余的一些参考资料,顺便结合本身已有的一些知识,作为本身的学习笔记,总结和记录一下吧~~html
本文首先从硬件原理的角度,阐述提升硬盘 I/O 效率的途径。
本文包括一些小知识,与高性能服务器开发没有直接关系,不感兴趣的话能够跳过。segmentfault
本文地址:http://www.javashuo.com/article/p-aadigvbs-hr.html缓存
这里我所说的 “硬盘”,也就是所谓的 “hard disk”,常常简称为 “disk” 或者 “HDD”,同时还有另一个更加高大上的名字 “非易失性存储”。安全
请各位回忆一下计算机组成原理里关于存储的部分,从 CPU 开始,存储层次以下:服务器
非易失性存储就是说该存储介质上的数据,只要写入了,那么就算设备掉电了,也可以保持,而不会被清空。
广义而言,非易失性存储包含很是多的种类,包括磁盘、闪存、EEPROM 等等。而对于服务器而言,只涉及两种,那就是磁盘和 SSD。网络
磁盘使用磁性元件作成盘片,而后使用盘片上对应位置是否有磁性,来判断该位置存储的值是逻辑 1 仍是逻辑 0。
另外一种是固态硬盘,也就是 SSD。SSD 的原理其实就是咱们的 “U盘”。从存储介质的角度,“U盘” 其实不是一个准确的说法,准确的说,应该叫作 “闪存”(flash memory)。oop
从制造原理上,闪存又分为两种,一种是 NOR-flash,另外一种是 NAND-Flash。NOR-Flash 不会在服务器上使用,正文略过不讲(感兴趣的话,能够看本文的小知识)。本文关注的是使用 NAND-Flash 制做而成的硬盘,也就是 SSD。性能
Linux 中,全部的东西均可以抽象成文件。而全部的设备,则会被分为字符设备和块设备。
字符设备的意思是,对于该设备上随机指定的地址的值,均可以直接写入。学习
相对应地,块设备的意思是,对于该设备上随机指定的地址上的数据,若是须要修改的话,须要连同该地址周边一整块数据都一块儿读到内存中、修改了指定数据以后,再整块写回。优化
<<<< 小知识:为何 SSD 是块设备?为何写入这么麻烦?>>>> SSD 不能简单随机地读写给定地址上的数据。SSD 读取以 ”页“ 为单位(如:256 Bytes),擦除 / 写入以 ”块“ (与内存映射的 “4kB” 的那个 “块” 不是一回事) 为单位。 此外,SSD 还有一个很大的特色,就是修改对应数据的时候,还不是简单地执行一个 write 动做 (不是标准 C 的 write())就能够了,而是须要首先执行一次 erase 操做,将当前的整个块擦除掉 (所有变成逻辑 0),而后再将整个块的数据从新写一遍。 因此对于块设备而言,执行读操做还算简单,可是执行写操做的话,整个流程就变成了:read、erase、 write 了,何其复杂!SSD 之因此被设计成这么复杂的缘由,主要是半导体比特密度和制形成本之间的一个 取舍。原理能够写一整章,本文就不展开讲了。 为何磁盘是块设备?这个很抱歉,笔者没有准确的答案。或许由于磁盘转的太快,没办法极其精 准地定位具体一个 bit?
这里咱们先放下 SSD,来说一讲磁盘。我的电脑和服务器上所使用的磁盘结构都是如出一辙的。磁盘的结构和各术语以下图所示:
磁盘中会并列地摆放不少片盘片,每一个盘片的正反面都会有一个磁头,使用这个磁头来读取盘片上的磁状态。读数据的时候,通常会同时从几个盘片读,以达到最高的读取速度。
因此咱们能够看到,磁盘寻址的速度,主要受到如下两个因素的影响:
极端状况下,磁头须要从一端转到另外一端;而盘片则须要转动 180 度。
乍一看,其实这两个时间是很是短的,彷佛并不会影响读取文件的速度。两边引发质变,这两个时间积累起来的时候,就会出现问题了。那么怎样才能累积呢?答案就是:频繁、随机地存取文件系统。
因此,提升磁盘效率的思路就是:避免频繁的随机存取文件
这里所说的包含磁盘和 SSD。前面已经说了,硬盘是块设备,也就是当读取内容的时候,只能以块为单位进行操做。
这里举一个最简单的例子吧,咱们把块的单位减小到 8bits,存取的单位以 bits 来计算。好比在一段连续的内存中,数据是这样的:
Addr: 0 1 2 3 4 5 6 7 value: 0 0 1 1 0 1 0 0
咱们只须要读取地址 5 上的值,这就是所谓的随机读取。可是硬盘的原理决定了咱们没办法只读这么一个数据。驱动只能把这一整块的数据(00110100)一块儿读出来,而后再把这地址 5 的值返回给应用程序。
写入的时候就更复杂了。针对 SSD,若是咱们须要把地址 5 上的值改成 0,那么驱动须要干下面几件事情:
磁盘还算比较简单,只须要执行 1 和 4 两个步骤就好了。
从上面的流程咱们大概能够看到磁盘文件存取速度的优化方向了。若是你还没弄明白的话,我再举一个例子:
假设仍是上面的多个 SSD 块,咱们作一次循环操做来模拟屡次存取。伪代码以下:
define SECT_SIZE (5) int addr = 0; for (sectNum = 0 to 100) { bits[SECT_SIZE] = read_data(from: addr, len: SECT_SIZE); bits[0] = 0; bits[SECT_SIZE - 1] = 0; // 只修改一部分 write_data(data: bits, from: addr, len: SECT_SIZE) addr += SECT_SIZE }
这段代码有什么问题呢?咱们只须要取前两次循环,看看驱动作了什事情就知道了。
首先是第一次循环(Loop 0):
此时 addr = 0, 1. 从 0 号块读出 8 bits 的数据,而且取其中的 5bits 返回给应用程序(耗时 t1) 2. 应用程序修改了两个 bits 3. 将 0 号块的 8bits 写回(擦除 + 写入,耗时 t2)
第二次循环就不同了:
此时 addr = 5 1. 从 0 号块取出 8bits 的数据,而且取最后 3bits 为有效数据(耗时 t1) 2. 从 1 号块取出 8bits 的数据,而且取前 2bits 为有效数据,与前面的 3bits 拼在一块儿,返回 5bits 给应用程序(耗时 t1) 3. 应用程序修改了两个 bits 4. 将 0 号块的 8bits 写回(耗时 t2) 5. 将 1 号块的 8bits 写回(耗时 t2) 总耗时是第一个循环的两倍。
可见,因为横跨了两个块,虽然应用程序操做的数据量是同样的,可是操做的时间却多出了整整一倍。
所以从这里咱们能够看出,提升硬盘存取效率的另外一个途径是:尽量以块为单位,进行读写操做。在操做系统中,软件层面关心的块的单位通常是 4096 字节(4kB)。
一句话,NOR Flash 只用在嵌入式设备中,作服务器开发的不须要关心。本小节没有正片,只有小知识。
<<<< 小知识:NOR Flash 是什么?有什么特色? >>>> NOR Flash 和本文所说的 SDD(NAND Flash)的区别,首先在硬件结构上显然是不一样的。可是嘛, 如前文所述,硬件的咱不讲。 NOR Flash 的特色有下面几点: 1. NOR Flash 也是块设备,但 NOR Flash 支持绝对的随机读取,要读多长就读多长,而且读取 速度高于 NAND Flash 2. 相同条件下,NOR Flash 的擦除和写入耗时远远大于 NAND Flash 3. NOR Flash 支持有限的随机写能力,所谓有限,意思是 NOR Flash 能够将任意逻辑 0 的位改 写为逻辑 1,可是却没办法将 1 改写为 0 4. NOR 执行块的擦除操做后,整个块都会变成逻辑 0。所以对于绝大部分数据(0 和 1 混杂的) 写入操做,实际上和 NAND Flash 的操做流程是同样的 5. 当容量小于 16MB 时,NOR Flash 的成本小于 NAND Flash。再往上就不如 NAND 了。 上面的特性,使得 NOR Flash 几乎不会用在 PC 的存储体系中。但却在嵌入式设备中(包括计算 机主板上 BIOS 的存储器)应用极广,由于: 1. 嵌入式设备主要是保存大量的代码数据(只读,特色1),和少数而且不多变更的用户数据(读写, 特色1) 2. 嵌入式设备的程序空间很小,裁减过的 Linux 内核通过压缩能够达到2MB 甚至更低(特色5) 3. 嵌入式设备可能随时断电,支持 jffs2 文件系统以后,能够保护文件内容(特色3)
<<<< 小知识:为何支持了 jffs2 就支持断电保护?>>>> 能够说 jffs2 简直就是为 NOR Flash 量身定作的文件系统了。通常而言,好比咱们使用 FAT32 对 U盘进行格式化以后,若是 U盘在写入数据的时候忽然从主机设备上拔掉,那么文件系统极可能会崩 溃、损坏。这就是为何操做系统会有 “安全移除存储设备” 的功能。 Jffs2 完美地利用了 NOR Flash “能够将 0 改写为 1” 的特性。首先在格式化的时候,jffs2 以 块为单位划分存储空间,而后在建立索引表的时候。文件系统在将数据写完以前,会对应的块设置为 0, 也就是标记为无效块。当数据彻底写入完成以后,就将标记从 0 修改成 1。而 jffs2 每次加载的时候, 会遍历全部的块,而且在内存中重建索引表。 若是在写入数据的过程当中断电了,那么相应的块继续保持无效状态。这样就保证了文件系统的断电 保护。 固然 jffs2 的原理远远没有这么简单。Linux 里面就有 jffs2 的代码,各位看官能够自行取用。
针对硬盘做为块设备的各类特色,从硬件原理上优化磁盘效率,咱们的思路主要就是两个方向:
实际代码中具体应该怎么操做,在下一篇文中给出。