请问在 Linux 下如何清空一个大文件的内容对磁盘 I/O 的冲击较小? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
zhoudaiyu
V2EX    Linux

请问在 Linux 下如何清空一个大文件的内容对磁盘 I/O 的冲击较小?

  •  
  •   zhoudaiyu
    PRO
    2020-11-22 16:26:54 +08:00 6431 次点击
    这是一个创建于 1814 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前知道如下几种方式可以清空文件(假定文件名是 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 冲击小一些?

    42 条回复    2020-11-26 00:49:31 +08:00
    ysc3839
        1
    ysc3839  
       2020-11-22 16:31:51 +08:00 via Android
    个人认为是 1 和 4
    zhoudaiyu
        2
    zhoudaiyu  
    OP
    PRO
       2020-11-22 16:33:35 +08:00
    @ysc3839 #1 为什么呢
    xuanbg
        3
    xuanbg  
       2020-11-22 16:47:38 +08:00
    重新链接一个文件,几乎没有磁盘 IO
    KagurazakaNyaa
        4
    KagurazakaNyaa  
       2020-11-22 18:08:08 +08:00
    rm -f a && touch a
    zhoudaiyu
        5
    zhoudaiyu  
    OP
    PRO
       2020-11-22 18:18:05 +08:00
    @xuanbg #3 硬连接?

    @XiLingHost #4 这样会不会有一瞬间向这个文件写数据的应用报错?
    ysc3839
        6
    ysc3839  
       2020-11-22 18:36:13 +08:00
    @zhoudaiyu 因为没有向文件写数据。
    codehz
        7
    codehz  
       2020-11-22 18:37:52 +08:00 via Android   1
    显然和文件系统有关系,需要根据具体情况分析
    zhoudaiyu
        8
    zhoudaiyu  
    OP
    PRO
       2020-11-22 18:58:52 +08:00
    @codehz #7 也就是说不同的 fs 要用不同的命令保证冲击最小化?
    msg7086
        9
    msg7086  
       2020-11-22 19:07:24 +08:00 via Android   1
    清空文件本质上就是把文件的大小改为零。你说对这些方式调用的是同一个操作。
    dd 文件默认就是先 truncate,重定向也是。
    所以你就是贴了 4 个一样的东西……
    zhoudaiyu
        10
    zhoudaiyu  
    OP
    PRO
       2020-11-22 19:12:32 +08:00
    @msg7086 #9 相同的系统调用?
    laminux29
        11
    laminux29  
       2020-11-22 19:18:33 +08:00
    冲击小的正确方式应该让文件系统,根据磁盘设备的负载,来对 io 操作进行优先级划分。但是目前主流 fs 好像没这方面的 api 。

    退而且求其次的方法是,监控磁盘设备的负载,负载高的时候不写入,负载低的时候再写入。
    fasionchan
        12
    fasionchan  
       2020-11-22 19:26:14 +08:00
    @zhoudaiyu 应该都是 flags 设置 O_TRUNC 标志的 open 系统调用,多看看操作系统底层,别被眼前的表象给骗了

    也许可以尝试分多次 truncate,每次只截短一点,最终截到 0
    zhoudaiyu
        13
    zhoudaiyu  
    OP
    PRO
       2020-11-22 19:40:45 +08:00
    @laminux29 #11 至少我们用的 ext3 好像没有
    @fasionchan #12 分次 truncate 靠谱
    muzuiget
        14
    muzuiget  
       2020-11-22 20:41:37 +08:00
    这不是文件系统的的责任吗,本来删除文件就是仅删除文件元数据,下次写数据覆盖就是了,删除就是马上完成的事。

    你要是“安全擦除”那种,你这么还是得每隔字节覆盖一次,哪种方法都一样。
    walker2laok
        15
    walker2laok  
       2020-11-22 22:55:53 +08:00
    echo ' ' > big_file.log
    mingl0280
        16
    mingl0280  
       2020-11-23 02:29:59 +08:00 via Android
    我印象里这四个最后都是调的 trunc,所以没区别(?),你可以自己创建几个文件 strace 下……
    iceheart
        17
    iceheart  
       2020-11-23 07:22:36 +08:00 via Android
    unlink
    ericbize
        18
    ericbize  
       2020-11-23 08:52:15 +08:00 via iPhone
    很好奇楼主使用场景
    AmrtaShiva
        19
    AmrtaShiva  
       2020-11-23 09:00:55 +08:00 via iPhone
    15L 这个自己用过
    vuuv
        20
    vuuv  
       2020-11-23 09:03:25 +08:00 via Android
    4 最小,1 次之。因为 1 相当于 truncate+write 空字符串,多了至少一次磁盘操作。当然内核也可能把这几次操作给合并掉,从而没有差异。
    2 和 3 是一样的坑,因为没有限定源或目的的大小,会占满整个分区。
    vuuv
        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 )通知进程重新打开一次。从而完成文件切换。这样重新打开文件前,数据会继续写到原文件,之后只写新文件,算是无缝切换了。
    openbsd
        22
    openbsd  
       2020-11-23 09:20:07 +08:00
    一般都是用 15 楼说的法子
    liuhuan475
        23
    liuhuan475  
       2020-11-23 09:32:35 +08:00
    echo '' > xxx
    sujin190
        24
    sujin190  
       2020-11-23 09:39:10 +08:00
    @zhoudaiyu #5 删除后需要等所有一打开的进程都关闭这个文件之后才会真正从磁盘删除,继续读写完全是正常的,磁盘其实并不会释放,所以如果你想说的类似日志文件写的太大了,想清空它又不想重启进程估计不行,似乎不让进程重新打开这个文件是不行的吧,否则删除新建最靠谱了
    zhoudaiyu
        25
    zhoudaiyu  
    OP
    PRO
       2020-11-23 09:45:28 +08:00 via iPhone
    @ericbize 清理大日志
    ericbize
        26
    ericbize  
       2020-11-23 11:26:15 +08:00
    @zhoudaiyu 写个脚本,没什么 io 的时候操作不稳么
    li492135501
        27
    li492135501  
       2020-11-23 11:27:37 +08:00
    在文件表里删掉
    zhoudaiyu
        28
    zhoudaiyu  
    OP
    PRO
       2020-11-23 11:29:25 +08:00 via iPhone
    @ericbize 那还得定时查 IO 啊
    ericbize
        29
    ericbize  
       2020-11-23 11:41:07 +08:00
    只要不是像我司这种, 7x24 都是高峰的, 晚上一般都还好吧!
    zhoudaiyu
        30
    zhoudaiyu  
    OP
    PRO
       2020-11-23 12:00:28 +08:00 via iPhone
    @ericbize 但是往往白天磁盘就告警了...
    no1xsyzy
        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
    no1xsyzy
        32
    no1xsyzy  
       2020-11-23 12:25:21 +08:00
    你这是写了多少日志?白天就占满磁盘,这么多内容有人看吗?看得过来吗?
    没人看直接写进 /dev/null
    Jirajine
        33
    Jirajine  
       2020-11-23 12:28:11 +08:00 via Android   1
    @zhoudaiyu XY 问题,日志不该直接写到磁盘上。就算要写也是统一收集分析后再写,这样清理的时候一定要让进程 reload 一下重新打开文件。
    CallMeReznov
        34
    CallMeReznov  
       2020-11-23 13:23:35 +08:00
    姿势和设备使用方法不对的结果。
    2X 个盘 R5 软阵列了解一下?
    ppphp
        35
    ppphp  
       2020-11-23 13:41:05 +08:00
    日志应该 logrotate,不应该出现大日志其实
    zhoudaiyu
        36
    zhoudaiyu  
    OP
    PRO
       2020-11-23 13:59:16 +08:00
    @no1xsyzy 其实没人看 但是好多日志都是这么玩的 没时间弄 (狗头

    @Jirajine
    @ppphp 说的对,但是工作量太大了,太不规范了
    zhoudaiyu
        37
    zhoudaiyu  
    OP
    PRO
       2020-11-23 13:59:59 +08:00
    @CallMeReznov 不太清楚公司的虚机磁盘做没做 raid
    DoctorCat
        38
    DoctorCat  
       2020-11-23 16:31:09 +08:00
    冲击较小怎么理解???
    除非是写大量的数据进去,相比删除,几个原理都差不多的。最终都是要 read 、mmap 、fstat 、write 操作的。
    VFS 只是几组数据结构呀,提供统一接口并维持状态而已,同一个文件系统中,排除中断的耗时和磁盘性能因素外,基本都一样。
    no1xsyzy
        39
    no1xsyzy  
       2020-11-23 22:53:19 +08:00
    啊,其实还有这种方法来清空文件:shell 里直接输入
    > filename
    我想起来了, > 的时候会自动因为 open 的模式是 w 而 truncate 掉。
    仍然有稀疏文件的问题。

    想到,还有就是 mkfifo a.log 然后 nohup cat < a.log > /dev/null
    doubledna
        40
    doubledna  
       2020-11-24 08:15:50 +08:00 via Android
    echo " " > filename
    perfectlife
        41
    perfectlife  
       2020-11-25 16:18:02 +08:00
    cat /dev/null > /filename
    yanqiyu
        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 怎么样问题应该不大,不会产生稀疏文件,要是打开日志没用上述属性,建议跟开发者对线。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5213 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 07:14 PVG 15:14 LAX 23:14 JFK 02:14
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86