我们先来回顾一下机械硬盘的结构。
机械硬盘主要由盘片(platter)、磁头(head)和相应的控制电路等部分所组成。盘片表面镀有磁性物质,二进制位被存储在这些磁性材料上。硬盘工作时,盘片围绕着一根中心主轴(spindle)旋转,磁头在电路控制下移动到指定位置然后将数据存储或读取出来。
盘片有两个面,都可以储存数据,因此每个磁盘片对应两个读写磁头。如果有N个盘片,就有2N个面,对应2N个磁头。
以盘片中心为圆心,把盘片分成若干个同心圆,每一个划分圆的"线条",就称为磁道(track)。
所有盘面上半径相同的磁道构成了柱面(cylinder)。盘片中有多少个磁道,就有多少个柱面。
每个磁道又被等分为若干个弧段,这些弧段便是磁盘的扇区(sector)。扇区大小是固定的,两扇区之间以间隙(gap)来分割,间隙未被磁化。由于越接近磁盘圆心,磁道就越小,因此每个磁道的扇区数可能是不同的。在一些硬盘的参数列表上可以看到描述每个磁道的扇区数的参数,它通常用一个范围标识,例如373~746,这表示,最外圈的磁道有746个扇区,而最里面的磁道有373个扇区。
早期的磁盘规范将扇区大小定义为512字节。然而随着硬盘容量的不断扩展,这一大小已不再能满足硬盘管理和性能提升的需要。为了提高容错能力和硬盘的使用及管理效率,IDEMA(International Disk Drive Equipment and Materials Association)将原来的每个扇区512字节改为每个扇区4096个字节,也就是现在常说的“4K扇区”。支持这一标准的硬盘称为高级格式化(Advanced Format)硬盘。
4K扇区格式继承了传统512字节扇区格式的关键设计要点,比如扇区起始区域的同步(synchronization)和地址(address)标志以及扇区结尾的纠错编码ECC(error correction coding)。4K扇区通过将中间的八个数据区域结合到一个扇区,减少了扇区头尾及间隙的个数,从而磁盘利用效率更高,同时也让ECC有足够的空间可以从50字节扩展到100字节。延长后的ECC采用新的算法,使得数据错误的检测和更正都有所改善。
选择4K而不是其他长度作为AF标准主要是为了和其他计算机领域的其他标准保持一致,比如操作系统和处理器所支持的内存管理单元-页(page)的大小,关系型数据库标准交易的大小等。
由于4K扇区标准在2010年才完成制定,所以目前大量的硬件及软件系统仍然是以512字节扇区标准来设计的,其中包括了很多芯片集,操作系统,数据库引擎,硬盘分区和镜像工具,文件备份设备等。为了向下兼容这些系统及程序, 很多硬盘制造商都在AF格式的硬盘上集成了512字节转换固件。集成了这种固件的硬盘被称为Advanced Format 512e硬盘,其中512e代表512仿真(512 emulation)。
将4K物理扇区转换成512字节虚拟扇区这一过程对系统和硬盘来说都是透明的,系统对AF格式的硬盘所以发出的读写请求跟对传统格式的硬盘发出的请求一样。
在处理读请求的过程中,AF格式硬盘会将包含了所需要的512字节数据的整个4K扇区加载到内存中,转换固件会将所需要的512字节数据提取出来然后转化成512字节格式,再将其发送到主机。这一过程通常对性能都不会有影响,或者只有很小的影响。
处理写请求的过程比读请求要复杂一些,硬盘需要将包含目标数据的整个4K扇区读到内存中,再将改写后的数据和原有数据整合到一起,最后将这4K扇区一起写回到磁盘当中。这一读-改-写的操作在4K不对齐的情况下会给系统带来明显的性能影响。
以常见的NTFS文件系统为例,在版本6以前的规范中,其引导区占用63个扇区,真正的文件分区从第63个扇区之后开始存储。依照计算,63个扇区的大小为 63×512字节=31.5K,无法被4K整除,也可以说是4K没有对齐。扇区是磁盘的硬件物理参数,是对磁盘进行读写操作的最小单元。而磁盘与主存之间进行数据传输时的逻辑单元则为簇(cluster)或者块(block),其由一个或多个扇区所组成。一个簇只存放一个文件。NTFS数据传输单元-簇的默认大小为4K,如果从31.5K开始进行数据存储,那么每个簇都会跨越两个物理扇区,占据第一个扇区的后512字节和第二个扇区的前3584字节。这样文件系统在读写某个簇的时候,硬盘都需要对两个扇区进行读-改-写操作,而在4K对齐的系统里,只要一次操作就可以了。
根据我们对SSD 0.5T云盘的测试,发现不对齐在写性能损耗方面的影响还是比较大的:
非4k对齐 | 随机读 | 块大小4k | 读带宽:61002 KB/s | IOPS:15200 |
---|---|---|---|---|
块大小64k | 读带宽:260110 KB/s | IOPS:4100 | ||
4k对齐 | 随机读 | 块大小4k | 读带宽:62517 KB/s | IOPS:15479 |
块大小64k | 读带宽:263080 KB/s | IOPS:4379 |
非4k对齐 | 随机写 | 块大小4k | 写带宽:25788 KB/s | IOPS:6471 |
---|---|---|---|---|
块大小64k | 写带宽: 227951 KB/s | IOPS:3501 | ||
4k对齐 | 随机写 | 块大小4k | 写带宽: 48458 KB/s | IOPS:12221 |
块大小64k | 写带宽: 261159 KB/s | IOPS:4281 |
注:上面这组数据是用fio压测出来的结果,仅供参考。
因此只要你的硬盘是Advanced Format的,都建议进行4K对齐。否则无论是对硬盘的读写速度,还是使用寿命,都将有不利的影响。
Linux系统的磁盘4k对齐
- 查看系统中磁盘物理大小扇区和逻辑大小扇区
[root@demo vdg]# cat /sys/block/vdg/queue/physical_block_size
512
[root@demo vdg]# cat /sys/block/vdg/queue/logical_block_size
512
可以看到我的这块测试磁盘的物理扇区大小是512字节,逻辑扇区大小也是512字节,这样我们物理块到逻辑块的映射都是512字节的。
- 对齐分区
查看现有磁盘是否是4k对齐,可以用fdisk -l -u:
- 如何用fdisk 对齐分区:
fdisk /dev/vdb
WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u').
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-208050, default 1):
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-208050, default 208050):
Using default value 208050
Command (m for help): x
Expert command (m for help): b
Partition number (1-4): 1
New beginning of data (1-209714399, default 63): 128
Expert command (m for help): p
Disk /dev/vdb: 16 heads, 63 sectors, 208050 cylinders
Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID
1 00 1 1 0 15 63 1023 128 209714272 83
2 00 0 0 0 0 0 0 0 0 00
3 00 0 0 0 0 0 0 0 0 00
4 00 0 0 0 0 0 0 0 0 00
Expert command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.
这样分区之后再用fdisk -l -u查看,已经是分区对齐了。
Disk /dev/vdb: 107.4 GB, 107374182400 bytes
16 heads, 63 sectors/track, 208050 cylinders, total 209715200 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
Disk identifier: 0x00055dd3
Device Boot Start End Blocks Id System
/dev/vdb1 128 209714399 104857136 83 Linux
用parted也可以做到分区对齐,parted和fdisk相比,支持更多的类型(支持GPT)和更大的分区尺寸:
parted /dev/vdb
GNU Parted 2.1
使用 /dev/vdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit s
(parted) p
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 209715200s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number Start End Size Type File system 标志
1 128s 209714399s 209714272s primary
(parted) rm 1
(parted) mkpart primary 128 100%
(parted) p
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 209715200s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number Start End Size Type File system 标志
1 128s 209715199s 209715072s primary
Window系统磁盘分区对齐
针对widnows 分区4k对齐方法
C:\Users\Administrator>diskpart
DISKPART> list disk
磁盘 ### 状态 大小 可用 Dyn Gpt
-------- ------------- ------- ------- --- ---
磁盘 0 联机 40 GB 39 GB(需要做4k对齐的盘)
磁盘 1 联机 40 GB 0 B(可以运行系统的磁盘)
DISKPART> select disk 0
磁盘 0 现在是所选磁盘。
DISKPART> list partition
这个磁盘上没有显示的分区。
DISKPART> clean
DiskPart 成功地清除了磁盘。
DISKPART> create partition primary align=1024 (做了4k分区对齐)
DiskPart 成功地创建了指定分区。
DISKPART> list partition
分区 ### 类型 大小 偏移量
------------- ---------------- ------- -------
* 分区 1 主要 39 GB 1024 KB
DISKPART> select partition 1
分区 1 现在是所选分区。
DISKPART> active
DiskPart 将当前分区标为活动。
DISKPART> format fs=ntfs unit=4096 quick (在系统安装时,保持现在的分区不变)
100 百分比已完成
DiskPart 成功格式化该卷。
曾经遇到过两起案例,都是由于在使用SSD云盘的时候没有做到对齐分区,而造成磁盘性能不佳,所以当遇到磁盘IO性能不佳的问题的时候,除了观察后台IO负载是否很高,不妨也先来看一下你的磁盘分区是否做到了4k对齐?
参考文献:
https://www.ibm.com/developerworks/cn/linux/l-4kb-sector-disks/index
https://www.lvtao.net/server/298.html