核心概念
目的端:具备数据订阅功能的集中存储
源端:普通的文本文件,通过网络接收到的日志数据
推:日志采集Agent主动从源端取得数据后发送给目的端
拉:目的端主动向日志采集Agent获取源端的数据
- 常用采集工具:Fluentd、Logstash、Flume、scribe
简而言之是对Linux下的tail -f命令的完善
实现日志采集
如何发现一个文件?
- 简单粗暴的方式是让用户直接把要采集的文件罗列出来放在配置文件中,然后日志采集Agent读取配置文件找到要采集的文件列表,然后打开这些文件进行采集。
- 灵活一点的会让用户配置一个日志采集的目录和文件名字匹配规则,agent自动采集。
如何发现新创建的日志文件?
- 定时去轮询目录。但是轮询的周期太长会导致不够实时,太短又会耗CPU。
- 利用Linux的Inotify的机制,让内核来监测一个目录下文件的变化,然后通过事件的方式通知agent。但是Inotify不支持递归下目录文件生成,并且不通用。
- 改进措施就是Inotify+轮询。定时轮询保证不会漏掉文件,Inotify保证实时性,减少CPU损耗。
如何保证在宕机情况下文件不会遗漏?
使用点位文件记录文件名和对应的采集位置,那么问题又来了。
如何保证点位文件的准确性?
使用Linux的rename机制保证文件写入要么成功,要么失败,绝对不能出现写了一半的情况。
文件在运行过程中被其他用户重命名怎么办?
使用inode作为文件的标识信息,而且保证同一时刻Inode是不会重复的,但是同一设备可能会有很多文件系统,所以需要加上设备码dev,所以点位文件的记录是一个三元组(dev,inode,offset)
如何正确识别一个文件?
利用文件的扩展属性xattr,保证如果文件被删除了,然后创建一个新的文件即使Inode相同,但是文件标识也不一样。或者也可以通过文件的内容来解决这个问题,可以读取文件的前N个字节作为文件标识。
如何读取文件?
尽可能的顺序读,充分利用Linux系统缓存,必要的时候可以用posix_fadvise在采集完日志文件后清除页缓存,主动释放系统资源。
如何才知道有新数据了,然后继续采集?
轮询去查询要采集文件的stat信息,发现文件内容有更新就采集,采集完成后再触发下一次的轮询。
如果在我们采集的过程中被删除了会如何?
已经打开的文件即使被删除也只是引用计数减1,只要有进程引用就可以继续读内容的,所以日志采集Agent可以安心的继续把日志读完,然后释放文件的fd,让系统真正的删除文件。
如何安全的释放文件句柄?
- 让用户配置一个时间,文件删除后如果在指定的时间范围内没有数据新增就释放句柄
- lsof -f列出系统中进程打开的文件列表,遍历所有的进程查看它们的打开文件表逐一的比较
FTP服务器采集
由于ftp客户端的不可控,所以导致FTP服务器的实时采集不同于一般的日志采集,因此agent只能够监听服务器上的文件,进而判断该文件是否写成功。
注意事项
- agent周期性访问FTP服务器,获取符合匹配规则文件的文件状态,过一定时间间隔(视情况而定,一般是几秒)再刷新,如果新增加的文件没有发生状态变更,则下载数据,如果是监控文件的更新,则是对比文件状态是否发生变更,找到之前记录的offset,采集更新数据。
- 在某些操作系统的ftp服务,在文件上传的时候,ftp服务会对此文件做加锁处理,保证该文件不被读写,但是并不通用,因此最理想的情况是由文件上传者管理,利用rename,临时文件夹等方式保证文件确实完成写入操作。