顺序IO和随机IO
随机IO
第一种:假设我们所需要的数据是随机分散在磁盘的不同页的不同扇区中的,那么找到相应的数据需要等到磁臂(寻址作用)旋转到指定的页,然后盘片寻找到对应的扇区,才能找到我们所需要的一块数据,一次进行此过程直到找完所有数据,这个就是随机IO,读取数据速度较慢。
顺序IO
第二种:假设我们已经找到了第一块数据,并且其他所需的数据就在这一块数据后边,那么就不需要重新寻址,可以依次拿到我们所需的数据,这个就叫顺序IO。
连续 I/O :指的是本次 I/O 给出的初始扇区地址和上一次 I/O 的结束扇区地址是完全连续或者相隔不多的。反之,如果相差很大,则算作一次随机 I/O。
同样的,就单次磁盘IO来说,我们不能说这次IO是顺序的还是随机的,这需要一个参照物。
连续 I/O 比随机 I/O 效率高的原因是:在做连续 I/O 的时候,磁头几乎不用换道,或者换道的时间很短;而对于随机 I/O,如果这个 I/O 很多的话,会导致磁头不停地换道,造成效率的极大降低。
扇区与块的区别
1、硬盘:
对硬盘分区:就是将磁盘分为一个一个的区域,可以方便归类使用。计算机是通过分区表来区别各个分区的。而分区表就存放在硬盘的固定扇区;(分区表一般位于硬盘的某柱面的0磁道 1扇区,而主分区表就位于0柱面,0磁道,1扇区。)
在安装操作系统时所进行的分区,实际上就是修改该硬盘的MBR(Master Boot Record,硬盘的主引导记录)。
硬盘分区有三种:主分区(primary partition),扩展分区,逻辑分区(logical partition)。
因为MBR上的DPT只有64字节,所以能储存的分区信息很有限,最多只能存储4个分区的信息。由此引入扩展分区(extended partition)。
逻辑分区是建立于扩展分区之上的。
扩展分区的工作原理就是在被划分为扩展分区的磁盘0柱面再建立一个新的DPT(硬盘分区表,Disk Partition Table,理论上大小无限制),上面用来储存逻辑分区的分区信息。
也就是通过主分区DPT找到扩展分区DPT,再通过扩展分区DPT找到各个逻辑分区。
新挂载了一个10GB的nvme盘
# fdisk -l //查看分区
Disk /dev/nvme0n2: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
对这个盘进行分区;
# fdisk /dev/nvme0n2
Welcome to fdisk (util-linux 2.32.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x906c02f6.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-20971519, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-20971519, default 20971519):
Created a new partition 1 of type 'Linux' and of size 10 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
[root@centos8 ~]#
再次检查;
# fdisk -l
Disk /dev/nvme0n2: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x906c02f6
Device Boot Start End Sectors Size Id Type
/dev/nvme0n2p1 2048 20971519 20969472 10G 83 Linux
nvme的盘,分区后,没看到heads参数,所以截取iscsi盘的参数
# fdisk -l
Disk /dev/hda: 80.0 GB, 80026361856 bytes
255 heads, 63 sectors/track, 9729 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
可以看到几个名词:heads/sectors/cylinders,分别就是磁头/扇区/柱面,每个扇区512byte(现在新的硬盘每个扇区有4K)了;
这个硬盘是80G的,有255个磁面;63个扇区;9729个磁柱;每个 cylinder(磁柱)的容量是 8225280 bytes=8225.280 K(约为)=8.225280M(约为);
硬盘容量就是:
$$ heads*sectors*cylinders*512"=255*63*9729*512byte=80,023,749,120b=80G //按1000进制计算,为80GB,按1024计算为,74.5GiB $$
注意:硬盘的最小存储单位就是扇区了,而且硬盘本身并没有block的概念。
2、操作系统的文件系统
文件系统是操作系统的基础部分。用来供操作系统组织与管理磁盘上的数据。
首先分区是必须的,因为操作系统要根据DPT(硬盘分区表,Disk Partition Table)才能识别相应的分区(都不识别的话,那就没法操作了)。
所以,要先分区才能进行格式化。另外,DPT中不仅仅记录了磁盘哪里到哪里是哪个分区,还记录了该分区的格式,也就是分区所采用的文件系统,这个会在系统启动时被使用;
文件系统不是一个扇区一个扇区的来读数据,太慢了,所以有了block(块)的概念,它是一个块一个块的读取的,block才是文件存取的最小单位。
对之前分区进行文件系统格式化,也就是:就是在一个个已经分好的区域上建立文件系统。
# mkfs.xfs /dev/sdb1 #格式化分区
Creating filesystem with 2621184 4k blocks and 655360 inodes
Filesystem UUID: ed01ce73-f884-4b4e-aea0-d37dc9f5a4c9
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
# mkdir /work #建立挂载点
# mount /dev/sdb1 /work #挂载硬盘
# tune2fs -l /dev/nvme0n2p1 | grep "Block size"
Block size: 4096
#
一个block是4K,也就是说我所使用的文件系统中1个块是由连续的8个扇区组成(8*512byte=4096btte)
简单的说扇区是对硬盘而言,块是对文件系统而言。
块是文件系统的抽象,不是磁盘本身的属性。 扇区大小则是磁盘的物理属性,它是磁盘设备寻址的最小单元。
Cache 和 Buffer 都是缓存,主要区别是什么?
背景知识一:我们现在的计算机、手机都是冯诺依曼架构,CPU只能操作内存中的数据,无法直接操作硬盘上的数据。
背景知识二:硬盘上的数据,最小读写单位是扇区(Sector)。老式硬盘上一个扇区是512字节,现代硬盘上一个扇区是4K字节。计算机不能以单个字节为单位访问硬盘上的数据。现在很常见的固态硬盘,物理上最小读写单位是页(Page),但大部分固态硬盘通过主控芯片模拟传统硬盘的扇区来进行读写。现代硬盘常用的LBA(Logical Block Addressing,逻辑块寻址)寻址方式,是把硬盘上的扇区分配从0~N-1的编号(N为硬盘上所有可用扇区数量)。
Cache,缓存:将缓慢的访问结果保存下来。
buffer,缓冲:将突发快速的访问平稳下来。
cache 是为了弥补高速设备和低速设备的鸿沟而引入的中间层,最终起到加快访问速度的作用。
而 buffer 的主要目的进行流量整形,把突发的大数量较小规模的 I/O 整理成平稳的小数量较大规模的 I/O,以减少响应次数(比如从网上下电影,你不能下一点点数据就写一下硬盘,而是积攒一定量的数据以后一整块一起写,不然硬盘都要被你玩坏了)。
1、Buffer(缓冲区)是系统两端处理速度平衡(从长时间尺度上看)时使用的。它的引入是为了减小短期内突发I/O的影响,起到流量整形的作用。比如生产者——消费者问题,他们产生和消耗资源的速度大体接近,加一个buffer可以抵消掉资源刚产生/消耗时的突然变化。
2、Cache(缓存)则是系统两端处理速度不匹配时的一种折衷策略。因为CPU和memory之间的速度差异越来越大,所以人们充分利用数据的局部性(locality)特征,通过使用存储系统分级(memory hierarchy)的策略来减小这种差异带来的影响。
3、假定以后存储器访问变得跟CPU做计算一样快,cache就可以消失,但是buffer依然存在。比如从网络上下载东西,瞬时速率可能会有较大变化,但从长期来看却是稳定的,这样就能通过引入一个buffer使得OS接收数据的速率更稳定,进一步减少对磁盘的伤害。
read cache(读缓存),read buffer(读缓冲),write cache(写缓存),write buffer(写缓冲)。
read cache(读缓存),read buffer(读缓冲):
读缓存跟读缓冲的最大区别在于,
read cache(读缓存)目标数据是始终有效的,如果不从缓存中读取,也可以直接读取实际数据,只不过实际数据读取会慢一些,当这个数据在缓存中,读取速度将会变快。当一个缓存中的数据被多次读取,实际上就减少了该数据从慢速设备中读取的量,这就存在某种算法去选择「什么数据需要保存在cache中」,因为尽可能多的让cache命中能提高性能。先进入cache的数据不一定先被读取,甚至说进入cache的数据有可能永远不被读取就被清除了,因此read cache呈现出非常明显的随机访问特性。
而read buffer(读缓冲)的数据则不是始终有效,而是实时生成的数据流,每当buffer满或者主动flush buffer的时候触发一次读取,对于小数据,这样可以减少读取次数,对于大数据,这可以控制单次读取的数据量。换句话说,无论数据量大还是小,单次读取数据量都按照buffer尺寸进行归一化了。通常来说,先喂给buffer的数据一定会先被读取,所有buffer的数据几乎一定会被读取,这是很明显的顺序访问特性。
从上面的情况看到,读缓存以及读缓冲很明确的反应出了我所说的表面特性。而其本质特性在于cache的目标是减少读取总量每次cache命中都减小了读取总量。而buffer并不能减少读取总量,只能规整化每次读取数据的尺寸大小。
write cache(写缓存),write buffer(写缓冲):
write buffer是read buffer的对应,对于小数据的写入,它需要填满write buffer再进行一次写入,对于大数据,大数据会被分割到buffer尺寸的大小分批写入。因此,write buffer 的用处在于使得每次写入的数据量相对固定。如果一次写入4k对某个设备来说效率最高,那么把buffer定为4k,小数据积攒到4k写一次,大数据分割到每个碎片4k多次写入,这样就是write buffer的用处。
最后我们来说write cache。所谓write cache,就是要设法减少写入次数。也就是说,如果某些数据需要产生多次写入,那么使用cache就可以只将最终数据写入,导致最终写入数据减少。在实际应用中,我们有时会使用到write buffer跟write cache的合体形态。
buffer本身需要规整尺寸,与此同时,buffer还允许多次随机写入,使得多次写入的数据只用写入最后一次,这属于cache的特性。BT软件使用的写缓存往往具有类似特性,因而这种形态它同时既是buffer又是cache。正因为在写入场合buffer跟cache没有那么明显的分界,所以才会有产生buffer跟cache究竟有啥区别的疑问。
我的结论:
在read(读取)的场合,cache通常被用于减少重复读取数据时的开销,而buffer则用于规整化每次读取数据的尺寸,在读取场合两者用途差别很大。
在write(写入)的场合,两者功能依然没变,但由于cache跟buffer的功能在写入场合可以融合使用,所以两者可以被混淆,写入缓冲跟写入缓存往往会同时担当规整化写入尺寸以及减少写入次数的功能,所以两者有时会被混淆,但这只是个名称问题,没有原则性关系。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。