filebeat-工作原理以及各种异常情况

filebeat主要模块

  • input: 找到配置的日志文件,启动harvester
  • harvester: 读取文件,发送至spooler
  • spooler: 缓存日志数据,直到可以发送至publisher
  • publisher: 发送日志至后端,同时通知registrar
  • registrar: 记录日志文件被采集的状态

日志整个采集过程

1、filebeat启动后根据linux glob规则去遍历input(Crawler的结构体)。
2、每个文件启动一个harvester去读取文件并发送到内存缓存队列memqueue,当文件被删除或者文件不活跃时间达到close_inactive(默认5min)时,harvester会被关闭。harvester被关闭后,删除的文件的磁盘空间才回被释放。
3、BufferingEventLoop获取到response channel后,consumer对memqueue的消费。(filebeat中的libbeats库包含了kafka、elasticsearch、logstash等几种client,可以实现这种队列方式)
4、调用Publish接口发送消息,并通知registrar
5、filebeat启动了一个独立的registry协程负责监听日志数据发送至后端成功后返回ack的事件,接收到ack事件后会将日志文件的State状态更新至registry文件中,State中的Offset表示读取到的文件偏移量。

如何保证数据不丢失和数据不重复

  • filebeat维护了一个registry文件在本地的磁盘,该registry文件维护了所有已经采集的日志文件的状态。
    每当日志数据发送至后端成功后,会返回ack事件。filebeat启动了一个独立的registry协程负责监听该事件,接收到ack事件后会将日志文件的State状态更新至registry文件中,State中的Offset表示读取到的文件偏移量,所以filebeat会保证Offset记录之前的日志数据肯定被后端的日志存储接收到。
  • 文件被改名或移动,filebeat会根据registry文件中维护的inode和设备号来标志每个日志文件,保证文件不会被重复读取。
  • filebeat异常重启,在每个harvester启动的时候都会读取registry文件,获取对应文件上次读取的位置继续采集,确保不会从头开始重复发送所有的日志文件。
  • harvester读取中的日志文件被清空,filebeat会在下一次Reader.Next方法中返回ErrFileTruncate异常,将inode标志文件的Offset置为0,结束这次harvester,重新启动新的harvester,虽然文件不变,但是registry中的Offset为0,采集会从头开始。
  • 使用容器部署filebeat,需要将registry文件挂载到宿主机上,否则容器重启后registry文件丢失,会使filebeat从头开始重复采集日志文件,导致数据重复或丢失。

注册表文件(registry)

目录文件详细:

data/registry/filebeat/
├── 237302.json         # registry 快照文件,记录所有日志文件的当前状态,采用最后一次动作的编号作为文件名
├── active.dat          # 记录最新一个快照文件的绝对路径
├── log.json            # registry 日志文件,记录最近执行的一连串动作的日志
└── meta.json           # registry 的元数据

filebeat每执行一个动作,会在log.json文件中记录两行JSON日志,如下:

{"op":"set", "id":237302}                             // 本次动作的编号
{
  "k": "filebeat::logs::native::778887-64768",        // key ,由 beat 类型、日志文件的 id 组成
  "v": {
    "id": "native::778887-64768",                     // 日志文件的 id ,由 identifier_name、inode、device 组成
    "prev_id": "",
    "ttl": -1,                                        // -1 表示永不失效
    "type": "log",
    "source": "/var/log/supervisor/supervisord.log",  // 日志文件的路径(文件被重命名之后,并不会更新该参数)
    "timestamp": [2061628216741, 1611303609],         // 日志文件最后一次修改的 Unix 时间戳
    "offset": 1343,                                   // 当前采集的字节偏移量,表示最后一次采集的日志行的末尾位置
    "identifier_name": "native",                      // 识别日志文件的方式,native 表示原生方式,即根据 inode 和 device 编号识别
    "FileStateOS": {                                  // 文件的状态
      "inode": 778887,                                // 文件的 inode 编号
      "device": 64768                                 // 文件所在的磁盘编号
    }
  }
}

日志异常的情况

  • 日志发送过程中,没来得及回复ack事件,filebeat就挂掉了,registry文件未更新到日志的最新状态,但实际上这条日志是发送成功了的,这就导致在filebeat重启后,这条日志会被重新发送,即存在一条重复的日志数据。
  • linux下老文件被移除,新文件马上创建,这时可能会出现registry文件中维护的inode相同的情况( inode重用),会导致registry里记录的其实是被移除的文件State状态,这样新的文件采集却从老的文件Offset开始,从而会遗漏日志数据。
  • 日志滚动过于频繁,少于scan_frequency时间(默认10s),这就可能出现个别文件未被Filebeat的input模块扫描到,就已经滚动生成重命名为其他文件,导致日志数据丢失。(概率极低,因为一般很少有系统的日志会在几秒内频繁滚动)

docker或logrotate日志滚动

harvester监听的还是旧文件,因为文件重命名或者移动是不会改变inode的。滚动生成的新文件拥有新的inode,通过Filebeat的input模块会被扫描到,并启动新的harvester进行监听。旧文件会因为文件不活跃到达close_inactive时间,harvester会被关闭。

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

调整以下参数:

  • close_renamed:当文件被重命名时关闭重命名的文件处理,默认false。
  • clean_removed:当文件被删除时关闭被删除的文件处理,从registry记录中清除文件记录,但是如果该文件后续再一次出现,将会导致文件会被filebeat从头再读一遍,默认false。
  • clean_inactive:当文件不活跃时间达到指定的时间,从registry记录中清除文件记录,若在scan_frequency时间间隔后,改文件再次发生更改,则会从最新的内容开始采集。
  • ignore_older:忽略在指定时间跨度之前修改的任何文件,例如只需要采集一天内的文件,则配置为24h。
    • 确保文件在忽略前,文件不再被读取,所以ignore_older的值必须大于clean_inactive的值。

注意:即使是文件被重新命名,这些参数也会生效,因为registry记录的是inode,与文件名称无关。所以以上的重命名或者删除都是基于inode有没有发生变化,重命名时inode是不会变的,若inode发生变化则认为原文件被删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值