ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# Linux虚拟文件系统 虚拟文件系统 VFS,使得Linux“一切皆文件”的哲学得以实现。虚拟文件系统位于顶层应用软件和底层具体IO设备的中间一层。 :-: ![](https://img.kancloud.cn/2b/75/2b75c5b1d7efcab5d887ef1e1cc444ec_991x562.png) 虚拟文件系统是抽象的一层,对用户提供了统一的访问不同文件系统的接口。其使用面向对象的方式抽象出了四种类型的数据结构: * 超级块对象:代表一个已安装的文件系统,该文件系统才会真正的和IO设备交互。 * 索引节点对象 inode:代表具体的文件。其结构可如下 :-: ![](https://img.kancloud.cn/9d/97/9d97f06d0fd32d63a0df5fd5194ec242_824x799.png) * 目录项对象 :代表一个目录项,是文件路径的一个组成部分。存在内存中。 * 文件对象FD:表示进程打开的一个文件,**也称文件描述符**,每个进程的文件描述符相互独立。当两个进程打开同一个文件的时候,文件描述符会维护独立的指针(seek)。 其中文件描述符、文件句柄、inode之间的关系如下: :-: ![](https://img.kancloud.cn/05/6e/056e7afd20d9f052bf53a7573a1fa3cb_758x499.png) 目录项、inode之间的关系(inode和超级快都在磁盘中 ): :-: ![](https://img.kancloud.cn/95/ab/95ab910ee917765bf7c192cc923c52aa_942x669.png)   **Linux系统分区** ~~~bash df -h ~~~ ~~~ 分区 大小 使用 可用 使用百分比 挂载目录 udev 1.9G 0 1.9G 0% /dev tmpfs 376M 4.7M 372M 2% /run /dev/vda1 79G 6.4G 69G 9% / tmpfs 1.9G 7.7M 1.9G 1% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup tmpfs 376M 0 376M 0% /run/user/0 ~~~ 具体的IO设备在进行挂载的时候会先挂载root目录,接着才会挂载其他的目录。与挂载相关的操作如下: ~~~ umount 分区 # 取消该分区与该目录的挂载 mount 分区 目录 # 将该分区与该目录进行挂载 ~~~   **文件类型** Linux将系统中的一切都抽象成文件,可以具体区分出多种不同类型的文件。 :-: ![](https://img.kancloud.cn/d9/7a/d97af3e441f7d8a2d19ec76ce5730f3c_852x337.png) 使用`ll`命令第一个字段的第一列可以查看文件的类型: -:表示普通文件。 d:表示目录。 b:表示块设备,例如硬盘,可以移动字节位置。 c:表示字符设备,例如键盘。 s:表示socket。 p:表示pipeline,管道。 l:链接,可以分为软硬链接,上图的数字就表示被硬链接引用的次数。 使用命令 ~~~ stat 文件名 ~~~ 可以查看文件的元数据信息 :-: ![](https://img.kancloud.cn/d7/f7/d7f7920ee62b11dc92310b890e702de9_982x238.png)   Linux系统有个/proc目录,里面存放着打开进程的信息,每个数字文件夹标识着一个进程pid号。Linux也将进程也映射成一个文件,同时在任何的进程中都有文件描述符为: - 0:标准输入。 - 1:标准输出。 - 2:报错输出。 采用如下命令可以查看一个进程打开的文件 ~~~ lsof -p pid ~~~ 输出结果的一部分如下: ~~~ bash 162968 root 0u CHR 136,0 0t0 3 /dev/pts/0 bash 162968 root 1u CHR 136,0 0t0 3 /dev/pts/0 bash 162968 root 2u CHR 136,0 0t0 3 /dev/pts/0 ~~~ 例如使用如下命令可以用标准输入将内容输入到文件中 ~~~ ls ./ 1> ls.out ~~~ 可以将当前的ls命令的输出内容输出到ls.out文件中。 又例如在运行jar包的时候 ~~~ nohup java -jar *.jar >server.log 2>&1 ~~~ 即表示将输出重定向到server.log文件中,同时将报错输出重定向到标准输出文件描述符1中。这样报错输出也会输出到server.log中。   **管道** 管道就是在命令行中用符号【|】表示,例如: ~~~ ps -ef | grep java ~~~ 表示将左边的命令的输出作为右边命令的输入。 管道是进程间通信的一种方式,并且是单向通信的。可以分为**匿名管道**和**命名管道**,上面的 “|” 就是匿名管道,命令管道可以使用命令`mkfifo`创建。 ~~~ [root@iZwz9243apyfnh4y2y36scZ test]# mkfifo mypipe [root@iZwz9243apyfnh4y2y36scZ test]# ll total 0 prw-r--r-- 1 root root 0 Feb 24 21:11 mypipe ~~~ p就是表示命名管道类型的文件。 往命令管道存入的数据之后被读出之后程序才会退出,不然会一直阻塞住。注意**管道就是内核中的一串缓存数据**。 原理: 当我们在shell使用匿名管道时,会fork两个子进程,其父进程是shell这个客户端,并复制命令的文件文件描述符,这样文件描述符就可以通过管道进行数据交互了。 其他: 【$$】和【$BASHPID】都能表示当前进程的PID号,但是$$的优先级要比管道符号的要高。   ## pageCache 磁盘高速缓存,pageCache是内核的内存空间中对磁盘读写数据的一块缓存空间,系统内核对磁盘数据的读写会先经过pageCache,然后再从pageCache中复制到用户空间中(直接io的方式不用使用pageCache)。使用pageCache有如下的特点: 1. 跟计算机中大多数的缓存层的作用类似,符合“程序的局部性原理”,可以减少对磁盘的访问。 2. 当pageCache中的数据被修改过后,需要设置成脏页标志,操作系统会根据一定的策略将脏页的数据写回到磁盘中。但是并不一定会立刻写出,所以可能造成数据丢失不能持久化的问题。 3. 当pageCache满的时候会通过LRU算法将某些页写回磁盘。 4. 具备**预读**的功能,能够在一次磁盘读取数据的时候,额外的读取更多的数据(受局部性原理的指导)。 图示pageCache的位置: :-: ![](https://img.kancloud.cn/c0/af/c0afe3dbf71cb967ad398f32641522bd_954x598.png) 现在都是由DMA将磁盘中的数据放到pageCache中 :-: ![](https://img.kancloud.cn/1c/4e/1c4ef7fa46b625f9e44eeb2dabc66097_904x595.png)   **查看系统脏页大小** 1. 查看系统配置 ~~~ sysctl -a | grep dirty ~~~ :-: ![](https://img.kancloud.cn/4e/26/4e26d740e88b45a3051eabd660e4f938_622x171.png) 其中: * vm.dirty_background_ratio:是内存可以填充脏数据的百分比。超过这个比例,这些脏数据稍后会写入磁盘,由后台进程执行,不会阻塞。比如,我有32G内存,那么有3.2G的脏数据可以待着内存里,超过3.2G的话就会有后台进程来清理。 * vm.dirty_ratio:是可以用脏数据填充的绝对最大系统内存量,当系统到达此点时,必须将所有脏数据提交到磁盘,同时所有新的`I/O`块都会被阻塞,直到脏数据被写入磁盘。这通常是长`I/O`卡顿的原因,但这也是保证内存中不会存在过量脏数据的保护机制。 * `vm.dirty_background_bytes`和`vm.dirty_bytes`是另一种指定这些参数的方法。如果设置`_bytes`版本,则`_ratio`版本将变为0,反之亦然。 * vm.dirty_expire_centisecs:指定脏数据能存活的时间。在这里它的值是30秒。当后台进程在运行的时候,他们会检查是否有数据超过这个时限,如果有则会把它异步地写到磁盘中。 * vm.dirty_writeback_centisecs:指定多长时间后台进程会唤醒一次,然后检查是否有缓存需要清理。 **修改系统配置** ~~~ vim /etc/sysctl.conf ~~~ 重新生效 ~~~ sysctl -p ~~~ 2. 查看脏页数据: ~~~ cat /proc/vmstat | egrep "dirty|writeback" ~~~ 或者使用`pcstat`查看, ### 安装pcstat 1. 如果没有go环境需要先安装golang环境 官网下载安装包:[Downloads - The Go Programming Language](https://go.dev/dl/),解压 ~~~ tar -zxvf goxxx.tar.gz ~~~ 2. 添加环境变量 ~~~ vim /etc/profile ~~~ ~~~ export GO_HOME=go的解压地址/go export PATH=$PATH:$GO_HOME/bin # 国内 export GOPROXY=https://goproxy.io export GO111MODULE=on ~~~ ~~~ source /etc/profile ~~~ 3. 安装pcstat 官方地址:[tobert/pcsta(github.com)](https://github.com/tobert/pcstat),阅读一下Readmd.md安装即可。 4. 使用 注意`pcstat`命令需要放于环境变量中,这里我放到了go的bin目录下。 :-: ![](https://img.kancloud.cn/fb/d7/fbd722fcebb2b8d941840b119806e4d5_711x129.png)