Filebeat如何保证logrotate时依然正确读取文件

我们的日志收集系统使用Filebeat来收集日志文件,部署时并没有多想,只配置了一下监控的日志文件名。上线几个月,日志监控从没出过问题。后来想想其实这里面有很多点需要考虑的,没出问题真是感谢Filebeat默认配置下想的就很周全。

业务系统使用logback作为日志框架。通过查看源码,发现logback日志切割用的是JDK里File#renameTo()方法。如果该方法失败,就再尝试使用复制数据的方式切割日志。查找该方法相关资料得知,只有当源文件和目标目录处于同一个文件系统、同volumn(即windows下的C, D盘)下该方法才会成功,切不会为重命名的后的文件分配新的inode值。也就是说,如果程序里一直保存着该文件的描述符,那么当程序再写日志时,就会向重命名后的文件中写。那么问题来了,filebeat是会一直打开并保存文件描述符的,那么它是怎么得知日志被切割这件事的呢?

如果只用当前文件描述符一路监控到天黑的话,那么当logback把日志重命名后,filebeat仍然会监控重命名后的日志,新创建的日志文件就看不到了。实际上,filebeat是通过close_inactivescan_frequency两个参数(机制)来应对这种情况的:

  • close_inactive 
    该参数指定当被监控的文件多长时间没有变化后就关闭文件句柄(file handle)。官方建议将这个参数设置为一个比文件最大更新间隔大的值。比如文件最长5s更新一次,那就设置成1min。默认值为5min.

  • scan_frequency 
    该参数指定Filebeat搜索新文件的频率(时间间隔)。当发现新的文件被创建时, Filebeat会为它再启动一个 harvester 进行监控。默认为10s。

综合以上两个机制,当logback完成日志切割后(即重命名),此时老的harvester仍然在监控重命名后的日志文件,但是由于该文件不会再更新,因此会在close_inactive时间后关闭这个文件的 harvester。当scan_frequency时间过后,Filebeat会发现目录中出现了新文件,于是为该文件启动 harvester 进行监控。这样就保证了切割日志时也能不丢不重的传输数据。(不重是通过为每个日志文件保存offset实现的)

 

反思

先上官网链接 How Filebeat Works
首先感谢filebeat的默认配置很给力,我们的日志收集系统使用Filebeat来收集日志文件,部署时并没有多想,只配置了一下监控的日志文件名。上线测试,日志采集这块从没出过问题。自己就没有深入考虑过Filebeat工作原理,只知道filebeat是根据文件系统文件名关联到inode信息,根据inode信息进行日志文件的监听的。并没有深入的结合配置及filebeat原理深入思考过Filebeat。

Filebeat由两个主要组件组成:input 组件和文件监听器(harvester,下文都用"harvester"代替)。这俩组件一起工作以跟踪文件并将事件数据发送到指定的输出模块。
下面我们来介绍一下input 和 harvester两个模块的作用、生命周期、和原理进行描述:

1.1 harvester 简介和生命周期

harvester负责读取单个文件的内容。harvester逐行读取每个文件,并将内容发送到输出模块。每个文件启动一个harvester线程。harvester负责打开和关闭文件,这意味着file descriptor在harvester运行时保持打开状态。如果在获取文件时删除或重命名该文件,Filebeat将继续读取该文件。这样做的影响是,在harvester关闭之前,磁盘上的空间将被保留。默认情况下,Filebeat会保持文件打开状态,直到到达close_inactive。

 关闭harvester有以下影响:

  • 文件句柄被关闭,如果文件在harvester仍在读取文件时被删除,则会释放基础资源。
  • 只有通过scan重新开始获取文件,scan操作的频率根据scan_frequency配置的值。
  • 如果在harvester关闭时移动或移除文件,则不会继续监听文件。

想要控制harvester的关闭请使用close_*相关配置

1.2 input 简介及配置

input负责管理harvester,并查找所有要读取的文件。
如果输入类型是log,则input将查找驱动器上与定义的glob路径匹配的所有文件,并为每个文件启动一个harvester。每个input都在自己的Go routine中运行。下面是配置的例子

filebeat.inputs:
- type: log
  paths:
    - /var/log/*.log
    - /var/path2/*.log
  • Filebeat当前支持多种input类型( 输入类型配置文档请点击链接)。每个input类型可以定义多次。当input类型为log时,filebeat会根据配置的路径检查每个文件,来判断是否需要启动harvester、是否已经有harvester在监听文件或是否可以忽略该文件(ignore_older配置详见)。在harvester关闭后,只有文件大小发生变化时,才会重新创建harvester监听新的数据。

1.3 Filebeat记录文件状态

Filebeat保存每个文件的状态,并经常将文件状态刷新到磁盘中的registry文件中(7.*以后版本的registry文件路径:./data/registry/filebeat/data.json)。该状态用于记录harvester读取文件的最后一个偏移量,并确保发送所有日志行。如果无法访问输出模块(如Elasticsearch或Logstash等),Filebeat将跟踪最后发送的偏移量,并在输出模块再次可用时继续读取文件。当Filebeat运行时,状态信息也保存在每个输入的内存中。当Filebeat重新启动时,使用registry文件来重建状态,Filebeat根据registry文件中的记录来恢复harvester。
对于每个输入,Filebeat都会保留它找到的每个文件的状态。由于文件可以重命名或移动,文件名和路径不足以标识文件。对于每个文件,Filebeat存储唯一的标识符,以检测文件是否以前被捕获。
如果每天创建大量新日志文件,您可能会发现registry文件变得太大,可以参考通过clean_*配置减少registry文件大小相关内容。

1.4 Filebeat如何保证消息最少发送一次(at-least-once 特性)

Filebeat保证日志事件将至少传递一次到配置的输出,并且不会丢失数据(个人理解不能完全保证详见2.1)。因为它将每个事件的传递状态存储在registry文件中(上述流程图中有描述)。在已定义的输出被阻止且未确认所有事件的情况下,Filebeat将继续尝试发送事件,直到输出模块确认已接收到事件为止。
如果Filebeat在发送事件的过程中关闭,它不会等待输出确认所有事件后再关闭。当Filebeat重新启动时,将再次发送关闭前未确认的所有事件到输出模块。这样可以确保每个事件至少发送一次,但未确认的事件就可能成为重复事件,故只能保证至少传递一次。通过设置shutdown_timeout选项,可以将Filebeat配置为在结束进程前等待特定时间,来尽可能地多的收到确认消息。

2 Filebeat异常场景及应对办法

2.1 文件滚动时异常中断

问题描述:
通过阅读官方文档,以及自己的使用,个人认为filebeat并不能保证消息的at-least-once 特性,因为filebeat的input会在根据scan_frequency来扫描文件,如果日志滚动过于频繁且小于scan_frequency的时间就会发生滚动,这样就有可能出现个别文件不能被Filebeat的input模块扫描到,导致数据丢失,当然这种情况出现的概率极低,因为一般很少有系统的日志会在几秒内频繁滚动。
应对办法:
这种情况的出现我们需要调整两个地方:

  1. 日志滚动策略,降低日志滚动频率
  2. 减小scan_frequency的值,最小不能小于1s

2.2 日志文件滑动策略与大量日志文件产生导致registry文件过大

问题描述:
首先解释下日志文件滑动生成策略,单个日志文件达到某种阈值(时间或容量),就会将生成一个新的文件名继续记录,而滚动生成就是将这个日志文件重命名,新的日志仍然使用原有文件名。只不过指向了新的inode信息。
所以滑动生成日志的策略会导致,Filebeat在registry中产生大量的记录,滚动生成可以通过exclude_file的方式排出已经监听过的文件。
应对办法
如果你监听的日志文件是滑动策略,或没有办法配置exclude_file导致大量,那么需要配置clean_inactive或clean_removed,不然filebeat的registry文件的容量会不断增多。参考通过clean_*配置减少registry文件大小相关内容。
elastic官方也给出了跟丰富的troubleshooting文档,供参考。

 

filebeat采集数据的几个痛点的解决方案

1.行转列

filebeat采集多行日志的时候会把日志分开来采集,这样传递到logstash的时候就无法正确解析了,所以用把多行日志统一采集。 
这时候可以使用:multiline配置选项。

  • multiline:适用于日志中每一条日志占据多行的情况,比如各种语言的报错信息调用栈。这个配置的下面包含如下配置:

    pattern:多行日志开始的那一行匹配的pattern 
    negate:是否需要对pattern条件转置使用,不翻转设为true,反转设置为false 
    match:匹配pattern后,与前面(before)还是后面(after)的内容合并为一条日志 
    max_lines:合并的最多行数(包含匹配pattern的那一行) 
    timeout:到了timeout之后,即使没有匹配一个新的pattern(发生一个新的事件),也把已经匹配的日志事件发送出去

譬如采集tomcat日志的时候可以这么配

    multiline:
    pattern: ‘^\[‘
    negate:  true
    match:   after

这样就能采集每一次输入的多行日志了,不过对已经存在的日志会一窝蜂的采集。

2.带上自定义参数

基本上filebeat数据通过logstash解析后传到es的数据都会进行分类。采集的时候就必须带上采集数据所属的类别,以便于之后的分析。filebeat可以在采集的数据上增加fields自定义参数,便于解析。

  • fields:向输出的每一条日志添加额外的信息,比如“level:debug”,方便后续对日志进行分组统计。默认情况下,会在输出信息的fields子目录下以指定的新增fields建立子目录,例如fields.level。 
    fields: level: debug

不过这样采集的数据还是无法进行分析,因为数据到达es后,es默认会将数据进行分词,录入的数据会被分词器分析称各个term,无法进行分类。必须使用动态模板映射logstash传输到es的数据。

3.多目录采集

很多时候会采集多目录下的日志数据,并且每个日志数据都会有自己的自定义参数,这时候可以定义多个input_type来解决这个问题,写法如下

filebeat.prospectors:
- input_type: log
  paths:
    - /data1/server/tomcat/tomcat12004/logs/*
  fields:
    logIndex: tomcat
    docType: tomcat-log
    system:  m.openapi
  multiline:
    pattern: ‘^\[‘
    negate:  true
    match:   after
- input_type: log
  paths:
    - /data1/server/tomcat/tomcat12001/logs/catalina.out
  fields:
    logIndex: tomcat
    docType: tomcat-log
    system:  csb
  multiline:
    pattern: ‘^\[‘
    negate:  true
    match:   after

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
logrotate是一个用于管理日志文件的工具,它可以定期轮转、压缩和删除日志文件,以便节省磁盘空间并保持日志文件的可读性。logrotate的配置文件通常位于/etc/logrotate.conf或/etc/logrotate.d/目录下。 logrotate配置文件的基本结构如下: 1. 日志文件路径:指定需要轮转的日志文件路径,可以使用通配符来匹配多个文件。 2. 轮转规则:定义了轮转的频率和方式,包括轮转周期、保留的旧日志文件数量、是否压缩等。 3. 轮转后的操作:可以指定轮转后需要执行的操作,如发送通知、重新启动相关服务等。 以下是一个logrotate配置文件的示例: ``` /var/log/example.log { rotate 7 daily compress delaycompress missingok notifempty create 0644 root root postrotate /usr/bin/killall -HUP example_daemon endscript } ``` 上述配置文件中,"/var/log/example.log"是需要轮转的日志文件路径。配置项的含义如下: - rotate 7:保留7个旧日志文件。 - daily:每天执行一次轮转。 - compress:压缩旧日志文件。 - delaycompress:延迟压缩,下次轮转才压缩上一次轮转生成的旧日志文件。 - missingok:如果日志文件不存在,不报错。 - notifempty:如果日志文件为空,不轮转。 - create 0644 root root:创建新的日志文件,并设置权限为0644,所有者为root。 - postrotate...endscript:在轮转后执行的操作,此处是重新加载example_daemon服务。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值