概叙
科普文:软件架构Linux系列之【从硬件角度了解固态盘SSD】-CSDN博客
科普文:软件架构Linux系列之【从硬件角度了解机械盘HDD】-CSDN博客
科普文:软件架构Linux系列之【读懂Linux内存管理:mmap(Memory-Mapped File)内存映射文件】-CSDN博客
在前面的文章中,,主要对存储文件的磁盘的一些基础知识进行了介绍。对于Linux系统来说,一切的数据都起源于磁盘中存储的文件。
Linux文件系统的结构及其在磁盘中是如何存储的?
操作系统是怎样找到这些文件进行读取的?
Linux文件系统
由于磁盘很大,为了更加方便的管理,OS对磁盘块进行了分区。分区后再对每一个磁盘区域进行分组。具体结构如下:
在OS对磁盘进行分区时,会在最开始的位置设置一个 Boot Block ,这段区域里面主要保存与OS相关的内容,比如分区表、镜像地址等等。一般而言这个分区存在于 0 号盘面的 0 号磁道的 1 号扇区。当用户开机时,OS会加载磁盘的驱动,读取磁盘的分区表,再从特定分区的开始位置读取到OS所在的地址,并加载OS,此时OS才算真正运行起来。
在之后是OS对每一个分区进行分组形成的诸多 Block group,即块组 。每一个 Block group 都有上图所示的 6 块区域。
1、Super Block
Super Block保存的是文件系统的所有的属性信息,包括文件系统的类型、整个分组的情况。记录的信息主要有:block和inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最后一次写入数据的时间,最近一次写入磁盘的时间等其他文件系统的相关信息。
2、Group Descriptor Table
GDT 为组描述符,保存该组内的详细统计等属性信息。比如本组内从哪里到哪里是哪部分内容,本组被使用了多少等等。
3、inode Table
一般而言,我们把文件内部所有属性的集合叫做inode节点,一般大小为128字节。一个文件会有一个inode,一个分组内会有大量的文件,也有大量的inode节点,所以在组内会有一个专门的区域来保护这些inode节点,这个区域就叫做inode Table,也叫 inode 表。
在分组内部,每个inode表都有自己的inode编号,inode编号本身也属于对应文件的属性,Linux查找一个文件的时候,也是通过inode编号来查找的。
一个inode对应一个文件,该文件的inode属性和该文件对应的数据块是有映射关系的。
4、Data Blocks
文件的内容是变化的,用数据块来进行保存。所以要保存一个有效文件的内容,就需要 n 个数据块。如果有多个文件就需要多个数据块。这些数据块所在的区域就是 Data Blocks 。一个数据块的默认大小是 4KB 。
Linux查找一个文件,首先找到该文件的inode。在inode结构体内部有一个 int blocks[NUM] 数组,数组内记录了存储该文件内容的数据块的地址。一个分组中,百分之95以上的内容都是 Data Blocks 。
当操作系统要加载一个文件时,只加载该文件的 inode 节点。而 inode 节点中包含该文件内容数据块的映射关系,想要访问哪部分内容,就根据映射关系把哪一部分内容加载到内存中。
5、inode Bitmap
inode Bitmap 是一个位图结构,每个bit表示一个 inode 是否空闲可用。
6、Block Bitmap
Block Bitmap 是一个位图结构,记录着 Data Block 中哪个数据块已经被占用,哪个数据块没
有被占用。
文件路径
在Linux系统中,路径可以是相对的也可以是绝对的。
绝对路径: 从根目录(/)开始的完整路径,不依赖当前工作目录。例如:
/home/user/documents
相对路径: 不以根目录开始的路径,相对于当前工作目录。例如,如果当前工作目录是/home/user
,要指向同一目录下的documents
,可以只写:
./documents 或者直接 documents
相对路径表示法:
-
..
表示上一级目录(父目录) -
../
表示上移一级目录 -
./
表示当前目录(通常可以省略)
例如,从/home/user
要到/etc
目录下,可以使用相对路径:
cd ../../etc
inode概叙
1、inode与文件名
Linux系统只认inode值,且inode属性中不会包含文件名,因为文件名只是提供给用户看的
任何一个文件一定存在于目录中,目录其实也是一个文件,也有自己的inode值和对应的数据块,目录的数据库块里保存的是该目录的文件名和inode值对应的映射关系,而且在目录内,文件名与inode编号互为key值
inode number 在一个分区内唯一有效,不能跨分区使用。根据 inode number 可以确定该文件在当前分区的哪一个分组。
2、文件的增删查改
2.1、查看文件内容
当用户访问一个目标文件的内容时,一定是在特定目录下访问的,具体流程如下:
先要在当前目录下找到目标文件的 inode number 。
一个目录也是文件,也隶属于一个分区,在该分区中通过目标文件的 inode number 找到分组,在该组的 inode Table 区域找到目标文件的 inode 。
通过目标文件的 inode 与对应 Data blocks 的映射关系,找到该文件的数据块,加载到OS,最后显示在显示器上。
2.2、删除文件
当用户删除一个目标文件时,具体流程如下:
在当前目录下,根据文件名找到目标文件的 inode number 。
根据 inode number 找到目标文件的 inode ,结合与对应 Data blocks 的映射关系,把 block bitmap 对应的比特位设置为 0 。
根据 inode number 把 inode bitmap 对应的比特位设置为 0 。
2.3、创建文件
当用户创建一个目标文件时,一定是在一个目录下创建的。具体流程如下:
OS在目录所处的分组里扫描 inode bitmap ,找到空余的位置并设置为 1 ,获得 inode number 。
把该文件创建出来后的默认属性填充到对应的 inode 中。
在当前所处的目录文件的 Data blocks 里追加一条新的文件名与 inode number 的映射关系。
2.4、补充内容
上面的内容包括分区、分组、填写系统属性等等,这些工作都是OS做的。分区完成之后,为了让分区能够正常使用,需要对分区做格式化操作,即OS向分区写入文件系统的管理属性信息,并做区域划分工作。如果区域划分之前已经做好了,那么格式化操作把位图结构清空,把属性字段设置为初始状态就可以了。
文件系统给 inode 与 Data blocks 建立映射关系通过数组来完成,由于 Data blocks 很大,为了能够映射的过来,数组采用了直接索引、二级索引、三级索引的方式来完成映射,因为不是重点内容,仅作了解,不作讲解。
文件系统中,有可能出现 inode 没用完,Data blocks 用完了。或者 inode 用完了,但是 Data blocks 还有剩余的情况。比如只建立一个文件,然后不断地往这一个文件中塞入数据,消耗 Data blocks。或者不断地建立空文件,消耗 inode 。这种问题目前是没有办法解决避免的。
软硬链接
1、软链接
建立软链接指令:ln -s [目标文件] [软链接文件名称]
使用 code-soft 链接了code。code-soft 是一个链接文件。
观察到 code-soft 与 code.c的 inode number 不同,这说明软链接是一个独立的链接文件。有自己的 inode number,必有自己的inode属性和内容。软链接的内容是自己所指向的文件的路径。可以让用户快速的找到目标文件。
软链接的具体用法是:如果一个目标文件的路径非常深,我们每次访问目标文件都要写一遍很长的路径,效率不高。此时就可以使用软链接在工作目录制作一个软链接文件,以方便访问目标文件。类似 Windows 系统中的快捷方式。
2、硬链接
建立硬链接指令:ln [目标文件] [软链接文件名称]
具体操作如下:
使用 code-hard 链接了code.c。code-hard 是一个普通文件。
观察到 code-hard 与code.c的 inode number 相同,这说明硬链接与原文件是同一个文件,硬链接只是建立了新的文件名与老的inode number的映射关系,只修改了当前目录的内容。
code-hard 与 code.c 的硬链接数都变成了 2 。意思是此时有两种方法可以找到该文件,分别对应两个文件名。硬链接数,本质是一种引用计数。
现在我们使用指令 unlink 来删除硬链接:
此时文件的硬链接数又变成了 1
接下来我们再创建一个目录文件,观察硬链接数:
可以看到目录文件的默认硬连接数是 2 。这是因为目录文件天生拥有两个硬链接,一个是它本身的名字,另一个是在该目录内部的 " . " 符号。如果目录文件的内部还有目录文件,那么该目录文件的硬链接数就变成了 3 :本身的名字、该目录内部的 " . " 符号、该目录内部的目录内的 " .. " 符号:
Linux中不允许对目录进行硬链接
3、为什么要有硬链接
(1)、文件备份与冗余
提供额外的文件访问路径:创建硬链接后,多个文件名可以指向同一个文件的 inode(索引节点)。这意味着可以通过不同的路径名来访问同一个文件内容。如果一个路径名被意外删除或损坏,仍然可以通过其他硬链接路径访问文件,起到了一种备份的作用。
增加文件的可靠性:在一些关键应用场景中,通过创建硬链接可以确保文件在多个位置都能被访问,降低了因单个文件名丢失或损坏而导致数据丢失的风险。
(2)、文件管理与组织
方便文件共享:多个用户或程序可以通过不同的硬链接路径同时访问同一个文件,无需复制文件内容,节省了磁盘空间和时间。例如,在一个团队项目中,不同的成员可以通过各自的工作目录中的硬链接来访问共享的文件,实现文件的协同操作。
简化文件结构:可以使用硬链接来组织文件系统,使得相关的文件可以通过多个路径进行访问。这对于一些复杂的文件系统结构或需要灵活访问文件的情况非常有用。
(3)、与传统文件系统的兼容性
与旧有系统和工具的兼容性:许多传统的文件系统工具和应用程序都能够理解和处理硬链接。这使得在从旧系统迁移到 Linux 或在不同的文件系统环境中工作时,能够继续使用熟悉的文件管理方式。
稳定性和可靠性:硬链接的实现基于文件系统的底层结构,相对稳定可靠。不像某些高级文件系统特性可能会在不同的操作系统版本或文件系统实现中存在差异,硬链接在大多数情况下都能提供一致的行为。
动静态库
动静态库的本质就是可执行程序的"半成品"。
一段代码生成一个可执行程序需要以下的四个步骤:
预处理:完成头文件的展开,去掉注释,宏替换,条件编译等,最终形成xx.i文件
编译:完成语法分析,词法分析,语义分析,符号汇总,检查无误后将代码编译成汇编指令,最终形成xx.s文件
汇编:将汇编指令转换成二进制文件,xx.o文件
链接:将生成的各个.o文件进行链接,最终形成可执行程序
Linux系统目录树
几乎所有的计算机操作系统都是使用目录结构组织文件。具体来说就是在一个目录中存放子目录和文件,而在子目录中又会进一步存放子目录和文件,以此类推形成一个树状的文件结构,由于其结构很像一棵树的分支,所以该结构又被称为目录树。
- windows:以多根的方式组织文件,系统目录与磁盘是强对应的。C盘下目录文件不可能与D盘下目录有关联或交集
- Linux:以单根的方式组织文件。Linux系统目录与磁盘等设备是不直接关联的,每个目录都可以关联(官称:挂载)在不同的设备如磁盘上。访问/、/etc、/boot时可能是在访问完全不同的分区和磁盘。
目录树(directory tree)
在Linux底下,所有的文件与目录都是由根目录开始的。那是所有目录与文件的源头, 然后再一个一个的分支下来,因此,我们也称这种目录配置方式为:目录树(directory tree), 这个目录树的主要特性有:
-
目录树的启始点为根目录 (/, root);
-
每一个目录不止能使用本地端的 partition 的文件系统,也可以使用网络上的 filesystem 。举例来说, 可以利用 Network File System (NFS) 服务器挂载某特定目录等。
-
每一个文件在此目录树中的文件名(包含完整路径)都是独一无二的。
linux文件系统所有文件和目录都是由根目录开始的,以树的形式展开,如下图所示:
Linux 系统目录结构的最顶端是“/”,称其为根目录,根目录是 Linux 系统所有目录的起始点,所有的目录、文件、设备都在“/”之下,根目录下的目录是个树状结构,可以这么说,“/”就是Linux 文件系统的组织者、领导者,通过 tree 命令可以查看 Linux 的一级目录结构。
示例代码如下:
根据FHS的基本定义,根目录下面的各个目录(如usr,var)基本上都有其特定的意义,在此不多做介绍。重点说一下根目录'/'的作用和意义:
- 其他所有目录都是由根目录衍生出来的。
- 根目录中包含了开机软件、系统内核文件、函数库、文件系统修复程序等。
因此,根目录(/)所在的分区应该越小越好,应用程序所安装的软件最好不要与根目录存放在同一个分区。根目录越小,系统性能会更好,根目录所在的文件系统也较不容易出现问题。
Linux 下面的设备(磁盘),如果不挂载,则是看不到入口的,就像没窗没门的监獄一样,是不能被正常使用的,如果要访问设备,就必须为设备开一个入口,这个人口就是挂载点,挂载点实质上就是一个目录,开入口的过程,就是将挂载点与磁盘设备相关联,即挂载。
查看/etc/fstab 开机设备自动挂载文件
根/目录概叙
Filesystem Hierarchy Standard(文件系统层次化标准)的缩写, 多数Linux版本采用这种文件组织形式,类似于Windows操作系统中c盘的文件目录,FHS采用树形结构组织文件。FHS定义了系统中每个区域的用途、所需要的最小构成的文件和目录,同时还给出了例外处理与矛盾处理。
事实上,FHS是根据过去的经验一直再持续的改版的,FHS依据文件系统使用的频繁与否与是否允许使用者随意更动, 而将目录定义成为四种交互作用的形态,用表格来说有点像底下这样:
可分享的(shareable) | 不可分享的(unshareable) | |
---|---|---|
不变的(static) | /usr (软件放置处) | /etc (配置文件) |
/opt (第三方协力软件) | /boot (开机与核心档) | |
可变动的(variable) | /var/mail (使用者邮件信箱) | /var/run (程序相关) |
/var/spool/news (新闻组) | /var/lock (程序相关) |
1.可分享的:可以分享给其他系统挂载使用的目录,所以包括执行文件与用户的邮件等数据, 是能够分享给网络上其他主机挂载用的目录;
2.不可分享的:自己机器上面运作的装置文件或者是与程序有关的socket文件等, 由于仅与自身机器有关,所以当然就不适合分享给其他主机了。
3.不变的:有些数据是不会经常变动的,跟随着distribution而不变动。 例如函式库、文件说明文件、系统管理员所管理的主机服务配置文件等等;
4.可变动的:经常改变的数据,例如登录文件、一般用户可自行收受的新闻组等。
事实上,FHS针对目录树架构仅定义出三层目录底下应该放置什么数据而已,分别是底下这三个目录的定义:
- / (root, 根目录):与开机系统有关;
- /usr (unix software resource):与软件安装/执行有关;
- /var (variable):与系统运作过程有关。
目录 | 应放置档案内容 |
---|---|
/bin | 系统有很多放置执行档的目录,但/bin比较特殊。因为/bin放置的是在单人维护模式下还能够被操作的指令。在/bin底下的指令可以被root与一般帐号所使用,主要有:cat,chmod(修改权限), chown, date, mv, mkdir, cp, bash等等常用的指令。 |
/boot | 主要放置开机会使用到的档案,包括Linux核心档案以及开机选单与开机所需设定档等等。Linux kernel常用的档名为:vmlinuz ,如果使用的是grub这个开机管理程式,则还会存在/boot/grub/这个目录。 |
/dev | 在Linux系统上,任何装置与周边设备都是以档案的型态存在于这个目录当中。 只要通过存取这个目录下的某个档案,就等于存取某个装置。比要重要的档案有/dev/null, /dev/zero, /dev/tty , /dev/lp, / dev/hd, /dev/sd*等等 |
/etc | 系统主要的设定档几乎都放置在这个目录内,例如人员的帐号密码档、各种服务的启始档等等。 一般来说,这个目录下的各档案属性是可以让一般使用者查阅的,但是只有root有权力修改。 FHS建议不要放置可执行档(binary)在这个目录中。 比较重要的档案有:/etc/inittab, /etc/init.d/, /etc/modprobe.conf, /etc/X11/, /etc/fstab, /etc/sysconfig/等等。 另外,其下重要的目录有:/etc/init.d/ :所有服务的预设启动script都是放在这里的,例如要启动或者关闭iptables的话: /etc/init.d/iptables start、/etc/init.d/ iptables stop/etc/xinetd.d/ :这就是所谓的super daemon管理的各项服务的设定档目录。 /etc/X11/ :与X Window有关的各种设定档都在这里,尤其是xorg.conf或XF86Config这两个X Server的设定档。 |
/home | 这是系统预设的使用者家目录(home directory)。 在你新增一个一般使用者帐号时,预设的使用者家目录都会规范到这里来。比较重要的是,家目录有两种代号: ~ :代表当前使用者的家目录,而 ~guest:则代表用户名为guest的家目录。 |
/lib | 系统的函式库非常的多,而/lib放置的则是在开机时会用到的函式库,以及在/bin或/sbin底下的指令会呼叫的函式库而已 。 什么是函式库呢?妳可以将他想成是外挂,某些指令必须要有这些外挂才能够顺利完成程式的执行之意。 尤其重要的是/lib/modules/这个目录,因为该目录会放置核心相关的模组(驱动程式)。 |
/media | media是媒体的英文,顾名思义,这个/media底下放置的就是可移除的装置。 包括软碟、光碟、DVD等等装置都暂时挂载于此。 常见的档名有:/media/floppy, /media/cdrom等等。 |
/mnt | 如果妳想要暂时挂载某些额外的装置,一般建议妳可以放置到这个目录中。在古早时候,这个目录的用途与/media相同啦。 只是有了/media之后,这个目录就用来暂时挂载用了。 |
/opt | 这个是给第三方协力软体放置的目录 。 什么是第三方协力软体啊?举例来说,KDE这个桌面管理系统是一个独立的计画,不过他可以安装到Linux系统中,因此KDE的软体就建议放置到此目录下了。 另外,如果妳想要自行安装额外的软体(非原本的distribution提供的),那么也能够将你的软体安装到这里来。 不过,以前的Linux系统中,我们还是习惯放置在/usr/local目录下。 |
/root | 系统管理员(root)的家目录。 之所以放在这里,是因为如果进入单人维护模式而仅挂载根目录时,该目录就能够拥有root的家目录,所以我们会希望root的家目录与根目录放置在同一个分区中。 |
/sbin | Linux有非常多指令是用来设定系统环境的,这些指令只有root才能够利用来设定系统,其他使用者最多只能用来查询而已。放在/sbin底下的为开机过程中所需要的,里面包括了开机、修复、还原系统所需要的指令。至于某些伺服器软体程式,一般则放置到/usr/sbin/当中。至于本机自行安装的软体所产生的系统执行档(system binary),则放置到/usr/local/sbin/当中了。常见的指令包括:fdisk, fsck, ifconfig, init, mkfs等等。 |
/srv | srv可以视为service的缩写,是一些网路服务启动之后,这些服务所需要取用的资料目录。 常见的服务例如WWW, FTP等等。 举例来说,WWW伺服器需要的网页资料就可以放置在/srv/www/里面。呵呵,看来平时我们编写的代码应该放到这里了。 |
/tmp | 这是让一般使用者或者是正在执行的程序暂时放置档案的地方。这个目录是任何人都能够存取的,所以你需要定期的清理一下。当然,重要资料不可放置在此目录啊。 因为FHS甚至建议在开机时,应该要将/tmp下的资料都删除。 |
事实上FHS针对根目录所定义的标准就仅限于上表,不过仍旧有些目录也需要我们了解一下,具体如下:
目录 | 应放置文件内容 |
---|---|
/lost+found | 这个目录是使用标准的ext2/ext3档案系统格式才会产生的一个目录,目的在于当档案系统发生错误时,将一些遗失的片段放置到这个目录下。 这个目录通常会在分割槽的最顶层存在,例如你加装一个硬盘于/disk中,那在这个系统下就会自动产生一个这样的目录/disk/lost+found |
/proc | 这个目录本身是一个虚拟文件系统(virtual filesystem)喔。 他放置的资料都是在内存当中,例如系统核心、行程资讯(process)(是进程吗?)、周边装置的状态及网络状态等等。因为这个目录下的资料都是在记忆体(内存)当中,所以本身不占任何硬盘空间。比较重要的档案(目录)例如: /proc/cpuinfo, /proc/dma, /proc/interrupts, /proc/ioports, /proc/net/*等等。呵呵,是虚拟内存吗[guest]? |
/sys | 这个目录其实跟/proc非常类似,也是一个虚拟的档案系统,主要也是记录与核心相关的资讯。 包括目前已载入的核心模组与核心侦测到的硬体装置资讯等等。 这个目录同样不占硬盘容量。 |
除了这些目录的内容之外,另外要注意的是,因为根目录与开机有关,开机过程中仅有根目录会被挂载, 其他分区则是在开机完成之后才会持续的进行挂载的行为。就是因为如此,因此根目录下与开机过程有关的目录, 就不能够与根目录放到不同的分区去。
那哪些目录不可与根目录分开呢?
有底下这些:
- /etc:配置文件
- /bin:重要执行档
- /dev:所需要的装置文件
- /lib:执行档所需的函式库与核心所需的模块
- /sbin:重要的系统执行文件
这五个目录千万不可与根目录分开在不同的分区。
重点目录
/etc 系统重要配置文件, 以及常用服务配置文件
/var 存放系统引导启动时产生的可变文件,文件通常动态更改的,例如: 缓存目录,日志文件
/run 系统启动后, 运行的程序产生的运行时数据, 包括进程的pid文件,锁文件等
/home 普通用户的主目录, 普通用户的家目录默认为/HOME/USERNAME
/root 超级管理员的主目录, 普通用户无权操作
/tmp 存放临时文件, 一般存放超过10天以上都会自动删除,可以更改删除临时文件的期限
/boot 存放系统引导时候需要的文件
/dev 存放设备文件
/usr 安装的软件, 共享库, 重要的子目录有
/usr/bin 用户命令目录
/usr/sbin 管理员命令目录
/usr/local 本地自定义安装的软件
/etc/目录
特定主机系统范围内的配置文件。
目录 | 描述 |
/etc/rc /etc/rc.d /etc/rc*.d | 启动、或改变运行级时运行的scripts或scripts的目录. |
/etc/hosts | 本地域名解析文件 |
/etc/sysconfig/network | IP、掩码、网关、主机名配置 |
/etc/resolv.conf | DNS服务器配置 |
/etc/fstab | 开机自动挂载系统,所有分区开机都会自动挂载 |
/etc/inittab | 设定系统启动时Init进程将把系统设置成什么样的runlevel及加载相关的启动文件配置 |
/etc/exports | 设置NFS系统用的配置文件路径 |
/etc/init.d | 这个目录来存放系统启动脚本 |
/etc/profile, /etc/csh.login, /etc/csh.cshrc | 全局系统环境配置变量 |
/etc/issue | 认证前的输出信息,默认输出版本内核信息 |
/etc/motd | 设置认证后的输出信息, |
/etc/mtab | 当前安装的文件系统列表.由scripts初始化,并由mount 命令自动更新.需要一个当前安装的文件系统的列表时使用,例如df 命令 |
/etc/group | 类似/etc/passwd ,但说明的不是用户而是组. |
/etc/passwd | 用户数据库,其中的域给出了用户名、真实姓名、家目录、加密的口令和用户的其他信息. |
/etc/shadow | 在安装了影子口令软件的系统上的影子口令文件.影子口令文件将/etc/passwd 文件中的加密口令移动到/etc/shadow 中,而后者只对root可读.这使破译口令更困难. |
/etc/sudoers | 可以sudo命令的配置文件 |
/etc/syslog.conf | 系统日志参数配置 |
/etc/login.defs | 设置用户帐号限制的文件 |
/etc/securetty | 确认安全终端,即哪个终端允许root登录.一般只列出虚拟控制台,这样就不可能(至少很困难)通过modem或网络闯入系统并得到超级用户特权. |
/etc/printcap | 类似/etc/termcap ,但针对打印机.语法不同. |
/etc/shells | 列出可信任的shell.chsh 命令允许用户在本文件指定范围内改变登录shell.提供一台机器FTP服务的服务进程ftpd 检查用户shell是否列在 /etc/shells 文件中,如果不是将不允许该用户登录. |
/etc/xinetd.d | 如果服务器是通过xinetd模式运行的,它的脚本要放在这个目录下。有些系统没有这个目录,比如Slackware,有些老的版本也没有。在Redhat Fedora中比较新的版本中存在。 |
/etc/opt/ | /opt/的配置文件 |
/etc/X11/ | X_Window系统(版本11)的配置文件 |
/etc/sgml/ | SGML的配置文件 |
/etc/xml/ | XML的配置文件 |
/etc/skel/ | 默认创建用户时,把该目录拷贝到家目录下 |
/usr/目录
默认软件都会存于该目录下。用于存储只读用户数据的第二层次;包含绝大多数的用户工具和应用程序。
目录 | 描述 |
/usr/X11R6 | 存放X-Windows的目录; |
/usr/games | 存放着XteamLinux自带的小游戏; |
/usr/doc | Linux技术文档; |
/usr/include | 用来存放Linux下开发和编译应用程序所需要的头文件; |
/usr/lib | 存放一些常用的动态链接共享库和静态档案库; |
/usr/man | 帮助文档所在的目录; |
/usr/src | Linux开放的源代码,就存在这个目录,爱好者们别放过哦; |
/usr/bin/ | |
/usr/lib/ | /usr/bin/和/usr/sbin/中二进制文件的库。 |
/usr/sbin/ | |
/usr/share/ | 体系结构无关(共享)数据。 |
/usr/src/ | 源代码,例如:内核源代码及其头文件。 |
/usr/X11R6/ | X Window系统版本 11, Release 6. |
/usr/local/ | 本地数据的第三层次,具体到本台主机。通常而言有进一步的子目录,例如:bin/、lib/、share/.这是提供给一般用户的/usr目录,在这里安装一般的应用软件; |
/var/目录
/var 包括系统一般运行时要改变的数据.每个系统是特定的,即不通过网络与其他计算机共享.
目录 | 描述 |
/var/log/message | 日志信息,按周自动轮询 |
/var/spool/cron/root | 定时器配置文件目录,默认按用户命名 |
/var/log/secure | 记录登陆系统存取信息的文件,不管认证成功还是认证失败都会记录 |
/var/log/wtmp | 记录登陆者信息的文件,last,who,w命令信息来源于此 |
/var/spool/clientmqueue/ | 当邮件服务未开启时,所有应发给系统管理员的邮件都将堆放在此 |
/var/spool/mail/ | 邮件目录 |
/var/tmp | 比/tmp 允许的大或需要存在较长时间的临时文件. (虽然系统管理员可能不允许/var/tmp 有很旧的文件.) |
/var/lib | 系统正常运行时要改变的文件. |
/var/local | /usr/local 中安装的程序的可变数据(即系统管理员安装的程序).注意,如果必要,即使本地安装的程序也会使用其他/var 目录,例如/var/lock . |
/var/lock | 锁定文件.许多程序遵循在/var/lock 中产生一个锁定文件的约定,以支持他们正在使用某个特定的设备或文件.其他程序注意到这个锁定文件,将不试图使用这个设备或文件. |
/var/log/ | 各种程序的Log文件,特别是login (/var/log/wtmp log所有到系统的登录和注销) 和syslog (/var/log/messages 里存储所有核心和系统程序信息. /var/log 里的文件经常不确定地增长,应该定期清除. |
/var/run | 保存到下次引导前有效的关于系统的信息文件.例如, /var/run/utmp 包含当前登录的用户的信息. |
/var/cache/ | 应用程序缓存数据。这些数据是在本地生成的一个耗时的I/O或计算结果。应用程序必须能够再生或恢复数据。缓存的文件可以被删除而不导致数据丢失。 |
/proc/目录
虚拟文件系统,将内核与进程状态归档为文本文件(系统信息都存放这目录下)。
例如:uptime、 network。在Linux中,对应Procfs格式挂载。该目录下文件只能看不能改(包括root)
目录 | 描述 |
/proc/meminfo | 查看内存信息 |
/proc/loadavg | 还记得 top 以及 uptime 吧?没错!上头的三个平均数值就是记录在此! |
/proc/uptime | 就是用 uptime 的时候,会出现的资讯啦! |
/proc/cpuinfo | 关于处理器的信息,如类型、厂家、型号和性能等。 |
/proc/cmdline | 加载 kernel 时所下达的相关参数!查阅此文件,可了解系统是如何启动的! |
/proc/filesystems | 目前系统已经加载的文件系统罗! |
/proc/interrupts | 目前系统上面的 IRQ 分配状态。 |
/proc/ioports | 目前系统上面各个装置所配置的 I/O 位址。 |
/proc/kcore | 这个就是内存的大小啦!好大对吧!但是不要读他啦! |
/proc/modules | 目前我们的 Linux 已经加载的模块列表,也可以想成是驱动程序啦! |
/proc/mounts | 系统已经挂载的数据,就是用 mount 这个命令呼叫出来的数据啦! |
/proc/swaps | 到底系统挂加载的内存在哪里?呵呵!使用掉的 partition 就记录在此啦! |
/proc/partitions | 使用 fdisk -l 会出现目前所有的 partition 吧?在这个文件当中也有纪录喔! |
/proc/pci | 在 PCI 汇流排上面,每个装置的详细情况!可用 lspci 来查阅! |
/proc/version | 核心的版本,就是用 uname -a 显示的内容啦! |
/proc/bus/* | 一些汇流排的装置,还有 U盘的装置也记录在此喔! |
/dev/目录
设备文件分为两种:块设备文件(b)和字符设备文件(c)
设备文件一般存放在/dev目录下,
对常见设备文件作如下说明:
目录 | 描述 |
/dev/hd[a-t] | IDE设备 |
/dev/sd[a-z] | SCSI设备 |
/dev/fd[0-7] | 标准软驱 |
/dev/md[0-31] | 软raid设备 |
/dev/loop[0-7] | 本地回环设备 |
/dev/ram[0-15] | 内存 |
/dev/null | 无限数据接收设备,相当于黑洞 |
/dev/zero | 无限零资源 |
/dev/tty[0-63] | 虚拟终端 |
/dev/ttyS[0-3] | 串口 |
/dev/lp[0-3] | 并口 |
/dev/console | 控制台 |
/dev/fb[0-31] | framebuffer |
/dev/cdrom | => /dev/hdc |
/dev/modem | => /dev/ttyS[0-9] |
/dev/pilot | => /dev/ttyS[0-9] |
/dev/random | 随机数设备 |
/dev/urandom | 随机数设备 |
Linux文件(目录)存储方式
linux中,磁盘(硬盘)上的存储划分如下图所示:
- MBR: 主引导分区。
- 自举块(引导分区Boot Sector):分区中文件系统自身引导程序存放的地方。
- 超级块(Super block): 记录整个文件系统相关的信息的地方,它记录的信息主要有:block与inode的总量、使用量、剩余量,文件系统的挂载时间,最近一次写入数据的时间等。
- 柱面组(块组) 每个柱面为一个柱面组(组号与柱面号一致),一个分区包含多个柱面。
- 配置信息:不详。
- i节点位图(inode bitmap):每个inode结点对应位图中的一个位(这样一个字节可表示8个inode的使用情况),每个位值为0或1,表示该位所处下标对应的inode有没有被使用。
- 块位图(block bitmap):每个数据块或目录块都对应着块位图中的一个位,位的下标和块编号一一对应,每个位的值为0或1,表示该块是否已被使用。
- i节点表(数组)(inode table):每个文件或者目录都有对应的一个inode,inode放在inode table中,包括inode的编号及其对应的信息。
- i节点(inode): 存储文件相关信息(不包括文件名)。
- 数据块(data block): 存储文件具体内容。
- 目录块: 特殊一点的数据块,存放
inode编号--文件(目录)名
。
inode详解
inode的主要记录了文件的属性以及该文件实际数据是放在哪几号数据块(或目录块)中,具体包含以下信息:
- 文件的访问模式(r/w/x)
- 文件所有者和组(owner/group)
- 文件大小
- 文件创建或状态改变的时间(ctime)
- 最近一次的读取时间(atime)
- 最近修改的时间(mtime)
- 定义文件特性的标志(flag)
- 文件真正内容指向的数据块(pointer)
在Linux中,使用 ls 指定加上 -i 命令选项,就可以观察到文件的 inode 。
另外,inode的特征有:
- inode的数量和大小在磁盘格式化的时候就已经固定了,除非再次格式化重新设置,否则不可改变。
- 每个inode的大小均为128Bytes。
- 每个文件仅占用一个inode。
- 文件系统能够创建(存储)的文件数量和inode的数量有关,也和磁盘大小(数据块数量)有关。
- 系统读取文件时,需要先找到inode,分析inode记录的权限与用户是否符合,若符合才可以开始实际读取数据块中的内容。
- 为了解决inode数量可能不够用的问题,操作系统将inode记录block号的区域定义为12个直接、1个间接、1个双间接、1个三间接的记录区。
- 文件IO编程中常说的文件句柄,其实就是inode编号。
文件读取过程
已读取文件/var/log/message
为例,讲解读取文件messages时,从磁盘中查找/读取文件内容的过程。
- 首先系统通过挂载信息(在超级块中,位置固定)找到根目录(/)的inode编号,根目录对应的inode是固定的(通常为2号)。
- 根据根目录的inode编号(2号),在inode table中找到对应的inode信息,从inode信息中找到存储根目录信息的目录块编号,根据编号找到数据块,如图中标记为‘/’的方格,该目录块存储的信息如图中的dentry所示。
- 从目录块中存储的信息中,找到文件名(目录名)为var所对应的inode编号(2667711)。
- 在inode table中找到编号为2667711的inode信息,从该inode信息中,找到var目录存放的数据块。从var数据块存储的信息中,找到log目录对应的inode编号(267850)。
- 重复上述步骤,直至找到message文件对应的inode结点,根据inode结点中记录的message文件内容对应的数据块,从数据块中读取内容。
以机械盘为例:扇区、块(簇/数据块)、页
科普文:软件架构Linux系列之【从硬件角度了解机械盘HDD】-CSDN博客
在操作系统数据交互过程中,经常听到扇区、块(簇/数据块)、页
这几种单位,他们在数据交互过程中的意义为:
- 扇区: 磁头从磁盘中读取数据的最小单位,即磁头每次从磁盘中读取数据,都是一个扇区一个扇区读的。
- 块(簇): 操作系统与磁盘(硬盘)交互的最小数据单元(在linux系统中称为块,在windows系统中称为簇)。操作系统从硬盘中拿一块数据,即完成一次磁盘IO。块(数据块)的大小在硬盘格式化时被指定,一般有1K,2K,4K(最常用)。如果块的大小设置为4K,那么磁盘要读取8个扇区之后,才将数据块传给操作系统。另外,数据块也是DOS下数据存储的最小单元。例如,如果一个文件的大小为1K,而块的大小为4K,那么该文件还是会占用一个块,块中剩下的3K被空闲出来,不能用于存储其他数据。因此,设置块的大小时,需要考虑要存储文件的大小。
- 页: 操作系统访问内存时的最小单元,一般系统页的大小为4K(或者更大)。操作系统访问内存中的数据时,如果发现内存中没有哪个
页
可以提供该数据,那么会发生缺页,系统通过页替换(从硬盘中读取数据)的方式,将数据从硬盘读取到内存页中,再返回给调用者。
总的说来,主要就是不同系统、设备间数据交互时,使用了不同的机制和概念。
- 其中磁盘内部(磁盘驱动程序从磁盘)读取数据时,以扇区为单位;
- 操作系统从磁盘读取数据时,以块为单位;操作系统从内存读取数据时,以页为单位。
一个普通文件包括属性 + 内容,本质上都是数据,占据一个或多个扇区。操作系统通过寻址(CHS寻址/LBA寻址) 定位任意一个扇区,就能定位任意多个扇区,从而将文件从硬件角度读取或者写入。
LBA(Logical Block Addressing)逻辑块寻址模式: 它是一种抽象的、逻辑上的地址,用于指代硬盘上的数据块。
每个数据块都被分配了一个唯一的LBA地址,这个地址是一个 从0开始的连续的数字序列。
每个数据块的大小通常是512字节,但随着技术的发展,
这个大小也在不断变化,目前已经达 到了4KB或更大的大小。
所以LBA寻址方式不需要考虑硬盘的物理结构,这是与CHS寻址方式最大的不同之处。
我们已经知道如果OS/Linux可以得知磁盘地址(寻址),就能够访问任意一个扇区。但是由于OS/Linux是软件,磁盘是硬件,为了防止硬件发生迭代变化OS/Linux也要跟着变化,就要做好OS/Linux与硬件的解耦工作,因此OS/Linux内部使用的不是磁盘地址(寻址)。
为了减少进行IO操作的频率,OS/Linux与外设进行IO操作的基本单位大小是4KB(可以调整)。
就算只需要修改一个字节的数据,也需要把这个数据所在的4KB大小的数据都加载进内存,修改好后再统一写回磁盘,因此我们把磁盘称为块设备。OS/Linux需要有一套新的地址来进行块级别的访问。
把磁盘磁道看作一个连续的空间结构:
扇区就相当于连续的数组,此时定位一个扇区就只需要一个数组下标了。由于OS/Linux是以4KB为单位进行IO的,所以一个OS级别的文件块要包括8个扇区。
OS/Linux不关心扇区的概念,计算机常规的访问地址是通过 起始地址 + 偏移量 的方式进行的,因此OS/Linux访问数据块时,只需要知道数据块的起始地址 + 4KB 就可以了,把数据块看作一种类型。
所以块的地址本质就是数组的一个下标N,以后就可以采用下标N的方式定位任意一个块了。这种寻址方式被称为 LBA ,即逻辑块地址。
获得 LBA 地址后,通过简单的数学计算就可以转换成磁盘的 CHS 地址。
假如已知 LBA = 6500 ,磁盘一个磁面的大小为 5000 ,一个磁道的大小为 1000 。则其对应的地址是第 2 个磁面,第 6 个磁道,第 500 个扇区。
从此之后,对于磁盘的管理就被抽象成了对一个大数组的管理。
科普文:软件架构数据库系列之【MySQL5.7的InnoDB引擎存储结构分析:buffer+disk】_mysql 5.7 innodb存储引擎架构-CSDN博客
科普文:软件架构数据库系列之【详解InnoDB双写(Doublewrite Buffer)】-CSDN博客
看完操作系统和磁盘间的io过程,再去理解innodb的双写是不是就很明白了呢??
即产生了部分页面写问题,因为写 innodb 的一页无法保证原子性,所以引入了 Doublewrite Buffer。
innodb引擎对于磁盘读写的最小单位为页,每页为16kb(但是文件系统的一页为4kb,所以innodb引擎需要写4次文件系统,这4次操作不是原子性的)
其实就是当 innodb 要将数据落盘的时候,先将页数据拷贝到 Doublewrite Buffer 中,然后 Doublewrite Buffer 再刷盘到 Doublewrite Buffer Files,这时候数据已经落盘了。
Linux操作系统对文件存取操作的优化
并非每次读、写文件操作都会真正地从磁盘读出或写入,那样性能难以接受。为此操作系统使用了一系列机制,提升了文件IO的性能。
预读
在Linux操作系统中,对文件存取操作进行优化时,预读是一种常用的技术。预读是一种提前加载数据到内存的方法,目的是为了减少对磁盘的I/O操作,从而提高文件读取的效率。
科普文:软件架构Linux系列之【Linux的文件预读readahead】-CSDN博客
科普文:软件架构数据库系列之【数据库内核月报:InnoDB 预读 VS Oracle 多块读】-CSDN博客
科普文:软件架构数据库系列之【MySQL:InnoDB预读Ahead-read(线性预读linear read-ahead和随机预读randomread-ahead)】-CSDN博客
科普文:软件架构数据库系列之【MySQL查询优化器中的优化策略optimizer_switch--MRR 优化器】-CSDN博客
缓存
不管是硬盘还是操作系统,都会对从磁盘片中读取的数据进行缓存。硬盘中的缓存一般会比较小,如十几M,操作系统中的缓存则可能大很多。系统会将常用的文件数据放到主存储器的缓冲区,以加速文件系统的读写。
一般情况下,只要系统的内存够用,系统会尽可能多的将磁盘中常用的文件缓存到内存中,直至内存耗尽(这是正常现象)。
比如,如果你发现在电脑上读取文件的速度达到了2G每秒,那肯定不是真的从磁盘读取的,而是从缓存读取的。所以要测试磁盘真正的读数据的速度,需要先清空系统的缓存。
理解一下MySQL的redolog、undolog、binlog、脏数据刷盘。
科普文:软件架构数据库系列之【MySQL5.7的InnoDB引擎存储结构分析:buffer+disk】_mysql 5.7 innodb存储引擎架构-CSDN博客
innodb刷盘参数 os_sync
innodb_flush_method 是 MySQL 中的一个系统变量,用于控制 InnoDB 如何将数据写入磁盘。这个参数在 MySQL 5.6.3 及以上版本中引入,用来替代之前的 innodb_flush_log_at_trx_commit 和 sync_binlog 参数。
innodb_flush_method 参数可以设置为以下值:
fdatasync(默认值):使用 fsync() 来刷新数据和日志文件到磁盘,但使用 O_DSYNC 打开和写入文件。
O_DIRECT:使用 O_DIRECT 标志打开并写入文件,避免双缓冲区(double buffering),但不会对日志文件使用 fsync()。
O_DSYNC:使用 O_DSYNC 标志打开并写入文件,同时使用 fsync() 刷新日志文件到磁盘。
os_sync 并不是一个 InnoDB 参数,它可能是指操作系统级别的同步设置。在 Linux 系统中,os_sync 可能指的是文件系统的同步设置,如 sync 命令或 fsync 系统调用。
如果提到 os_sync 是指控制数据库操作同步到磁盘的行为,那么它可能与 innodb_flush_method 参数有关。但是,这个参数在 MySQL 中并没有明确对应的设置。
如果你想要控制数据库操作同步到磁盘的行为,你应该调整 innodb_flush_method 的设置,或者在操作系统层面调整相关设置,如调整 fsync 的使用频率。
异步处理
当系统加载一个文件到内存后,如果该文件没有被改动过,则在内存区段的文件数据会被标记为clean
,如果是被改动了,则会标记为dirty
。
此时所有的文件操作还是在内存中进行,并没有写入到磁盘中。系统会不定时的将内存中设置为dirty
的数据写回到磁盘,以保持磁盘与内存数据的一致性。这个过程是异步的。你也可以sync
命令,将内存中的数强制写回到硬盘。
另外,要注意的是,在正常关机的情况下,关机命令会主动调用sync来将内存中的数据写入到磁盘内,但是如果非正常关机(如断电、死机),由于数据没有来得及写入到磁盘,因此重新启动可能会花费很长的时间进行磁盘检验,甚至可能导致文件系统的损毁(非磁盘损坏)。
在Linux操作系统中,优化文件存取操作可以通过以下方法实现:
-
使用
mmap
替代普通的文件读取方式。mmap
可以将文件内容映射到内存中,之后的读取可以直接从内存中进行,避免了频繁的系统调用。 -
使用
sendfile
系统调用来传输文件数据。sendfile
可以直接在内核空间之间传输数据,避免了用户态和内核态之间的数据拷贝,提高了效率。 -
使用
O_DIRECT
标志打开文件,这样可以跳过文件系统缓存,直接进行磁盘I/O操作。 -
使用
O_SYNC
标志打开文件,确保每次写入操作都会同步到磁盘中。 -
使用
fsync
系统调用来强制将缓冲区的数据写入磁盘。 -
使用
posix_fadvise
来给操作系统提示文件访问模式,帮助操作系统优化缓存策略。
总的来说,文件系统进行性能调优,来获得更高的I/O性能提升,主要可以从三个方面来做工作:
1、Disk相关参数调优
2、文件系统本身参数调优
3、文件系统挂载(mount)参数调优
这里就不再展开了,后面再详细描述。
科普文:Linux服务器磁盘的 I/O 性能优化思路_fio slat clat-CSDN博客
科普文:软件架构Linux系列之【零拷贝-zero copy】-CSDN博客