目前知道如下几种方式可以清空文件(假定文件名是 foo): 1 、echo>foo(>foo,:>foo) 2 、cp /dev/null(cat /dev/null)>foo 3 、dd if=/dev/null of=a 4 、truncate -s 0 a
请问哪种清理方式对磁盘的 I/O 冲击小一些?
1
ysc3839 2020-11-22 16:31:51 +08:00 via Android
个人认为是 1 和 4
|
3
xuanbg 2020-11-22 16:47:38 +08:00
重新链接一个文件,几乎没有磁盘 IO
|
4
XiLingHost 2020-11-22 18:08:08 +08:00
rm -f a && touch a
|
5
zhoudaiyu OP |
7
codehz 2020-11-22 18:37:52 +08:00 via Android 1
显然和文件系统有关系,需要根据具体情况分析
|
9
msg7086 2020-11-22 19:07:24 +08:00 via Android 1
清空文件本质上就是把文件的大小改为零。你说对这些方式调用的是同一个操作。
dd 文件默认就是先 truncate,重定向也是。 所以你就是贴了 4 个一样的东西…… |
11
laminux29 2020-11-22 19:18:33 +08:00
冲击小的正确方式应该让文件系统,根据磁盘设备的负载,来对 io 操作进行优先级划分。但是目前主流 fs 好像没这方面的 api 。
退而且求其次的方法是,监控磁盘设备的负载,负载高的时候不写入,负载低的时候再写入。 |
12
fasionchan 2020-11-22 19:26:14 +08:00
@zhoudaiyu 应该都是 flags 设置 O_TRUNC 标志的 open 系统调用,多看看操作系统底层,别被眼前的表象给骗了😁
也许可以尝试分多次 truncate,每次只截短一点,最终截到 0 |
13
zhoudaiyu OP |
14
muzuiget 2020-11-22 20:41:37 +08:00
这不是文件系统的的责任吗,本来删除文件就是仅删除文件元数据,下次写数据覆盖就是了,删除就是马上完成的事。
你要是“安全擦除”那种,你这么还是得每隔字节覆盖一次,哪种方法都一样。 |
15
walker2laok 2020-11-22 22:55:53 +08:00
echo ' ' > big_file.log
|
16
mingl0280 2020-11-23 02:29:59 +08:00 via Android
我印象里这四个最后都是调的 trunc,所以没区别(?),你可以自己创建几个文件 strace 下……
|
17
iceheart 2020-11-23 07:22:36 +08:00 via Android
unlink
|
18
ericbize 2020-11-23 08:52:15 +08:00 via iPhone
很好奇楼主使用场景
|
19
AmrtaShiva 2020-11-23 09:00:55 +08:00 via iPhone
15L 这个自己用过
|
20
vuuv 2020-11-23 09:03:25 +08:00 via Android
4 最小,1 次之。因为 1 相当于 truncate+write 空字符串,多了至少一次磁盘操作。当然内核也可能把这几次操作给合并掉,从而没有差异。
2 和 3 是一样的坑,因为没有限定源或目的的大小,会占满整个分区。 |
21
vuuv 2020-11-23 09:12:07 +08:00 via Android
另外,文件不是你单方面清空就了事了,你得有机制告诉进程重新调整已打开文件的 offset 。
不然进程会继续使用其保存的 offset 写文件。如果之前是 2G,那么外部清空后,此进程的文件依旧保持打开状态,会继续从 2G 开始写,这种被称为稀疏文件。假设写 100m,则 ls 大小 2.1G (看 offset ),du 大小 100m (数 fs block )。 更加常规的做法是 mv 原文件,然后生成新的空文件,然后(大都用 sighup )通知进程重新打开一次。从而完成文件切换。这样重新打开文件前,数据会继续写到原文件,之后只写新文件,算是无缝切换了。 |
22
openbsd 2020-11-23 09:20:07 +08:00
一般都是用 15 楼说的法子
|
23
liuhuan475 2020-11-23 09:32:35 +08:00
echo '' > xxx
|
24
sujin190 2020-11-23 09:39:10 +08:00
@zhoudaiyu #5 删除后需要等所有一打开的进程都关闭这个文件之后才会真正从磁盘删除,继续读写完全是正常的,磁盘其实并不会释放,所以如果你想说的类似日志文件写的太大了,想清空它又不想重启进程估计不行,似乎不让进程重新打开这个文件是不行的吧,否则删除新建最靠谱了
|
27
li492135501 2020-11-23 11:27:37 +08:00
在文件表里删掉
|
29
ericbize 2020-11-23 11:41:07 +08:00
只要不是像我司这种, 7x24 都是高峰的, 晚上一般都还好吧!
|
31
no1xsyzy 2020-11-23 12:21:39 +08:00 1
@vuuv
1 具体是否会 write 甚至是 shell 的具体实现。有可能 shell 的 > 重定向在长度 = 0 的时候不写入。 不过 shell 似乎是 fork 之后 open,把拿到的 fp 替换 stdout 然后 exec ?那样的话似乎得看 echo 的实现。 2 和 3: /dev/null 作为读取的时候大小就是 0 (区别于 /dev/zero ),一读就是 EOF |
32
no1xsyzy 2020-11-23 12:25:21 +08:00
你这是写了多少日志?白天就占满磁盘,这么多内容有人看吗?看得过来吗?
没人看直接写进 /dev/null |
33
Jirajine 2020-11-23 12:28:11 +08:00 via Android 1
@zhoudaiyu XY 问题,日志不该直接写到磁盘上。就算要写也是统一收集分析后再写,这样清理的时候一定要让进程 reload 一下重新打开文件。
|
34
CallMeReznov 2020-11-23 13:23:35 +08:00
|
35
ppphp 2020-11-23 13:41:05 +08:00
日志应该 logrotate,不应该出现大日志其实
|
36
zhoudaiyu OP |
37
zhoudaiyu OP @CallMeReznov 不太清楚公司的虚机磁盘做没做 raid
|
38
DoctorCat 2020-11-23 16:31:09 +08:00
冲击较小怎么理解???
除非是写大量的数据进去,相比删除,几个原理都差不多的。最终都是要 read 、mmap 、fstat 、write 操作的。 VFS 只是几组数据结构呀,提供统一接口并维持状态而已,同一个文件系统中,排除中断的耗时和磁盘性能因素外,基本都一样。 |
39
no1xsyzy 2020-11-23 22:53:19 +08:00
啊,其实还有这种方法来清空文件:shell 里直接输入
> filename 我想起来了, > 的时候会自动因为 open 的模式是 w 而 truncate 掉。 仍然有稀疏文件的问题。 想到,还有就是 mkfifo a.log 然后 nohup cat < a.log > /dev/null |
40
doubledna 2020-11-24 08:15:50 +08:00 via Android
echo " " > filename
|
41
perfectlife 2020-11-25 16:18:02 +08:00
cat /dev/null > /filename
|
42
yanqiyu 2020-11-26 00:49:31 +08:00
In reply to #1
还是假定你想要管理的是日志,其实可以考虑 split 工具,可以一开始就把输出到标准输出(管道)日志按照一定大小分割并且存档。 但是无论如何,剪裁一下文件都是元数据操作,应该不管怎么搞都不会带来冲击,都是暂时写进缓存等到下一波元数据更新的时候一起更新磁盘。 In reply to #4 @XiLingHost 这样不行,老的 fd 不会失效,空间不会被释放。 In reply to #39 #21 @no1xsyzy @vuuv 如果是日志文件的话打开的时候应该有 O_APPEND 属性,那样无论 file pointer 怎么样问题应该不大,不会产生稀疏文件,要是打开日志没用上述属性,建议跟开发者对线。 |