filebeat占用文件句柄导致磁盘占用越来越大的解决方案

760 阅读4分钟

小知识

Linux中是通过link的数量来控制文件删除的,只有当一个文件不存在任何link的时候,这个文件才会被删除。一般来说,每个文件都有2个link计数器:i_count 和 i_nlink。 i_count的意义是当前文件使用者(或被调用)的数量,i_nlink 的意义是介质连接的数量(硬链接的数量);可以理解为i_count是内存引用计数器,i_nlink是磁盘的引用计数器。 当一个文件被某一个进程引用时,对应i_count数就会增加;当创建文件的硬链接的时候,对应i_nlink数就会增加。 对于删除命令rm而言,实际就是减少磁盘引用计数i_nlink。这里就会有一个问题,如果一个文件正在被某个进程调用,而用户却执行rm操作把文件删除了,那么会出现什么结果呢?当用户执行rm操作删除文件后,再执行ls或者其他文件管理命令,无法再找到这个文件了,但是调用这个删除的文件的进程却在继续正常执行,依然能够从文件中正确的读取及写入内容。这又是为什么呢? 这是因为rm操作只是将文件的i_nlink减少了,如果没其它的链接i_nlink就为0了;但由于该文件依然被进程引用,因此,此时文件对应的i_count并不为0,所以即使执行rm操作,但系统并没有真正删除这个文件,当只有i_nlink及i_count都为0的时候,这个文件才会真正被删除。也就是说,还需要解除该进程的对该文件的调用才行。 以上讲的i_nlink及i_count是文件删除的真实条件,但是当文件没有被调用时,执行了rm操作删除文件后是否还可以找回被删的文件呢? 前面说了,rm操作只是将文件的i_nlink减少了,或者说置0了,实际就是将文件名到inode的链接删除了,此时,并没有删除文件的实体即(block数据块),此时,如果及时停止机器工作,数据是可以找回的,如果此时继续写入数据,那么当新数据就可能会被分配到被删除的数据的block数据块,此时,文件就会被真正的回收了。

问题描述

在生产中,会产生大量的日志。filebeat在采集日志文件的时候只有遇到EOF符号才会停止一次采集。而log4j在压缩日志文件时,可能会造成filebeat还未遇到EOF符号,文件就被重命名压缩。这样就导致filebeat日志一直持有已经被压缩日志文件的文件句柄。所以,在linux中日志文件虽然被重命名压缩,但是仍在被引用,所以文件并没有被真正的删除,这就会导致磁盘被占用的越来越多。

排查过程

  1. 没有其他原因导致磁盘报警

  2. 查看filebeat打开的文件 lsof | grep "filebeat",会发现在filebeat打开的文件中有非常多标识为deleted的文件。

    image.png

  3. 将filebeat服务杀死之后磁盘空间立即被释放

解决方法

在配置文件中添加close_timeout配置。

filebeat.inputs:
  - input_type: log
    paths:
      - /usr/share/filebeat/logs/test.log
    close_time: 5m

不过需要注意的是close_timeout存在两个潜在的副作用:一个潜在的副作用是可能会数据丢失。另一个副作用是,在超时之前,多行事件可能无法完全发送。

启用此选项后,Filebeat会给每个采集器一个预定义的寿命。无论阅读器在文件中的位置如何,在close_timeout期过后,读取将停止。当你只想在文件上花费预定义的时间时,这个选项对旧的日志文件很有用。虽然close_timeout会在预定义的超时后关闭文件,但如果文件仍在更新,Filebeat会按照定义的scan_frequency再次启动新的采集器。而这个采集器的close_timeout将以超时的倒计时重新开始。

这个选项在输出被阻塞的情况下特别有用,这使得Filebeat即使对从磁盘上删除的文件也能保持打开的文件处理程序。将close_timeout设置为5m,可以确保定期关闭文件,以便操作系统可以释放它们。

如果你把close_timeout设置为等于ignore_older,那么如果文件在采集器关闭时被修改,就不会被接收。这种设置组合通常会导致数据丢失,并且不会发送完整的文件。

当你对包含多行事件的日志使用close_timeout时,采集器可能会在多行事件的中间停止,这意味着只有部分事件会被发送。如果再次启动采集器,并且文件仍然存在,那么只有事件的第二部分会被发送。

这个选项默认设置为0,这意味着其不会停止监控

拓展

filebeat其他close_*属性介绍