🚙

💨 💨 💨

×

  • Categories

  • Archives

  • Tags

  • About

服务器开发自我修养专栏-Linux文件系统

Posted on 11-06-2020 | In Self-cultivation

Linux文件系统

详细的可以查看本博客的这篇文章哈文件描述符FD与Inode
fd数目大小的限制可以改变, 参考 文件描述符限制

系统目录结构

Linux 系统目录结构 登录系统后,在当前命令窗口下输入命令: ls / 你会看到如下图所示: 树状目录结构: 以下是对这些目录的解释: /bin: bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。

以下是对这些目录的解释:

  • /bin:
    bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。
  • /boot:
    这里存放的是启动 Linux 时使用的一些核心文件,包括一些连接文件以及镜像文件。
  • /dev :
    dev 是 Device(设备) 的缩写, 该目录下存放的是 Linux 的外部设备,在 Linux 中访问设备的方式和访问文件的方式是相同的。
  • /etc:
    etc 是 Etcetera(等等) 的缩写, 这个目录用来存放所有的系统管理所需要的配置文件和子目录。
  • /home:
    用户的主目录,在 Linux 中,每个用户都有一个自己的目录,一般该目录名是以用户的账号命名的,如上图中的 alice、bob 和 eve。
  • /lib:
    lib 是 Library(库) 的缩写这个目录里存放着系统最基本的动态连接共享库,其作用类似于 Windows 里的 DLL 文件。几乎所有的应用程序都需要用到这些共享库。
  • /lost+found:
    这个目录一般情况下是空的,当系统非法关机后,这里就存放了一些文件。
  • /media:
    linux 系统会自动识别一些设备,例如 U 盘、光驱等等,当识别后,Linux 会把识别的设备挂载到这个目录下。
  • /mnt:
    系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将光驱挂载在 /mnt/ 上,然后进入该目录就可以查看光驱里的内容了。
  • /opt:
    opt 是 optional(可选) 的缩写,这是给主机额外安装软件所摆放的目录。比如你安装一个 ORACLE 数据库则就可以放到这个目录下。默认是空的。
  • /proc:
    proc 是 Processes(进程) 的缩写,/proc 是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息。
    这个目录的内容不在硬盘上而是在内存里,我们也可以直接修改里面的某些文件,比如可以通过下面的命令来屏蔽主机的 ping 命令,使别人无法 ping 你的机器:

    echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
  • /root:
    该目录为系统管理员,也称作超级权限者的用户主目录。

  • /sbin:
    s 就是 Super User 的意思,是 Superuser Binaries (超级用户的二进制文件) 的缩写,这里存放的是系统管理员使用的系统管理程序。
  • /selinux:
    这个目录是 Redhat/CentOS 所特有的目录,Selinux 是一个安全机制,类似于 windows 的防火墙,但是这套机制比较复杂,这个目录就是存放 selinux 相关的文件的。
  • /srv:
    该目录存放一些服务启动之后需要提取的数据。
  • /sys:
    这是 Linux2.6 内核的一个很大的变化。该目录下安装了 2.6 内核中新出现的一个文件系统 sysfs 。
    sysfs 文件系统集成了下面 3 种文件系统的信息:针对进程信息的 proc 文件系统、针对设备的 devfs 文件系统以及针对伪终端的 devpts 文件系统。
    该文件系统是内核设备树的一个直观反映。
    当一个内核对象被创建的时候,对应的文件和目录也在内核对象子系统中被创建。
  • /tmp:
    tmp 是 temporary(临时) 的缩写这个目录是用来存放一些临时文件的。
  • /usr:
    usr 是 unix shared resources(共享资源) 的缩写,这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于 windows 下的 program files 目录。
  • /usr/bin:
    系统用户使用的应用程序。
  • /usr/sbin:
    超级用户使用的比较高级的管理程序和系统守护程序。
  • /usr/src:
    内核源代码默认的放置目录。
  • /var:
    var 是 variable(变量) 的缩写,这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件。
  • /run:
    是一个临时文件系统,存储系统启动以来的信息。当系统重启时,这个目录下的文件应该被删掉或清除。如果你的系统上有 /var/run 目录,应该让它指向 run。

在 Linux 系统中,有几个目录是比较重要的,平时需要注意不要误删除或者随意更改内部文件。
/etc: 上边也提到了,这个是系统中的配置文件,如果你更改了该目录下的某个文件可能会导致系统不能启动。
/bin, /sbin, /usr/bin, /usr/sbin: 这是系统预设的执行文件的放置目录,比如 ls 就是在 /bin/ls 目录下的。
值得提出的是,/bin, /usr/bin 是给系统用户使用的指令(除 root 外的通用户),而 / sbin, /usr/sbin 则是给 root 使用的指令。
/var: 这是一个非常重要的目录,系统上跑了很多程序,那么每个程序都会有相应的日志产生,而这些日志就被记录到这个目录下,具体在 /var/log 目录下,另外 mail 的预设放置也是在这里。

inode

硬盘的最小存储单位是扇区(Sector),块(block)由多个扇区组成。文件数据存储在块中。块的最常见的大小是 4kb,约为 8 个连续的扇区组成(每个扇区存储 512 字节)。一个文件可能会占用多个 block,但是一个块只能存放一个文件。

虽然,我们将文件存储在了块(block)中,但是我们还需要一个空间来存储文件的 元信息 metadata :如某个文件被分成几块、每一块在的地址、文件拥有者,创建时间,权限,大小等。这种 存储文件元信息的区域就叫 inode,译为索引节点:i(index)+node。 每个文件都有一个 inode,存储文件的元信息。

可以使用 stat 命令可以查看文件的 inode 信息。每个 inode 都有一个号码,Linux/Unix 操作系统不使用文件名来区分文件,而是使用 inode 号码区分不同的文件。

简单来说:inode 就是用来维护某个文件被分成几块、每一块在的地址、文件拥有者,创建时间,权限,大小等信息。
简单总结一下:

  • inode :记录文件的属性信息,可以使用 stat 命令查看 inode 信息。
  • block :实际文件的内容,如果一个文件大于一个块时候,那么将占用多个 block,但是一个块只能存放一个文件。(因为数据是由 inode 指向的,如果有两个文件的数据存放在同一个块中,就会乱套了)

软链接与硬链接

详细的可参考: https://blog.csdn.net/yangxjsun/article/details/79681229

硬链接

普通链接一般就是指硬链接, 硬链接是新的目录条目,其引用系统中的现有文件。文件系统中的每一文件默认具有一个硬链接。为节省空间,可以不复制文件,而创建引用同一文件的新硬链接。新硬链接如果在与现有硬链接相同的目录中创建,则需要有不同的文件名,否则需要在不同的目录中。指向同一文件的所有硬链接具有相同的权限、连接数、用户/组所有权、时间戳以及文件内容。指向同一文件内容的硬链接需要在相同的文件系统中。
简单说,硬链接就是一个 inode 号对应多个文件名。就是同一个文件使用了多个别名(上图中 hard link 就是 file 的一个别名,他们有共同的 inode)。

由于硬链接是有着相同 inode 号仅文件名不同的文件,因此硬链接存在以下几点特性:

  • 文件有相同的 inode 及 data block;
  • 只能对已存在的文件进行创建;
  • 不能交叉文件系统进行硬链接的创建;
  • 不能对目录进行创建,只可对文件创建;
  • 删除一个硬链接文件并不影响其他有相同 inode 号的文件, 只是相应的链接计数器(link count)减1

软链接

(又称符号链接,即 soft link 或 symbolic link) 软链接与硬链接不同,若文件用户数据块中存放的内容是另一文件的路径名的指向,则该文件就是软连接。软链接就是一个普通文件,只是数据块内容有点特殊。软链接有着自己的 inode 号以及用户数据块。(见图2)软连接可以指向目录,而且软连接所指向的目录可以位于不同的文件系统中。

软链接特性:

  • 软链接有自己的文件属性及权限等;
  • 可对不存在的文件或目录创建软链接;
  • 软链接可交叉文件系统;
  • 软链接可对文件或目录创建;
  • 创建软链接时,链接计数 i_nlink 不会增加;
  • 删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接被称为死链接或悬挂的软链接(即 dangling link,若被指向路径文件被重新创建,死链接可恢复为正常的软链接)。

Linux 为什么多进程能够读写正在删除的文件

参考进程表_文件表_inode_vnode

Linux中多进程环境下,打开同一个文件,当一个进程进行读写操作,如果另外一个进程删除了这个文件,那么读写该文件的进程会发生什么呢?

  • 因为文件被删除了,读写进程发生异常?
  • 正在读写的进程仍然正常读写,好像没有发生什么?

学操作系统原理的时候,我们知道,linux是通过link的数量来控制文件删除,只有当一个文件不存在任何link的时候,这个文件才会被删除。

而每个文件都会有2个link计数器:

  • i_count: i_count的意义是当前使用者的数量,也就是打开文件进程的个数。
  • i_nlink: i_nlink的意义是介质连接的数量.

或者可以理解为 i_count是内存引用计数器,i_nlink是硬盘引用计数器。再换句话说,当文件被某个进程引用时,i_count 就会增加;当创建文件的硬连接的时候,i_nlink 就会增加。

对于 rm 而言,就是减少 i_nlink。这里就出现一个问题,如果一个文件正在被某个进程调用,而用户却执行 rm 操作把文件删除了,会出现什么结果呢?

当用户执行 rm 操作后,ls 或者其他文件管理命令不再能够找到这个文件,但是进程却依然在继续正常执行,依然能够从文件中正确的读取内容。这是因为,rm 操作只是将 i_nlink 置为 0 了;由于文件被进程引用的缘故,i_count 不为 0,所以系统没有真正删除这个文件。i_nlink 是文件删除的充分条件,而 i_count 才是文件删除的必要条件。

基于以上只是,大家猜一下,如果在一个进程在打开文件写日志的时候,手动或者另外一个进程将这个日志删除,会发生什么情况?

是的,数据库并没有停掉。虽然日志文件被删除了,但是有一个进程已经打开了那个文件,所以向那个文件中的写操作仍然会成功,数据仍然会提交。

文件操作偏移lseek

lseek的函数用于设置文件偏移量。

每个打开的文件都有一个与其相关联的“当前文件偏移量”(当前文件偏移量)。它通常是一个非负整数,用以度量从文件开始处计算的字节数。通常,读写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。按系统默认的情况,当打开一个文件时,除非制定O_APPEND选项,否则该偏移量被设置为0。

文件空洞

我们知道lseek()系统调用可以改变文件的偏移量,但如果程序调用使得文件偏移量跨越了文件结尾,然后再执行I/O操作,将会发生什么情况? read()调用将会返回0,表示文件结尾。令人惊讶的是,write()函数可以在文件结尾后的任意位置写入数据。在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。从原来的文件结尾到新写入数据间的这段空间被成为文件空洞。调用write后文件结尾的位置已经发生变化。

文件空洞不占用任何磁盘空间,直到后续某个时点,在文件空洞中写入了数据,文件系统才会为之分配磁盘块。空洞的存在意味着一个文件名义上的大小可能要比其占用的磁盘存储总量要大(有时大出许多)。向文件空洞中写入字节,内核需要为其分配存储单元,即使文件大小不变,系统的可用磁盘空间也将减少。这种情况并不常见,但也需要了解。

实际中的空洞文件会在哪里用到呢?常见的场景有:

  • 一是在下载电影的时候,发现刚开始下载,文件的大小就已经到几百M了.
  • 二是在创建虚拟机的磁盘镜像的时候,你创建了一个100G的磁盘镜像,但是其实装起来系统之后,开始也不过只占用了3,4G的磁盘空间,如果一开始把100G都分配出去的话,无疑是很大的浪费.
  • 空洞文件方法对多线程共同操作文件是及其有用的。有时候我们创建一个很大的文件(比如视频文件),如果从头开始依次构建时间很长。有一种思路就是将文件分为多段,然后多线程来操作每个线程负责其中一段的写入。(就像修100公里的高速公路,分成20个段来修,每个段就只负责5公里,就可以大大提高效率)。

习题

Linux下两个进程可以同时打开同一个文件,这时如下描述错误的是(答案是4):

  1. 两个进程中分别产生生成两个独立的fd
  2. 两个进程可以任意对文件进行读写操作,操作系统并不保证写的原子性
  3. 进程可以通过系统调用对文件加锁,从而实现对文件内容的保护
  4. 任何一个进程删除该文件时,另外一个进程会立即出现读写失败
  5. 两个进程可以分别读取文件的不同部分而不会相互影响
  6. 一个进程对文件长度和内容的修改另外一个进程可以立即感知

proc文件夹

参考: https://www.cnblogs.com/liushui-sky/p/9354536.html

下面是作者系统(RHEL5.3)上运行的一个PID为2674的进程saslauthd的相关文件,其中有些文件是每个进程都会具有的,后文会对这些常见文件做出说明。

[root@rhel5 ~]# ll /proc/2674
total 0
dr-xr-xr-x 2 root root 0 Feb 8 17:15 attr
-r-------- 1 root root 0 Feb 8 17:14 auxv
-r--r--r-- 1 root root 0 Feb 8 17:09 cmdline
-rw-r--r-- 1 root root 0 Feb 8 17:14 coredump_filter
-r--r--r-- 1 root root 0 Feb 8 17:14 cpuset
lrwxrwxrwx 1 root root 0 Feb 8 17:14 cwd -> /var/run/saslauthd
-r-------- 1 root root 0 Feb 8 17:14 environ
lrwxrwxrwx 1 root root 0 Feb 8 17:09 exe -> /usr/sbin/saslauthd
dr-x------ 2 root root 0 Feb 8 17:15 fd
-r-------- 1 root root 0 Feb 8 17:14 limits
-rw-r--r-- 1 root root 0 Feb 8 17:14 loginuid
-r--r--r-- 1 root root 0 Feb 8 17:14 maps
-rw------- 1 root root 0 Feb 8 17:14 mem
-r--r--r-- 1 root root 0 Feb 8 17:14 mounts
-r-------- 1 root root 0 Feb 8 17:14 mountstats
-rw-r--r-- 1 root root 0 Feb 8 17:14 oom_adj
-r--r--r-- 1 root root 0 Feb 8 17:14 oom_score
lrwxrwxrwx 1 root root 0 Feb 8 17:14 root -> /
-r--r--r-- 1 root root 0 Feb 8 17:14 schedstat
-r-------- 1 root root 0 Feb 8 17:14 smaps
-r--r--r-- 1 root root 0 Feb 8 17:09 stat
-r--r--r-- 1 root root 0 Feb 8 17:14 statm
-r--r--r-- 1 root root 0 Feb 8 17:10 status
dr-xr-xr-x 3 root root 0 Feb 8 17:15 task
-r--r--r-- 1 root root 0 Feb 8 17:14 wchan

  • cmdline — 启动当前进程的完整命令,但僵尸进程目录中的此文件不包含任何信息;

    [root@rhel5 ~]# more /proc/2674/cmdline 
    /usr/sbin/saslauthd
  • cwd — 指向当前进程运行目录的一个符号链接;

  • environ — 当前进程的环境变量列表,彼此间用空字符(NULL)隔开;变量用大写字母表示,其值用小写字母表示;

    [root@rhel5 ~]# more /proc/2674/environ 
    TERM=linuxauthd
  • exe — 指向启动当前进程的可执行文件(完整路径)的符号链接,通过/proc/N/exe可以启动当前进程的一个拷贝;

  • fd — 这是个目录,包含当前进程打开的每一个文件的文件描述符(file descriptor),这些文件描述符是指向实际文件的一个符号链接;

    [root@rhel5 ~]# ll /proc/2674/fd
    total 0
    lrwx------ 1 root root 64 Feb 8 17:17 0 -> /dev/null
    lrwx------ 1 root root 64 Feb 8 17:17 1 -> /dev/null
    lrwx------ 1 root root 64 Feb 8 17:17 2 -> /dev/null
    lrwx------ 1 root root 64 Feb 8 17:17 3 -> socket:[7990]
    lrwx------ 1 root root 64 Feb 8 17:17 4 -> /var/run/saslauthd/saslauthd.pid
    lrwx------ 1 root root 64 Feb 8 17:17 5 -> socket:[7991]
    lrwx------ 1 root root 64 Feb 8 17:17 6 -> /var/run/saslauthd/mux.accept
  • limits — 当前进程所使用的每一个受限资源的软限制、硬限制和管理单元;此文件仅可由实际启动当前进程的UID用户读取;(2.6.24以后的内核版本支持此功能);

  • maps — 当前进程关联到的每个可执行文件和库文件在内存中的映射区域及其访问权限所组成的列表;

    [root@rhel5 ~]# cat /proc/2674/maps 
    00110000-00239000 r-xp 00000000 08:02 130647 /lib/libcrypto.so.0.9.8e
    00239000-0024c000 rwxp 00129000 08:02 130647 /lib/libcrypto.so.0.9.8e
    0024c000-00250000 rwxp 0024c000 00:00 0
    00250000-00252000 r-xp 00000000 08:02 130462 /lib/libdl-2.5.so
    00252000-00253000 r-xp 00001000 08:02 130462 /lib/libdl-2.5.so
  • mem — 当前进程所占用的内存空间,由open、read和lseek等系统调用使用,不能被用户读取;

  • root — 指向当前进程运行根目录的符号链接;在Unix和Linux系统上,通常采用chroot命令使每个进程运行于独立的根目录;

  • stat — 当前进程的状态信息,包含一系统格式化后的数据列,可读性差,通常由ps命令使用;

  • statm — 当前进程占用内存的状态信息,通常以“页面”(page)表示;

  • status — 与stat所提供信息类似,但可读性较好,如下所示,每行表示一个属性信息;其详细介绍请参见 proc的man手册页;

    [root@rhel5 ~]# more /proc/2674/status 
    Name: saslauthd
    State: S (sleeping)
    SleepAVG: 0%
    Tgid: 2674
    Pid: 2674
    PPid: 1
    TracerPid: 0
    Uid: 0 0 0 0
    Gid: 0 0 0 0
    FDSize: 32
    Groups:
    VmPeak: 5576 kB
    VmSize: 5572 kB
    VmLck: 0 kB
    VmHWM: 696 kB
    VmRSS: 696 kB
    …………
  • task — 目录文件,包含由当前进程所运行的每一个线程的相关信息,每个线程的相关信息文件均保存在一个由线程号(tid)命名的目录中,这类似于其内容类似于每个进程目录中的内容;(内核2.6版本以后支持此功能)

muduo详解之网络编程难点解读

Posted on 09-24-2020 | In NP

时间有限, 有空待续…

. . .

Algo Tricks

Posted on 08-15-2020 | In Algo

算法白话总结

  • 参考: https://programmercarl.com/
  • 推荐参考本博客总结的 algo_newbie , 和本文对照着看

. . .

逻辑CPU与核心备忘

Posted on 07-06-2020 | In NP

. . .

python单例实现之详解元类和type和__call__和__new__和__init__

Posted on 06-17-2020 | In Misc

python的单例实现方式茫茫多, 讲道理, 其实是违背python之禅的:

There should be one– and preferably only one –obvious way to do it. 用一种方法,最好是只有一种方法来做一件事

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

. . .

Windows共享教程

Posted on 05-06-2020 | In Misc

曾在使用Win0系统进行数据交换过程中发现,网上邻居上怎么找都找不着其他电脑,为何呢?也是用了很多办法,一次次失败后最后终于解决了,原来在很多优化/安全软件“整理”过的电脑中,有他们认为危险但实际非常重要的设置被强行关闭了。接下来我们看看怎么处理。

先参考下面几张图设置一波

. . .

内省排序

Posted on 03-23-2020 | In Algo

基于比较的排序算法复杂度的理论下界为 O(nlog n),同时指出了:

每一次判定 a < b ,都相当于回答了一次「是否问题」。按照已有的知识,若要尽可能快地完成排序,就要让每一次大小判断的结果落在两种答案之一的概率接近;若不然,则这次比较带来的信息量较小,也就需要更多次的比较来完成排序。

此篇建立在这些知识的基础上,首先探讨以下三个问题,而后引出号称「在所有情况下,都能较快完成排序任务的内省式排序(Introspective Sort)」:

  1. 为什么堆排序一般快不过快速排序?
  2. 快速排序快得无懈可击吗?
  3. 插入排序什么时候快?

为什么在平均情况下快速排序比堆排序要优秀

堆排序是渐进最优的比较排序算法,达到了O(nlgn)这一下界,而快排有一定的可能性会产生最坏划分,时间复杂度可能为O(n^2),那为什么快排在实际使用中通常优于堆排序?

  • 虽然quick_sort会n^2(其实有稳定的nlgn的版本),但这毕竟很少出现。heap_sort大多数情况下比较次数都多于quick_sort,尽管大家都是nlgn。那就让倒霉蛋倒霉好了,大多数情况下快才是硬道理。
  • 堆排比较的几乎都不是相邻元素,对cache极不友好,这才是很少被采用的原因。数学上的时间复杂度不代表实际运行时的情况.快排是分而治之,每次都在同一小段进行比较,最后越来约接近局部性。反观堆排,堆化过程中需要一直拿index的当前元素A和处于index*2 + 1 的子元素B比较, 两个元素距离较远。(局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。)
  • 在快排的迭代过程中,我们所处理的 [比基准大的数],[比基准小的数] 序列中,在进行两个数之间大小比较时,在该局部范围内,产生“大于”或者“小于”的可能性是一样的。这意味着每比较一次必然会产生一次有意义的比较结果,会缩减接下来迭代的扫描工作量。
  • 我们再来看看堆排序。在每一次进行重新堆调整的时候,我们在迭代时其实就已经知道,上一层的结点值一定是比下面大的。为了打乱堆结构把最后一个元素与顶堆互换时,此时我们也已经知道,互换后的元素是一定比下一层的数要小的。而在迭代时为了调整堆我们还是要进行一次已经知道结果的比较,这无疑是没有什么价值的,也就是产生了一次没有意义的比较,对接下来的迭代工作量并没有任何进展。

. . .

Python玩MsgPack和ProtoBuf

Posted on 03-14-2020 | In Misc

MsgPack for python3

It’s like JSON.
but fast and small.
MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. But it’s faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves.

msgpack 比 json 模块序列化速度更快,所得到的数据体积更小

It’s like JSON,but fast and small

msgpack 用起来像 json,但是却比 json 快,并且序列化以后的数据长度更小,言外之意,使用 msgpack 不仅序列化和反序列化的速度快,数据传输量也比 json 格式小,msgpack 同样支持多种语言。

. . .

12345678910111213141516171819…37
Mike

Mike

🚙 🚗 💨 💨 If you want to create a blog like this, just follow my open-source project, "hexo-theme-neo", click the GitHub button below and check it out ^_^ . It is recommended to use Chrome, Safari, or Edge to read this blog since this blog was developed on Edge (Chromium kernel version) and tested on Safari.

11 categories
289 posts
111 tags
about
GitHub Spotify
© 2013 - 2025 Mike