Disk

lsblk命令

MAJ:MIN 主:次 设备号

TYPE:块设备类型,比如disk磁盘,part分区,lvm逻辑卷,rom只读存储

1
2
3
4
5
6
$ lsblk -f # 查看磁盘分区格式,有格式才能挂载成功。
NAME FSTYPE LABEL UUID FSAVAIL FSUSE% MOUNTPOINT
sda
├─sda1
└─sda2 ext4 9449ee1e-7cdb-4852-9c60-73959ce812c0 18.1G 93% /
sdb

lsblk显示 nvme2n1 什么意思

In the output of the lsblk command, nvme2n1 refers to a Non-Volatile Memory Express (NVMe) device. Here’s a breakdown of the naming convention:

nvme: This prefix indicates that the device is an NVMe storage device, which is a type of high-performance, solid-state drive (SSD) that connects directly to the motherboard via the PCIe bus.

fdisk命令

blkid命令

使用blkid命令对查询设备上所采用文件系统类型进行查询。blkid主要用来对系统的块设备(包括交换分区)所使用的文件系统类型、LABEL、UUID等信息进行查询。要使用这个命令必须安装e2fsprogs软件包。

分区已有文件系统

直接使用blkid可列出当前系统中所以已挂载文件系统的类型。(或者 check /etc/fstab)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> blkid
/dev/sdb: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="dc35a623-6a3e-f4fe-f9f7-05e102a9c7ec" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdc: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="7772d530-24d2-2064-29a3-9d61c0b6289e" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sda: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="683c1101-69b1-f2c6-586b-155fbda91846" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdd1: UUID="F51A-FBBA" TYPE="vfat" PARTUUID="f377e755-9c1e-41dd-b50b-cb50a095be4c"
/dev/sdd2: UUID="3df43f90-d64c-4061-bbca-2614ecc57f34" TYPE="ext4" PARTUUID="c599a2f0-9888-4f86-88fb-a49b9cde4666"
/dev/sdd3: UUID="f12ca879-4545-46b7-bb2e-bdcdf771cb96" TYPE="swap" PARTUUID="bb5ab1b6-f67b-46fc-aead-14b8b86972ad"
/dev/sdd4: UUID="07fbfa2a-6b48-4423-9260-dc36080b42c4" TYPE="ext4" PARTUUID="6b4f7a39-1c0f-4fcf-a407-b31e469a3cdc"
/dev/sdf: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="86ffe123-2c7f-f7f1-40a0-57a12982fe17" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdg: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="36a06a4f-c84e-0684-8997-2997a68de012" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdh: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="369a926d-1f63-f397-ba4e-3118ef2ecf1d" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sde: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="4dd3f6ca-1e73-2606-ec65-c98badcd77ad" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/md0p1: UUID="c960e42b-f321-482d-aed4-c90f29e77291" TYPE="ext4" PARTUUID="d0949a94-c6e4-4621-890b-8d3f2d70fe57"
/dev/md0p2: UUID="addb8c13-8e34-4d8a-995b-101638f2dcbb" TYPE="ext4" PARTUUID="c6594348-58c5-49c2-9f40-82ce49653b7c"
/dev/md0p3: UUID="3354846e-7bec-45fb-8b59-4c6d60340d0d" TYPE="ext4" PARTUUID="8012f7e0-7dfa-46c5-b748-ef04d68a31ed"
/dev/md0p4: UUID="def8fb56-701e-4d6c-81d9-ecb765cc4d06" TYPE="ext4" PARTUUID="f6bb7944-fb1c-42de-af77-545c26303ad2"
/dev/md0p5: UUID="2f0590a9-6490-4758-999f-bdb5ef5954db" TYPE="ext4" PARTUUID="bbfe02f4-6b6a-4eeb-bb58-92b8b14b0997"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> blkid -o list
device fs_type label mount point UUID
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/dev/sdb linux_raid_member ubuntu-server:0 (not mounted) 2d900913-d0a4-4a15-7bd8-46dda015c95e
/dev/sdc linux_raid_member ubuntu-server:0 (not mounted) 2d900913-d0a4-4a15-7bd8-46dda015c95e
/dev/sda linux_raid_member ubuntu-server:0 (not mounted) 2d900913-d0a4-4a15-7bd8-46dda015c95e
/dev/sdd1 vfat /boot/efi F51A-FBBA
/dev/sdd2 ext4 / 3df43f90-d64c-4061-bbca-2614ecc57f34
/dev/sdd3 swap [SWAP] f12ca879-4545-46b7-bb2e-bdcdf771cb96
/dev/sdd4 ext4 /tmp 07fbfa2a-6b48-4423-9260-dc36080b42c4
/dev/sdf linux_raid_member ubuntu-server:0 (not mounted) 2d900913-d0a4-4a15-7bd8-46dda015c95e
/dev/sdg linux_raid_member ubuntu-server:0 (not mounted) 2d900913-d0a4-4a15-7bd8-46dda015c95e
/dev/sdh linux_raid_member ubuntu-server:0 (not mounted) 2d900913-d0a4-4a15-7bd8-46dda015c95e
/dev/sde linux_raid_member ubuntu-server:0 (not mounted) 2d900913-d0a4-4a15-7bd8-46dda015c95e
/dev/md0p1 ext4 /home c960e42b-f321-482d-aed4-c90f29e77291
/dev/md0p2 ext4 /usr addb8c13-8e34-4d8a-995b-101638f2dcbb
/dev/md0p3 ext4 /boot 3354846e-7bec-45fb-8b59-4c6d60340d0d
/dev/md0p4 ext4 /var def8fb56-701e-4d6c-81d9-ecb765cc4d06
/dev/md0p5 ext4 /srv 2f0590a9-6490-4758-999f-bdb5ef5954db

UUID

帮助使用者唯一的确定系统中的所有存储设备,不管它们是什么类型的。它可以标识DVD驱动器,USB存储设备以及你系统中的硬盘设备等。

使用原因包括:设备名并非总是不变的

df 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
shaojiemike@brainiac1 ~/blockFrequency  [08:02:54]
> df -lh
文件系统 容量 已用 可用 已用% 挂载点
udev 94G 0 94G 0% /dev
tmpfs 19G 4.3M 19G 1% /run
/dev/sdd2 984G 12G 923G 2% /
tmpfs 95G 88K 95G 1% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 95G 0 95G 0% /sys/fs/cgroup
/dev/md0p3 20G 347M 19G 2% /boot
/dev/sdd4 53G 319M 50G 1% /tmp
/dev/md0p5 47G 53M 45G 1% /srv
/dev/sdd1 511M 3.6M 508M 1% /boot/efi
/dev/md0p4 590G 5.7G 554G 2% /var
/dev/md0p1 6.5T 5.1T 1.2T 82% /home
/dev/loop0 49M 49M 0 100% /snap/core18/2289
/dev/loop1 58M 58M 0 100% /snap/core20/1360
/dev/loop3 38M 38M 0 100% /snap/snapd/14982
/dev/loop4 38M 38M 0 100% /snap/snapd/15183
/dev/loop2 58M 58M 0 100% /snap/core20/1380
/dev/loop5 61M 61M 0 100% /snap/lxd/21843
/dev/loop7 49M 49M 0 100% /snap/core18/2349
/dev/loop6 62M 62M 0 100% /snap/lxd/22530
tmpfs 19G 0 19G 0% /run/user/1006
tmpfs 19G 0 19G 0% /run/user/1008
tmpfs 19G 0 19G 0% /run/user/1005

snap的机制

一种新的安装包管理方式。使用snapcraft将软件打包成snap格式的打包工具集。

1
2
3
4
5
6
7
8
9
10
11
12
13
+-----------+       +------------+      +------------+
| Developer +------>| Snapcraft +----->| Snap Store |
+-----------+ +------------+ +-----+------+
| update
v
+-----------+ +------------+ +------------+
| End User +------>| Snap +----->| Snapd |
+-----------+ +-----+------+ +-----+------+
| containerize |
v |
+------------+ |
| Snaps |<-----------+ manage
+------------+

core

snap的每个版本软件会,占用一个/dev/loop

1
2
/snap/core18 代表ubuntu 18版本的软件所运行的环境
/snap/core20 代表ubuntu 20版本的软件所运行的环境

Snap应用运行在以Ubuntu
为核心的容器里,与各个发行版做到了解耦。因此Snap应用的开发者很开心了,
只需保证自己应用在[Ubuntu Core]欢快运行即可,不需要考虑其他发行版的适配。

snapd

Snap应用由snapd守护进程管理。snapd每天会去Snap Store查本地Snap应
用有没有可用更新,如果有,就把更新拿下来,应用到当前Snap应用上。自动更新不可关闭,但是可以设置延迟60天。

lxc/lxd

lxc是Linux Container的简写,它是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源;它不需要提供指令解释机制,没有全虚拟化的复杂性,相当于C++中的NameSpace。
lxc容器能有效地把操作系统管理的资源划分到不同的组中,并能在不同的组之间平衡有冲突的资源使用需求,因此它可以在单一的主机节点上同时执行多个相互隔离的容器。

lxd是基于lxc构筑的容器管理进程,提供镜像、网络、存储、以及容器等能力。
  
大家可能有个疑问,为什么不用docker容器呢?docker容器原先也是我的首选,但实际操作过程中发现snap包安装所需要的squashfs文件系统在docker中无法mount,会出现如下错误:

1
system does not fully support snapd: cannot mount squashfs imag  

tmpfs

/dev/shm下的tmpfs是内存的一半,是一个临时文件系统,驻留在内存中,所以/dev/shm/这个目录不在硬盘上,而是在内存里。因为是在内存里,所以读写非常快,可以提供较高的访问速度。

/sys/fs/cgroup是systemd在代码里自动挂载的。cgroups(Control Groups) 是 linux 内核提供的一种机制,这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。简单说,cgroups 可以限制、记录任务组所使用的物理资源。

/run/user是每个login的用户所需的一些数据

1
2
3
4
5
6
> ls /run/user -l
总用量 0
drwx------ 7 qcjiang qcjiang 360 Jul 11 14:54 1005
drwx------ 7 shaojiemike shaojiemike 780 Jul 11 01:10 1006
drwx------ 7 zwcao zwcao 360 Jul 9 15:48 1008
drwx------ 7 udfrt udfrt 200 Jul 11 16:03 1010

利用tmpfs这个特性可以用来提高服务器性能,把一些对读写性能要求较高,但是数据又可以丢失的这样的数据保存在/dev/shm中,来提高访问速度。

tmpfs用途还是较广的,Linux中可以把一些程序的临时文件放置在tmpfs中,利用tmpfs比硬盘速度快的特点来提升系统性能。比如可以用来放squid程序的缓存文件。

1
2
3
4
5
6
# 临时调整大小,重启后会恢复正常,恢复为内存一半大小。
mount -o remount,size=777M tmpfs /dev/shm
# 永久修改
vim /etc/fstab
# 把tmpfs这一行改为:
tmpfs /dev/shm tmpfs defaults,size=777M 0 0

/etc/fstab 解析

/etc/fstab 是专门用配置挂载硬盘的文件

语法为:

1
2
3
4
5
6
7
8
[Device] [Mount Point] [File System Type] [Options] [Dump] [Pass]

[Device] 包含文件系统的device或者partition
[Mount Point] 挂载的目录,从该目录可以访问设备/分区的内容(注意:swap没有装入点)
[File System Type] 文件系统类型
[Options] mount的选项,默认的defaults
[Dump] 是否开启备份,0 来表示不备份这个区
[Pass] fsck是否会check该区域,0表示不检查。fsck (文件系统检查)是一种命令行程序,可让您在一个或多个Linux文件系统上执行一致性检查和交互式修复。 它用于检查指定类型文件系统。 在系统无法启动或无法安装分区的情况下,可以使用 fsck 命令修复损坏的文件系统。

Device

device 有两种表示方式,可以用/dev/xdx 之类的location 或者 硬件的UUID 来表示,硬件的UUID 可以用blkid 来查询

对于uuid

1
2
3
4
5
# / was on /dev/sdd2 during curtin installation  
/dev/disk/by-uuid/3df43f90-d64c-4061-bbca-2614ecc57f34 / ext4 defaults 0 0

> blkid |grep 3df
/dev/sdd2: UUID="3df43f90-d64c-4061-bbca-2614ecc57f34" TYPE="ext4" PARTUUID="c599a2f0-9888-4f86-88fb-a49b9cde4666"

对于id

1
2
3
4
5
6
7
8
9
10
# /home was on /dev/md0p1 during curtin installation                                            
/dev/disk/by-id/md-uuid-2d900913:d0a44a15:7bd846dd:a015c95e-part1 /home ext4 defaults 0 0
# /usr was on /dev/md0p2 during curtin installation
/dev/disk/by-id/md-uuid-2d900913:d0a44a15:7bd846dd:a015c95e-part2 /usr ext4 defaults 0 0
# /boot was on /dev/md0p3 during curtin installation
/dev/disk/by-id/md-uuid-2d900913:d0a44a15:7bd846dd:a015c95e-part3 /boot ext4 defaults 0 0
# /var was on /dev/md0p4 during curtin installation
/dev/disk/by-id/md-uuid-2d900913:d0a44a15:7bd846dd:a015c95e-part4 /var ext4 defaults 0 0
# /srv was on /dev/md0p5 during curtin installation
/dev/disk/by-id/md-uuid-2d900913:d0a44a15:7bd846dd:a015c95e-part5 /srv ext4 defaults 0 0
1
2
3
4
5
6
7
8
> blkid |grep a015c95e
/dev/sdb: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="dc35a623-6a3e-f4fe-f9f7-05e102a9c7ec" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdc: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="7772d530-24d2-2064-29a3-9d61c0b6289e" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sda: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="683c1101-69b1-f2c6-586b-155fbda91846" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdf: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="86ffe123-2c7f-f7f1-40a0-57a12982fe17" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdg: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="36a06a4f-c84e-0684-8997-2997a68de012" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sdh: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="369a926d-1f63-f397-ba4e-3118ef2ecf1d" LABEL="ubuntu-server:0" TYPE="linux_raid_member"
/dev/sde: UUID="2d900913-d0a4-4a15-7bd8-46dda015c95e" UUID_SUB="4dd3f6ca-1e73-2606-ec65-c98badcd77ad" LABEL="ubuntu-server:0" TYPE="linux_raid_member"

这里可以看到这7个硬盘的UUID是一样的,说明属于同一个RAID文件系统卷,但是子卷UUID_SUB是不一样的

问题:

  1. 为什么8块盘里/dev/sdd1第四块被拆成了4份
  2. blkid里的
    1. UUID_SUB 什么意思
    2. /dev/md0p1
      1. 好像和GPT分区有关
    3. 为什么device里 /dev/md0p1 没和blkid的对应上

File System Type

auto, vfat( for FAT partition), ntfs or ntfs-3g( for NTFS partition), ext4 or ext3 or ext2 or jfs, udf or iso9660 ( for CD/DVD), swap

磁盘分区 MBR vs GPT

当服务器插入一块硬盘,如果我们想要使用该硬盘,需要先使用磁盘分区管理工具进行磁盘分区,然后格式化分区,把分区挂载到目录

上,才可以正式使用该硬盘存储文件。磁盘分区管理工具有很多,本文主要介绍fdisk,gdisk,parted,并进行比较。

判断分区是GPT还是MBR

fdisk -lgdisk -l /dev/sda都可以,下面介绍另一种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sudo parted -l
型号:TOSHIBA AL15SEB120N (scsi) 磁盘 /dev/sdd: 1200GB
扇区大小 (逻辑/物理):512B/512B
分区表:gpt
磁盘标志:

编号 起始点 结束点 大小 文件系统 名称 标志
1 1049kB 538MB 537MB fat32 启动, EFI 启动
2 538MB 1074GB 1074GB ext4
3 1074GB 1143GB 68.7GB linux-swap(v1) 交换
4 1143GB 1200GB 57.2GB ext4

型号:Linux 软件 RAID 数组 (md)
磁盘 /dev/md0: 8401GB
扇区大小 (逻辑/物理):512B/512B
分区表:gpt
磁盘标志:

编号 起始点 结束点 大小 文件系统 名称 标志
1 1049kB 7147GB 7147GB ext4
2 7147GB 7684GB 537GB ext4
3 7684GB 7705GB 21.5GB ext4
4 7705GB 8349GB 644GB ext4
5 8349GB 8401GB 51.3GB ext4

可以看出上面的普通硬盘和RAID0都是GPT。#显示Partition Table: msdos,则是MBR分区

MBR(Master Boot Record)

是传统的分区机制,应用于绝大多数使用BIOS引导的PC设备(苹果使用EFI的方式),很多Server服务器即支持BIOS也支持EFI的引导方式。MBR只支持不超过2TB的硬盘。

MBR分区分为:

  1. 主分区(一块硬盘最多只能创建4个主分区)、
  2. 扩展分区(一个扩展分区会占用一个主分区的位置)、
  3. 逻辑分区(逻辑分区是基于扩展分区创建出来的,
    1. 先有扩展分区,然后在扩展分区的基础上再创建逻辑分区;
    2. 也就是说我们要使用逻辑分区,必须先要创建扩展分区,扩展分区的空间是不能被直接使用的,
    3. 我们必须在扩展分区的基础上去建立逻辑分区,才能够被使用)。
  4. 在Linux上使用扩展分区和逻辑分区最多可以创建15个分区;

GPT(GUID Partition Table)分区

解决了MBR的很多缺点;
​1. 支持超过2TB的磁盘;
​2. 向后兼容MBR;
3. GPT分区只支持64位操作系统;

fdisk对/dev/sdb硬盘进行分区

必须先取消挂载,取消挂载后分区。不然分区结果重启后会消失,文件全没了。

1
sudo umount /mnt/ #挂载目录

创建一个主分区,一个扩展分区,其中扩展分区包含两个逻辑分区。

1
2
3
lsblk
sdb 8:16 0 1G 0 disk
└─sdb1 8:17 0 200M 0 part

sdb这块磁盘大小为1G。而且已有分区sdb1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# fdisk /dev/sdb
p #打印分区表
d #因为此磁盘只有一个分区sdb1,所以按d删除时候默认不会让选择要删除的分区,如果有多个分区会提示要删除的分区。
p #打印分区表,再次查看分区表,发现/dev/sdb1已经被删除
Command (m for help): n #新建分区
Partition type:
p primary (0 primary, 0 extended, 4 free) #主分区
e extended #扩展分区
Select (default p): p #选择新建主分区
Partition number (1-4, default 1): #主分区号,会生成/dev/sdb1
First sector (2048-2097151, default 2048): #开始扇区,回车默认从2048开始
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-2097151, default 2097151): +50M #分配主分区大小,在此为50M
Partition 1 of type Linux and of size 50 MiB is set

Command (m for help): n #新建分区
Partition type:
p primary (1 primary, 0 extended, 3 free)
e extended
Select (default p): e #选择创建扩展分区
Partition number (2-4, default 2): #扩展分区编号,在此我们直接回车,默认为/dev/sdb2
First sector (104448-2097151, default 104448): #默认回车,从当前扇区开始
Using default value 104448
Last sector, +sectors or +size{K,M,G} (104448-2097151, default 2097151): +500M #分配扩展分区大小,在此为500M
Partition 2 of type Extended and of size 500 MiB is set

Command (m for help): n
Partition type:
p primary (1 primary, 1 extended, 2 free)
l logical (numbered from 5)
Select (default p): l #新建逻辑分区
Adding logical partition 5 #默认逻辑分区编号为5
First sector (106496-1128447, default 106496): #逻辑分区起始位置
Using default value 106496
Last sector, +sectors or +size{K,M,G} (106496-1128447, default 1128447): +200M #分配逻辑分区大小,在此为200M
Partition 5 of type Linux and of size 200 MiB is set

Command (m for help): n
Partition type:
p primary (1 primary, 1 extended, 2 free)
l logical (numbered from 5)
Select (default p): l #新建第二个逻辑分区
Adding logical partition 6
First sector (518144-1128447, default 518144):
Using default value 518144
Last sector, +sectors or +size{K,M,G} (518144-1128447, default 1128447): #直接回车,默认分配剩余空间
Using default value 1128447
Partition 6 of type Linux and of size 298 MiB is set

Command (m for help): p
...
Disk label type: dos

Device Boot Start End Blocks Id System
/dev/sdb1 2048 104447 51200 83 Linux
/dev/sdb2 104448 1128447 512000 5 Extended
/dev/sdb5 106496 516095 204800 83 Linux
/dev/sdb6 518144 1128447 305152 83 Linux

#通过如上输出可知,/dev/sdb1为主分区,/dev/sdb2为扩展分区,扩展分区又包含两个逻辑分区/dev/sdb5和/dev/sdb6

Command (m for help): w #保存分区信息并退出
1
2
3
4
5
6
7
[root@node5 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdb 8:16 0 1G 0 disk
├─sdb1 8:17 0 50M 0 part
├─sdb2 8:18 0 1K 0 part
├─sdb5 8:21 0 200M 0 part
└─sdb6 8:22 0 298M 0 part

格式化分区

把/dev/sdb5格式化成ext4文件系统
[root@node5 ~]# mkfs.ext4 /dev/sdb5

挂载分区

1
2
mkdir /sdb5
mount /dev/sdb5 /sdb5

设置开机自动挂载分区

磁盘分区使用mount手动挂载之后,还需要把挂载信息写入/etc/fstab文件中,不然重启之后,需要重新挂载。

1
mount -a #重新加载内核

RAID - mdadm

mdadm是一个用于创建、管理、监控RAID设备的工具,它使用linux中的md驱动。mdadm程序是一个独立的程序,能完成所有软件RAID的管理功能。常见功能如下:

  1. mdadm –create device options…
    1. Create a new array from unused devices.
  2. mdadm –manage device options…
    1. make changes to an existing array.
  3. mdadm –misc options… devices
    1. report on or modify various md related devices.

配置文件

配置文件,默认是”/etc/mdadm.conf”或者是”/etc/mdadm/mdadm.conf”

1
2
3
> cat /etc/mdadm/mdadm.conf
ARRAY /dev/md0 metadata=1.2 name=ubuntu-server:0 UUID=2d900913:d0a44a15:7bd846dd:a015c95e
MAILADDR root

–metadata=定义组件设备上超级块的类型。对于–create,默认是0.90。

0,0.90 : 限制一个RAID中的设备数为28个,限制组件设备大小为2TB

1,1.0,1.1,1.2 :不同的子版本号标识在不同的地方存储超级块。1.0在设备的结尾,1.1在设备的开头,1.2在设备的4K处。

MAILADDR 使用monitor模式(同时也使–scan选项)时,警报事件发送到的Email地址。

sudo mdadm -Ds > /etc/mdadm/mdadm.conf

把查询出来的 RAID 信息写到 mdadm.conf 中

-s 或 –scan 扫描 RAID 设备;-D 或 –detail 查看 RAID 的详细信息

查看当前RAID

1
2
3
4
5
6
> cat /proc/mdstat
Personalities : [raid0] [linear] [multipath] [raid1] [raid6] [raid5] [raid4] [raid10]
md0 : active raid0 sdf[4] sde[3] sdh[6] sdg[5] sda[0] sdc[2] sdb[1]
8203865600 blocks super 1.2 512k chunks

unused devices: <none>

RAID0的搭建

猜测命令

1
mdadm –create /dev/md0 –chunk=512 –metadata=1.2 –level=0 –raid-devices=7 /dev/sda /dev/sdb /dev/sdc /dev/sde /dev/sdf /dev/sdg /dev/sdh

说明:使用7块创建RAID0,条带大小是512KB。

创建完之后

1
2
3
> lsblk -l
md0 9:0 0 7.7T 0 raid0
md0p1 259:0 0 7.7T 0 md
1
2
3
4
5
fdisk /dev/md0 #分区
mount /dev/md0p1 /home/ #挂载
mount /dev/md0p2 /usr/ #挂载
mount /dev/md0p3 /boot/ #挂载
...
1
2
3
4
5
6
7
> lsblk -l
md0 9:0 0 7.7T 0 raid0
md0p1 259:0 0 6.5T 0 part /home
md0p2 259:1 0 500G 0 part /usr
md0p3 259:2 0 20G 0 part /boot
md0p4 259:3 0 600G 0 part /var
md0p5 259:4 0 47.8G 0 part /srv

vi /etc/fstab #设置开机自动挂载

扩容,添加硬盘

增大RAID 的大小涉及按给定顺序执行下列任务:

  1. 增加所有组成 RAID 的所有分区的大小,
  2. 增加 RAID 本身的大小,
  3. 最后增加文件系统的大小。

第一步:

1
mdadm /dev/md0 --add /dev/sdc1

说明:给md0增加热备盘sdc1。运行cat /proc/mdstat等到 RAID 同步并一致,然后再继续下一个分区。

第二步:
RAID 阵列配置将继续使用原始阵列大小,直到您强制其了解新的可用空间。您可以为 RAID 指定大小或使用最大可用空间。

查看大小

1
sudo mdadm -D /dev/md0 | grep -e "Array Size" -e "Dev Size"

将RAID大小增加到最大可用大小

1
sudo mdadm --grow /dev/md0 -z max

第三步: 不确定

更改 Ext2、Ext3 或 Ext4 文件系统的大小(先查看md0分区大小)

先fdisk删除part1分区,新建同名(同分区标号)的分区,First cylinder起始点相同,通过改变终点为最大值来扩容。

将文件系统大小扩展为名为 /dev/md0 的设备的最大可用大小,请输入

1
2
3
> sudo resize2fs /dev/md0p1
resize2fs 1.45.5 (07-Jan-2020)
文件系统已经为 1744830464 个块(每块 4k)。无需进一步处理!

如果未指定大小参数,大小将默认为该分区的大小。

loop机制

Loop设备是一种块设备,但是它并不指向硬盘或者光驱,而是指向一个文件块或者另一种块设备。

回环设备( ‘loopback device’)允许用户以一个普通磁盘文件虚拟一个块设备。设想一个磁盘设备,对它的所有读写操作都将被重定向到读写一个名为 disk-image 的普通文件而非操作实际磁盘或分区的轨道和扇区。(当然,disk-image 必须存在于一个实际的磁盘上,而这个磁盘必须比虚拟的磁盘容量更大。)回环设备允许你这样使用一个普通文件。

应用

将一个Loop设备指向一个文件系统文件,比如iso文件,紧接着就可以通过mount挂载该loop设备到主文件系统的一个目录下了,我们就可以正常访问该镜像中的内容,就像访问一个文件系统一样。

简单使用

losetup -a列出已使用的。

loop设备映射或者指向一个文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建一个文件
dd if=/dev/zeroof=/var/loop.img bs=1M count=10240
# 使用losetup将文件转化为块设备,获得了一个磁盘
losetup /dev/loop0 /var/loop.img
# 在磁盘上构建文件系统
# 挂载
mkdir /myloopdev
mount /dev/loop0 /myloopdev
# 正常使用
# 卸载该磁盘
umount /myloopdev
# 接着删除该loop设备,
losetup –d /dev/loop0

mount 硬盘

实际操作

物理挂盘

注意,推进插入的时候把卡扣打开

命令行处理

1
2
3
fdisk -l # 看不见新盘
lsblk # 也看不见
sudo reboot # 重启

还是找不到? 还是8块。

猜测:盘坏了吗?

额外找了其他类型的盘,还有160GB的固态插上。确实是四块坏盘。换了借口也无法识别。

1
sudo shutdown -h now # 热拔插还是有风险

总算整了5块

1
2
3
4
5
6
7
8
9
10
11
sdi         8:128  0 931.5G  0 disk  
└─sdi1 8:129 0 931.5G 0 part
sdj 8:144 0 149.1G 0 disk
├─sdj1 8:145 0 512M 0 part
└─sdj2 8:146 0 148.6G 0 part
sdk 8:160 0 1.8T 0 disk
└─sdk1 8:161 0 1.8T 0 part
sdl 8:176 0 1.8T 0 disk
└─sdl1 8:177 0 1.8T 0 part
sdm 8:192 0 1.8T 0 disk
└─sdm1 8:193 0 1.8T 0 part

尝试一: RAID0扩容

那sdk为例。

1
2
3
4
> sudo fdisk /dev/sdk #d 删除分区
> sudo mdadm /dev/md0 --add /dev/sdk
mdadm: add new device failed for /dev/sdk as 7: Invalid argument
# 没分区的结构

尝试分区后add分区

1
2
> sudo mdadm /dev/md0 --add /dev/sdk1
mdadm: add new device failed for /dev/sdk1 as 7: Invalid argument

第二种

1
mdadm --grow /dev/md0 --level=0 --raid-devices=8 --add /dev/sdk

理论上这样的,但是要reshape,而且和dev.raid.speed_limit_max速度有关。我不确定会不会丢失资料,所以没尝试。

所以没有扩容

尝试二: 普通挂载

先格式化各个分区

1
2
3
4
5
> blkid -o list                                                            
/dev/sdi1 ext4 (not mounted)
/dev/sdl1 LVM2_member (not mounted)
/dev/sdm1 LVM2_member (not mounted)
/dev/sdk1 LVM2_member (not mounted)

sdi/l/m/k 全部格式化为ext4。blkid -o list不是实时的。挂载后通过df -Th查看

1
2
sudo mkfs.ext4 /dev/sdk1     
sudo mount /dev/sdk1 /addDisk/DiskNo4

修改权限,大家都可以访问(直接777算了

1
sudo chmod -R ogu+r+w+X /addDisk

配置开机启动,blkid -o list 获得uuid

1
2
3
4
/dev/sdk1                                                                    ext4                                 (not mounted)                                                                    ac862e68-9c6f-424a-b4ec-e44e62f7a330
/dev/sdj1 ext4 (not mounted) 8258b393-2e8e-41d1-9b84-0a7f88986443
/dev/sdl1 ext4 (not mounted) 5c2e1324-ecc5-40dd-a668-4ec682065d9f
/dev/sdi1 ext4 (not mounted) 0ae289c5-51f7-4ef2-a07c-6ec8d123e065

修改/etc/fstab

1
2
3
4
5
6
7
8
# /addDisk/DiskNo1 was on /dev/sdi1 during curtin installation  
/dev/disk/by-uuid/0ae289c5-51f7-4ef2-a07c-6ec8d123e065 /addDisk/DiskNo1 ext4 defaults 0 0
# /addDisk/DiskNo2 was on /dev/sdl1 during curtin installation
/dev/disk/by-uuid/5c2e1324-ecc5-40dd-a668-4ec682065d9f /addDisk/DiskNo2 ext4 defaults 0 0
# /addDisk/DiskNo3 was on /dev/sdj1 during curtin installation
/dev/disk/by-uuid/8258b393-2e8e-41d1-9b84-0a7f88986443 /addDisk/DiskNo3 ext4 defaults 0 0
# /addDisk/DiskNo4 was on /dev/sdk1 during curtin installation
/dev/disk/by-uuid/ac862e68-9c6f-424a-b4ec-e44e62f7a330 /addDisk/DiskNo4 ext4 defaults 0 0

COW 文件系统

USB启动的系统,会挂载在COPY-ON-WRITE

1
2
3
4
5
6
7
ubuntu@ubuntu:/dev$ df -lh
Filesystem Size Used Avail Use% Mounted on
udev 126G 0 126G 0% /dev
tmpfs 26G 3.0M 26G 1% /run
/dev/sdc1 29G 2.1G 27G 8% /cdrom -- USB启动的设备
/dev/loop0 2.0G 2.0G 0 100% /rofs
/cow 126G 209M 126G 1% /

需要进一步的研究学习

  1. 查找未挂载的盘 lsblk
  2. 判断硬盘好坏,是否坏道
    1. 检测坏块sudo badblocks -v /dev/sda > badsectors.txt
    2. 综合评价sudo smartctl -H /dev/sda10
  3. 格式化硬盘
  4. 挂载新分区
    1. 查看已有盘挂载的分区
  5. 如何挂载已有分区

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://forum.ubuntu.org.cn/viewtopic.php?t=487421

https://bbs.huaweicloud.com/blogs/197847

https://blog.csdn.net/dangelzjj/article/details/104200396

https://www.cnblogs.com/renshengdezheli/p/13941563.html

https://linux.cn/article-7961-1.html

File System

文件系统简介

计算机文件系统是操作系统的一个重要组成部分,它管理计算机存储设备上的文件,负责文件存储、读取和组织等功能。文件系统的主要作用包括:

  • 文件存储与寻址:文件系统负责在存储设备上对文件进行存取,需要找到文件在存储设备上的位置。常见的寻址机制有:
    • FAT表:使用文件分配表记录每个文件所占用簇的位置。
    • inode:为每个文件分配一个inode,记录文件存储位置、大小、访问时间等元信息。
  • 文件组织与优化:文件系统负责组织硬盘空间,常见的组织结构包括:
    • 目录结构:将文件组织成目录/子目录的树形层次结构。
    • 碎片整理:通过碎片整理优化空间利用率。
    • 块大小:通过调整块大小来改善IO性能。
  • 访问控制:管理文件访问权限、用户组等信息,确保访问安全。
    • 高级功能:一些文件系统实现了高级功能,如快照、数据压缩、加密等。
    • 系统完整性:提供一致性检验、崩溃恢复机制来保证文件系统完整可靠。

常见的文件系统包括Windows上的FAT、NTFS,Unix/Linux上的ext、XFS、Btrfs等。

文件系统的设计对操作系统的性能、安全性有很大影响。一个优秀的文件系统应提供高效的IO访问、良好的安全控制和数据完整性保障。选择正确的文件系统对不同场景也很重要。

评估文件系统

  • 性能:读写速度、响应时间、并发支持如何,可以测试IO性能。
  • 可靠性:数据完整性保证、Crash可恢复性如何,测试崩溃恢复。
  • 安全性:访问控制、防篡改机制如何,测重写、破坏后的数据恢复。
  • 容量:最大文件大小、卷大小、目录容量如何,测试边界极限。
  • 扩展性:可线性扩展还是需要重构,测试大容量情况下的性能。
  • 元数据:元信息组织结构,是否支持快速查找、高级索引。
  • 分配机制:如何分配和回收空间,是否会产生碎片。
  • 一致性:是否保证读写顺序一致性,如何支持缓存与本地IO。
  • 插件机制:是否可以通过插件扩展功能,如压缩、加密等。
  • 兼容性:是否兼容主流平台和老系统,测试迁移和交互兼容性。

基本概念:数据分块存储

文件储存在硬盘上,硬盘的最小存储单位叫做”扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。

但是就像内存读取也不会只读一个字节, 硬盘的存储和读取都是按照Block进行的(比如,4KB即连续八个 sector组成一个 block。)

早期:FAT文件系统

早期文件分配表(File Allocate Table,FAT)

链表结构解决了文件和物理块映射的问题。

小结

  • 常见的FAT12、FAT16、FAT32格式,用于早期Windows系统。
  • 优点:简单易用,支持跨平台
  • 缺点:非常占用内存, 效率和安全性不高。
    • 比如 1T 的硬盘,如果块的大小是 1K,那么就需要 1G 个 FAT 条目。
    • 通常每个 FAT 条目还会存一些其他信息,需要 2~3 个字节, FAT条目总共占用 2-3G 的内存空间,才能用来管理 1T 的硬盘空间。

常见:基于inode的文件系统

基于 inode(index node的数据结构) 的传统文件系统。文件数据被存储不同块里面,文件的元数据信息就会被存储在inode里面。

特点

  • 在Unix/Linux中广泛使用的文件系统,如Ext、XFS等。
  • 每个文件都有一个对应的inode,记录文件元信息和数据块位置。
  • 操作系统通过inode找到文件内容,支持权限控制等高级功能。
  • 效率高,安全可靠,但inode会占用一定存储空间。

文件操作流程

由于inode号码与文件名分离

  • 删除流程
    • 删除一个文件名,就会使得inode节点中的”链接数”减1。当这个值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域。
    • 直接删除inode,能够起到删除(包含特殊字符)文件的作用find ./* -inum 节点号 -delete
  • 移动文件或重命名文件
    • 只是改变文件名,不影响inode号码;

inode存储Block信息

为了解决数据变化问题,它引入了3个存储指针设计

  • 直接指针可以直接指向数据块本身,数据块就是保存数据的块
  • 间接指针是在前面的指针指针不够的时候才会启用,间接指针可以看成链表那样,间接指针会指向一个个索引块,这块本身又是一个数据块的指针也是只是指向存储数据块。
  • 第3类指针,指向一个二级索引块,二级索引块的指针还可以指向新的索引块

大小占用

  • 每个inode节点的大小固定,一般是128字节或256字节。
  • inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode
  • 每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况。这时,就无法在硬盘上创建新文件。
  • 每个inode都有一个号码,操作系统用inode号码来识别不同的文件。
1
2
3
4
5
6
7
8
9
10
$ df -hi .
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda2 56M 5.1M 51M 10% /
或者
/dev/sda2 58605568 5321132 53284436 10% /

# 每个inode节点的大小,一般是128字节或256字节。
$ sudo dumpe2fs -h /dev/sda2 | grep "Inode size"
dumpe2fs 1.45.5 (07-Jan-2020)
Inode size: 256

58605568/256 = 222928 个 inode节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ fdisk -l
Disk /dev/sda: 894.26 GiB, 960197124096 bytes, 1875385008 sectors
Disk model: INTEL SSDSC2KB96
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 86F8050E-C9E7-4BDB-8B0C-89E20B013FF6

Device Start End Sectors Size Type
/dev/sda1 2048 4095 2048 1M BIOS boot
/dev/sda2 4096 1875382271 1875378176 894.3G Linux filesystem

$ sudo fdisk -l /dev/sda2
Disk /dev/sda2: 894.26 GiB, 960193626112 bytes, 1875378176 sectors (512 bytes per sector)
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes

1875378176/228928 = 8192(8K) 个 sector 对应一个inode节点

一个inode节点对应 4MB的空间?

目录、软链接、硬链接

  • 目录:目录是一种特殊的文件,它的inode节点中存储的是文件名和inode号码的对应关系。
  • 软链接:软链接拥有自己的inode,但是文件内容就是一个快捷方式。
    • 命令 ln -s /etc/nginx/config link_config
    • 文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的”软链接”(soft link)或者”符号链接(symbolic link)。
    • 文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode”链接数”不会因此发生变化。
  • 硬链接:多个文件名指向同一个inode号码。
    • 命令 ln main.c link_main.c

软链接、硬链接区别与使用场景

在大部分常见场景下,硬链接是更优的选择:

  1. 硬链接是一个真实文件,不会无效,更可靠。软链接指向的文件移动或删除后会失效。
  2. 硬链接与原文件性能一致,软链接需要在查询时重新解析路径。

硬链接也有一些限制:

  1. 不能跨文件系统,软链接可以实现跨文件系统的链接。
  2. 目录无法创建硬链接,只能软链接。

日志文件系统

  • NTFS 和 Ext3 是日志文件系统,它们和 FAT 最大的区别在于写入到磁盘中的是日志,而不是数据。
  • 日志文件系统会先把日志写入到内存中一个高速缓冲区,定期写入到磁盘。
  • 日志写入是追加式的,不用考虑数据的覆盖。
  • 一段时间内的日志内容,会形成还原点。这种设计大大提高了性能,当然也会有一定的数据冗余。

日志文件系统 与 inode 文件系统的关系

  1. 日志文件系统是一种技术,可以建立在多种文件系统之上,包括inode文件系统。
  2. inode文件系统是一种文件系统架构,每个文件都有一个inode保存元信息。ext、xfs等都是这种架构。
  3. 但两者不是必然关联的,日志文件系统技术也可以用在非inode型文件系统上。

常见名词及文件系统:MBR、GPT和FAT、EXT2

前两者是磁盘分区格式,后两者是文件系统格式。

MBR、GPT是两种比较常见的磁盘分区格式,而且对于磁盘分区而言,目前也主要是这两种格式。一个分区是一个存储设备上的一块独立区域,用户可以针对这块区域进行单独管理。

  • NFS:网络文件系统,允许通过网络访问文件,可应用在分布式系统。
  • ZFS:引入了pooled storage和checksum等特性的128位文件系统。
  • HFS:Mac OS使用的层次化文件系统,使用B*树对元数据进行组织。

实践:fdisk的结果

  • “Disk label type”表示当前磁盘的分区形式,
  • dos表示磁盘分区形式为MBR,
  • gpt表示磁盘分区形式为GPT

Windows NTFS文件系统

New Technology File System (NTFS):Windows NT引入的文件系统,使用主文件表(MFT)来管理文件,支持高级功能如权限控制等。

  • NTFS卷上的任何事物都是文件(为了与平时使用的文件相区别,以下用FILE特指),
  • FILE通过主文件表(master file table, MFT)来确定其在卷上的位置,
  • 每个FILE有固定大小,一般为1KB。
  • FILE记录了文件的所有数据,每个数据以一个属性来表示,如文件名、文件长度、文件的时间等都是属性,文件的内容也是一个属性,每个属性有一个特征码。
  • 属性数据较小时能够存放在FILE记录中,称为驻留的属性,反之为非驻留的属性,通过Data Runs来保存其存储索引表。
    • 这一点与FAT文件系统不同,FAT文件系统只在目录区保存了文件的首簇号,还要通过FAT表链接关系才能确定文件的全部存放位置。
    • Data Runs在一个FILE记录存放不下时还可以用扩展属性,增加FILE记录来保存,即一个文件可以有多个FILE记录。

NTFS的同层目录采用B+树结构,按文件(夹)名保持有序,通过文件号指向文件夹内的文件。文件夹的目录项较少时可以直接存储在文件夹的FILE记录中,目录项较多时占用数据簇,建立INDX记录,存放各目录项的属性。

NTFS文件系统一共由16个“元文件”构成

Linux常见 EXT文件系统的发展简介

ext1

  • 优点:1992 年的 ext 使用在 Linux 内核中的新虚拟文件系统(VFS)抽象层。
    • 与之前的 MINIX 文件系统不同的是,ext 可以处理高达 2 GB 存储空间并处理 255 个字符的文件名。
  • 缺点:原始的时间戳(每个文件仅有一个时间戳,而不是今天我们所熟悉的有 inode、最近文件访问时间和最新文件修改时间的时间戳。)

ext2

  • 优点:提供了 GB 级别的最大文件大小和 TB 级别的文件系统大小。
  • 缺点:
    • 将数据写入到磁盘的时候,系统发生崩溃或断电,则容易发生灾难性的数据损坏。
    • 随着时间的推移,由于碎片(单个文件存储在多个位置,物理上其分散在旋转的磁盘上),它们也遭受了严重的性能损失。

ext3

  • 2001 年 11 月在 2.4.15 内核版本中被采用到 Linux 内核主线中。
  • 优点:使用日志来解决断电数据不一致问题,和 20 世纪 90 年代后期的其它文件系统一样,如微软的 NTFS。

ext4

  • 2008年在 2.6.28 内核版本中被加入到了 Linux 主线。
  • 优点:
    • 支持大文件系统,
      • ext3 文件系统使用 32 位寻址,这限制它仅支持 2 TiB 文件大小和 16 TiB 文件系统系统大小
      • ext4 使用 48 位的内部寻址,理论上可以在文件系统上分配高达 16 TiB 大小的文件,其中文件系统大小最高可达 1000000 TiB(1 EiB)
    • 分配方式改进,显著提高读写性能
      • 区段(extent)
        • 是一系列连续的物理块 (最多达 128 MiB,假设块大小为 4 KiB),可以一次性保留和寻址。使用区段而不是 block可以减少给定文件所需的 inode 数量,并显著减少碎片并提高写入大文件时的性能。
      • 多块分配(multiple block allocation)
        • ext3 为每一个新分配的块调用一次块分配器。当多个写入同时打开分配器时,很容易导致严重的碎片。
        • 多块分配(multiple block allocation)允许一次性分配大量的连续文件块,以降低碎片并且有利于 RAID 设备的并行写入
      • 延迟分配(delayed block allocation)
        • ext4 使用延迟分配(delayed block allocation),这允许它合并写入并更好地决定如何为尚未提交的写入分配块。
        • 延迟分配允许 ext4 等待分配将写入数据的实际块,直到它准备好将数据提交到磁盘。(相比之下,即使数据仍然在往写入缓存中写入,ext3 也会立即分配块。)
        • 当缓存中的数据累积时,延迟分配块允许文件系统对如何分配块做出更好的选择,降低碎片(写入,以及稍后的读)并显著提升性能。
      • 持久的预分配( allocation without initialization)
        • 在为文件预分配磁盘空间时,大部分文件系统必须在创建时将零写入该文件的块中。
        • ext4 允许替代使用 fallocate(),它保证了空间的可用性(并试图为它找到连续的空间),而不需要先写入它。这显著提高了写入和将来读取流和数据库应用程序的写入数据的性能。
    • 提高了对碎片的抵抗力
      • ext2 和 ext3 都不直接支持在线碎片整理 —— 即在挂载时会对文件系统进行碎片整理。
      • ext4 通过 e4defrag 解决了这个问题,且是一个在线、内核模式、文件系统感知、块和区段级别的碎片整理实用程序。

Nas 防止碎片,开启预分配

实践问题: Nas 的 ext4 挂载被识别成NTFS

估计是有一层转换,类似的软件有 UFS Explorer

磁盘读写原理

读写操作分层

对于磁盘的一次读请求,

  • 首先经过虚拟文件系统层(VFS Layer),
  • 其次是具体的文件系统层(例如Ext2),
  • 接下来是Cache层(Page Cache Layer)、
  • 通用块层(Generic Block Layer)、
  • I/O调度层(I/O Scheduler Layer)、
  • 块设备驱动层(Block Device Driver Layer),
  • 最后是物理块设备层(Block Device Layer)。

Page Cache层

  • 为了提高Linux操作系统对磁盘访问的性能。Cache层在内存中缓存了磁盘上的部分数据。当数据的请求到达时,如果在Cache中存在该数据且是最新的,则直接将数据传递给用户程序,免除了对底层磁盘的操作,提高了性能。
  • 文件Cache分为两个层面,
    • 一是Page Cache,另一个Buffer Cache,每一个Page Cache包含若干Buffer Cache。
    • Page Cache主要用来作为文件系统上的文件数据的缓存来用,尤其是针对当进程对文件有read/write操作的时候。
    • Buffer Cache则主要是设计用来在系统对块设备进行读写的时候,对块进行数据缓存的系统来使用。
  • 磁盘Cache有两大功能:预读和回写。
    • 预读其实就是利用了局部性原理,具体过程是:
      • 对于每个文件的第一个读请求,系统读入所请求的页面并读入紧随其后的少数几个页面(通常是三个页面),这时的预读称为同步预读。
      • 对于第二次读请求,
        • 如果所读页面不在Cache中,即不在前次预读的页中,则表明文件访问不是顺序访问,系统继续采用同步预读;
        • 如果所读页面在Cache中,则表明前次预读命中,操作系统把预读页的大小扩大一倍,此时预读过程是异步的,应用程序可以不等预读完成即可返回,只要后台慢慢读页面即可,这时的预读称为异步预读。
      • 任何接下来的读请求都会处于两种情况之一:第一种情况是所请求的页面处于预读的页面中,这时继续进行异步预读;第二种情况是所请求的页面处于预读页面之外,这时系统就要进行同步预读。
    • 回写是通过暂时将数据存在Cache里,然后统一异步写到磁盘中。
      • 通过这种异步的数据I/O模式解决了程序中的计算速度和数据存储速度不匹配的鸿沟,减少了访问底层存储介质的次数,使存储系统的性能大大提高。Linux
      • 2.6.32内核之前,采用pdflush机制来将脏页真正写到磁盘中,什么时候开始回写呢?下面两种情况下,脏页会被写回到磁盘:
        • 在空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘,以便释放内存。
        • 当脏页在内存中驻留超过一定的阈值时,内核必须将超时的脏页写会磁盘,以确保脏页不会无限期地驻留在内存中。

I/O调度层

  • I/O调度层的功能是管理块设备的请求队列。
    • 即接收通用块层发出的I/O请求,缓存请求并试图合并相邻的请求。
    • 并根据设置好的调度算法,回调驱动层提供的请求处理函数,以处理具体的I/O请求。
  • 如果简单地以内核产生请求的次序直接将请求发给块设备的话,那么块设备性能肯定让人难以接受,因为磁盘寻址是整个计算机中最慢的操作之一。
  • 为了优化寻址操作,内核不会一旦接收到I/O请求后,就按照请求的次序发起块I/O请求。
  • 为此Linux实现了几种I/O调度算法,算法基本思想就是通过合并和排序I/O请求队列中的请求,以此大大降低所需的磁盘寻道时间,从而提高整体I/O性能。

常见的I/O调度算法包括

  1. Noop调度算法(No Operation)、
  2. CFQ(完全公正排队I/O调度算法)、
  3. DeadLine(截止时间调度算法)、
  4. AS预测调度算法等。

磁盘快速I/O常见机制

Linux系统中请求到达磁盘的一次完整过程,期间Linux一般会通过Cache以及排序合并I/O请求来提高系统的性能。

其本质就是由于磁盘随机读写慢、顺序读写快的磁盘I/O特性。

采用追加写

在进行系统设计时,良好的读性能和写性能往往不可兼得。在许多常见的开源系统中都是优先在保证写性能的前提下来优化读性能。那么如何设计能让一个系统拥有良好的写性能呢?

  • 一个好的办法就是采用追加写,每次将数据添加到文件。
  • 由于完全是顺序的,所以可以具有非常好的写操作性能。
  • 但是这种方式也存在一些缺点:从文件中读一些数据时将会需要更多的时间:
    • 需要倒序扫描,直到找到所需要的内容。
    • 当然在一些简单的场景下也能够保证读操作的性能:
      • 数据是被整体访问,比如HDFS
      • 知道文件明确的偏移量,比如Kafka
    • 在面对更复杂的读场景(比如按key)时,如何来保证读操作的性能呢?
      • 简单的方式是像Kafka那样,将文件数据有序保存,使用二分查找来优化效率;
      • 或者通过建索引的方式来进行优化;
      • 也可以采用hash的方式将数据分割为不同的桶。
    • 以上的方法都能增加读操作的性能,但是由于在数据上强加了数据结构,又会降低写操作的性能。
      • 比如如果采用索引的方式来优化读操作,那么在更新索引时就需要更新B-tree中的特定部分,这时候的写操作就是随机写。
    • 那么有没有一种办法在保证写性能不损失的同时也提供较好的读性能呢?
    • 一个好的选择就是使用LSM-tree。
      • LSM-tree与B-tree相比,LSM-tree牺牲了部分读操作,以此大幅提高写性能。

文件合并和元数据优化

目前的大多数文件系统,如XFS/Ext4、GFS、HDFS,在元数据管理、缓存管理等实现策略上都侧重大文件。

磁盘碎片

不同文件系统的比较

像 FAT 和 FAT32 这类文件系统中,文件紧挨着写入到磁盘中。文件之间没有空间来用于增长或者更新:

NTFS 中在文件之间保留了一些空间,因此有空间进行增长。但因块之间的空间是有限的,碎片也会随着时间出现。

Linux 的日志型文件系统采用了一个不同的方案。与文件相互挨着不同,每个文件分布在磁盘的各处,每个文件之间留下了大量的剩余空间。这就给文件更新和增长留下了很大的空间,碎片很少会发生。

此外,碎片一旦出现了,大多数 Linux 文件系统会尝试将文件和块重新连续起来。

检测命令

在已经挂载的分区中运行 fsck 将会严重危害到你的数据和磁盘。

1
2
umount /path
fsck -fn /path

大于20%需要整理。批评fsck不准的文章:大文件碎片少才是最重要的

NEC 的 Akira Fujita 和 Takashi Sato 在十年前就为 ext4 写了在线整理碎片的工具,因此我们直接拿来用就好了。

1
e4defrag -v /path

碎片整理

方法一:整个磁盘文件备份,格式化,重新搬运。(Liunx 会自动将文件进行连续分布排列。)

方法二:

1
2
# 不要中断,很危险
sudo e4defrag /

常见实践问题

为什么出现坏道之后,硬盘会飞速损耗

坏道分为逻辑坏道,和物理坏道。如果是物理坏道,由于异物或者碰撞导致磁头,盘面受损,会导致物理损坏扩散,应该今早备份数据。

并行下载多个两个文件,存储是交叉的吗?读数据会变慢吗?

场景问题:

1.同时向机械硬盘拷贝多个文件夹,每个文件夹里都有多个小文件。
2.同时解压多个压缩包,每个压缩包有大量的小文件。
3.同时安装多个游戏安装包。
会不会导致交叉存储?会不会导致碎片增加?会不会导致游玩游戏时读取速度变慢?

一般不用担心,有些文件系统会做碎片整理。然后操作系统的缓存写和预读策略也会优化。

硬盘的寿命

对于机械硬盘来讲,反复读写、多线程读写等情况对磁盘使用寿命的影响很低,
但“高温”、“低温”、“尘土”、“外力冲击(跌落)”等情况,会对磁盘的寿命造成较大的影响。

需要进一步的研究学习

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E9%87%8D%E5%AD%A6%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E5%AE%8C/30%20%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0%EF%BC%9AFAT%E3%80%81NTFS%20%E5%92%8C%20Ext3%20%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%EF%BC%9F.md

https://www.ruanyifeng.com/blog/2011/12/inode.html

https://tech.meituan.com/2017/05/19/about-desk-io.html

https://zhuanlan.zhihu.com/p/44267768

https://developer.aliyun.com/article/197465