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. 安装 httpd web 服务
#安装 httpd
yum install httpd -y#开启服务
[root@oldboy test]#/etc/init.d/httpd start
Starting httpd: httpd: apr_sockaddr_info_get() failed foroldboy
httpd: Could not reliably determine the server's fully qualified domain name, using127.0.0.1 forServerName
[ OK ]#查看80端口,表示服务已经运行
[root@oldboy test]#lsof -i :80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
httpd4801 root 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4803 apache 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4804 apache 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4805 apache 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4806 apache 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4807 apache 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4808 apache 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4809 apache 4u IPv6 39743 0t0 TCP *:http (LISTEN)
httpd4810 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+0records out81920 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=0blocks16 inodes, 80blocks4 blocks (5.00%) reserved forthe super user
First data block=1
1block group8192 blocks per group, 8192fragments per group16inodes per group
Writing inode tables: done
Filesystem too smallfora journal
Writing superblocks and filesystem accounting information: done
This filesystem will be automatically checked every22mounts or180 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 499M0 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() failedforoldboy
httpd: Could not reliably determine the server's fully qualified domain name, using127.0.0.1 forServerName
[ 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 499M0 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 499M0 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)
httpd4957 root 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4959 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4960 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4961 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4962 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4963 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4964 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4965 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
httpd4966 apache 7w REG 7,0 59356 12 /app/logs/access_log (deleted)
tail8895 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