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从头开始重复采集日志文件,导致数据重复或丢失。
日志异常的情况
- 日志发送过程中,没来得及回复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会被关闭。文章来源:https://uudwc.com/A/Y6dPx
日志文件滑动策略或大量日志文件产生导致registry文件过大
调整以下参数:文章来源地址https://uudwc.com/A/Y6dPx
- clean_removed :当文件被删除或重命名时,从registry记录中清除文件记录,但是如果该文件后续再一次出现,将会导致文件会被filebeat从头再读一遍。
- clean_inactive:当文件不活跃时间达到指定的时间,从registry记录中清除文件记录,clean_inactive必须大于ignore_older。
- ignore_older:忽略在指定时间跨度之前修改的任何文件。
PS:即使是文件被重新命名,这些参数也会生效,因为registry记录的inode和文件名称无关。