Linux下文件删除的原理

linux下文件删除的原理:

Linux 是通过 Link 的数量来控制文件删除的,只有当一个文件不存在任何 link 的时候,这个文件才会被删除。 

一般来说,每个文件都有2个link计数器:

  • i_count
    • 进程的引用计数
  • i_link 
    • 硬链接数量

i_count的意义是当前文件使用者(或被调用)的数量; 

i_link 的意义是介质连接的数量。

 

当一个文件被某一个进程引用时,对应i_count数就会增加;
当创建文件的硬链接的时候,对应i_link数就会增加。 

 

对于删除命令rm而言,实际就是减少磁盘引用计数i_link。
这里就会有一个问题,如果一个文件正在被某个进程调用,而用户却执行rm操作把文件删除了,那么会出现什么结果呢?
当用户执行rm操作删除文件后,再执行ls或者其他文件管理命令,无法再找到这个文件了,但是调用这个删除的文件的进程却在继续正常执行,依然能够从文件中正确的读取及写入内容。这又是为什么呢?

这是因为rm操作只是将文件的i_link减少了,如果没其它的链接i_link就为0了;但由于该文件依然被进程引用,因此,此时文件对应的i_count并不为0,所以即使执行rm操作,但系统并没有真正删除这个文件,当只有i_link及i_count都为0的时候,这个文件才会真正被删除。也就是说,还需要解除该进程的对该文件的调用才行。

以上讲的i_link及i_count是文件删除的真实条件,但是当文件没有被调用时,执行了rm操作删除文件后是否还可以找回被删的文件呢?

前面说了,rm操作只是将文件的i_link减少了,或者说置0了,实际就是将文件名到inode的链接删除了,此时,并没有删除文件的实体即(block数据块),此时,如果及时停止机器工作,数据是可以找回的,如果此时继续写入数据,那么当新数据就可能会被分配到被删除的数据的block数据块,此时,文件就会被真正的回收了,那时就是神仙也没有办法了。


文件删除生产场景案例解决实战 

  1. Web服务器磁盘满故障深入解析 https://blog.51cto.com/oldboy/612351
  2. 磁盘满的故障(inode满了)
 

案例实战环境模拟:

1. 安装 httpd web 服务

# 安装 httpd
yum install httpd -y

# 开启服务
[root@oldboy test]# /etc/init.d/httpd start
Starting httpd: httpd: apr_sockaddr_info_get() failed for oldboy
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
                                                           [  OK  ]

# 查看80端口,表示服务已经运行
[root@oldboy test]# lsof -i :80
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   4801   root    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4803 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4804 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4805 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4806 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4807 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4808 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4809 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)
httpd   4810 apache    4u  IPv6  39743      0t0  TCP *:http (LISTEN)

# 编辑配置文件,让日志记录到/app/log 下面
cd /etc/hpptd/conf 
vi /etc/httpd/conf # 查看CustomLog logs/access_log common 的参数在哪一行,退出来用sed命令替换。

# 先grep过滤确认替换的文本值是否唯一
[root@oldboy conf]# grep "CustomLog logs/access_log common" httpd.conf 
#CustomLog logs/access_log common

# 将日志路径从logs/access_log替换成/app/logs/access_log
# 注意,因为要将‘#’除掉,所以sed命令替换的分隔符换成了 ‘@’
[root@oldboy conf]# sed -i 's@#CustomLog logs/access_log common@CustomLog /app/logs/access_log common@g' httpd.conf 
[root@oldboy conf]# grep "CustomLog logs/access_log common" httpd.conf 

# 确认替换结果
[root@oldboy conf]# grep "CustomLog /app/logs/access_log common" httpd.conf  
CustomLog /app/logs/access_log common

关闭防火墙:

[root@oldboy test]# /etc/init.d/iptables stop
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Unloading modules:                               [  OK  ]

2. 创建一个小的文件系统,用于存放上述日志

# bs是块大小,count是块数量
[root@oldboy conf]# dd if=/dev/zero of=/dev/sdc bs=8K count=10
10+0 records in
10+0 records out
81920 bytes (82 kB) copied, 0.000283861 s, 289 MB/s


[root@oldboy conf]# ls -l /dev/sdc
-rw-r--r-- 1 root root 81920 Sep  5 23:58 /dev/sdc

# 格式化创建文件系统
[root@oldboy conf]# mkfs -t ext3 /dev/sdc          
mke2fs 1.41.12 (17-May-2010)
/dev/sdc is not a block special device.
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
Stride=0 blocks, Stripe width=0 blocks
16 inodes, 80 blocks
4 blocks (5.00%) reserved for the super user
First data block=1
1 block group
8192 blocks per group, 8192 fragments per group
16 inodes per group

Writing inode tables: done                            

Filesystem too small for a journal
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 22 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

# 取消180天的检查(可做可不做)
[root@oldboy conf]# tune2fs -c -1 /dev/sdc         
tune2fs 1.41.12 (17-May-2010)
Setting maximal mount count to -1


# 设置挂载点和存放日志的目录
[root@oldboy conf]# mkdir /app/logs -p
[root@oldboy conf]# mount -o loop /dev/sdc /app/logs

# 查看是否挂载成功
[root@oldboy conf]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3       6.9G  1.5G  5.1G  23% /
tmpfs           499M     0  499M   0% /dev/shm
/dev/sda1       190M   36M  145M  20% /boot
/dev/sdc         73K   14K   55K  21% /app/logs

成功模拟了一个73K的小磁盘。

 

3. 重启httpd服务,确保日志记录到了上述文件系统挂载的/app/log下面

[root@oldboy conf]# /etc/init.d/httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd: httpd: apr_sockaddr_info_get() failed for oldboy
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
                                                           [  OK  ]

访问localhost或127.0.0.1或Linux的ip地址,可以访问网站,然后/app/logs/access_log中会生成日志文件。

 

另起一个会话查看访问的动态:tail -f /app/logs/access_log 

 
为了快速塞满日志文件,循环访问:
[root@oldboy conf]# echo oldboy >/var/www/html/index.html

[root@oldboy conf]# for n in `seq 100`
> do 
>     curl 127.0.0.1
> done

查看硬盘使用情况,发现日志盘已经满了:

[root@oldboy conf]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3       6.9G  1.5G  5.1G  23% /
tmpfs           499M     0  499M   0% /dev/shm
/dev/sda1       190M   36M  145M  20% /boot
/dev/sdc         73K   73K     0 100% /app/logs

删除日志文件,查看硬盘空间,发现硬盘还是满的。

[root@oldboy conf]# rm /app/logs/access_log
rm: remove regular file `/app/logs/access_log'? y
[root@oldboy conf]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3       6.9G  1.5G  5.1G  23% /
tmpfs           499M     0  499M   0% /dev/shm
/dev/sda1       190M   36M  145M  20% /boot
/dev/sdc         73K   73K     0 100% /app/logs

查看被删除的但仍由进程占用的文件名:

[root@oldboy conf]# lsof |grep del
rdisc     3212      root    0u      CHR              136,0      0t0          3 /dev/pts/0 (deleted)
httpd     4957      root    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4959    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4960    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4961    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4962    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4963    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4964    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4965    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
httpd     4966    apache    7w      REG                7,0    59356         12 /app/logs/access_log (deleted)
tail      8895      root    3r      REG                7,0    59356         12 /app/logs/access_log (deleted)
[root@oldboy conf]# 

4. 重启httpd 服务 

/etc/init.d/httpd restart

 

注意确保没有进程占用文件,我删除并重启服务后,由于tail -f /app/logs/access_log也在占用该文件,导致一直没有释放,结束命令后即可。

 

5. 较好的解决方案

清空日志而不删除日志。

/app/logs/access_log

 
 
原文地址:https://www.cnblogs.com/zoe233/p/11919778.html