主流日志采集器,阴暗潮湿的地底世界
优采云 发布时间: 2022-05-06 10:13主流日志采集器,阴暗潮湿的地底世界
>68m
额外依赖
无
根据source与sink的不同可能需要额外的依赖包
配置复杂度
中
较高
性能
高
低
资源占用
低
高
扩展性
低
高
可靠性
高(at-least-once)
高(at-least-once)
限流
自带,背压敏感协议
自定义开发扩展的一个Interceptor
负载均衡
内置
内置
输入源
内置了几个
支持多样的输入源,方便的自定义扩展输入源
输出源
内置了几个
内置比较丰富,方便的扩展
权衡优劣后,我更倾向于选择filebeat作为日志收集的agent,原因如下:
我们对于agent的需求是低耗、稳定、高效、轻量。扩展性显得并不那么重要,功能丰富与稳定性,我更倾向于后者
对于输入源,我们的场景也正好只是基于文件的日志数据收集,filebeat已经满足我们的需求场景
对于输出源,filebeat需要定制开发,支持http/grpc,有一定开发成本,但是完全可以接受
目前flume-agent的方案,日志切分是在flink任务中,导致后续架构链路冗长。使用filebeat完全可以把切分的工作放在agent端来简化架构链路,这对于后续日志平台的运维也大有裨益
同时,我们做了filebeat的压测,压测数据如下:
其结果让我们震惊,在内存占用很低的情况下(3%以下),最高cpu占用只有70%,flume(平均145%)的一半不到。这使我们以后的agent方案逐渐向filebeat倾斜。
好了,是时候来点干货了,我们来看看日志收集都有哪些问题?哪些creepy的设计?
如何发现日志文件
agent如何发现哪些日志文件是要被收集的呢?主要有如下几种方式:
正则匹配(例如:access_log\.\d{4}-\d{2}-\d{2}\.\d{2})
占位符匹配(例如:access_log.yyyy-MM-dd.log)
日志平台使用的是占位符匹配的方式,但是后端其实是兼容正则匹配的,这是出于兼容历史的原因,后面将逐步去掉正则的匹配的方式。
解决了如何发现文件后,紧接着就会遇到另一个问题:
如何发现新创建的文件
直觉做法肯定是轮询目录中的日志文件,显然这不是个完美的方案。因为轮询的周期太长会导致不够实时,太短又会耗CPU。
这真是一个艰难的trade-off
我们来对比下flume(以下所说的flume都是我们基于flume改造定制的yanxuan-flume)和filebeat的做法:
又多了一个使用filebeat的理由
好了,现在我们已经清楚如何发现文件了,那么问题又来了,我们如何知道这个文件是否已经收集过了?如果没有收集完,应该从什么位置开始接着收集?
如何标识一个日志文件收集的位置
一般是用一个文件(这里我们称之为点位文件)来记录收集的文件名(包含文件路径)与收集位置(偏移量)的对应关系,key就是文件名称,value就是偏移量。记录到文件的好处是,在机器宕掉后修复,我们还能从文件中恢复出上次采集的位置来继续收集。如下图所示:
那么,点位文件存在什么问题呢?点位文件使用日志文件名称作为key,但是一个日志文件的名称是有可能被更改的,当文件被改名后,由于点位文件中查询不到对应的采集位置,agent会认为是一个全新的日志文件而重头重新收集。所以用文件名称不能识别一个文件。那么问题又来了:
如何识别一个文件
如何识别一个文件,最简单的就是根据文件路径+文件名称。但是我们上面说了,文件很可能被改名。每个文件其实都有个inode属性(可以使用命令stat test.log查看),这个inode由OS保证同一个device下inode唯一。所以自然而然的我们就会想到用device+inode来唯一确定一个文件。然而inode是会重新分配的,即当我们删除一个文件后,其inode是会被重复利用,分配给新创建的文件。
举个常见例子:假如日志文件配置为保留30天,那30天以前的日志文件是会被自动删除的。当删除30天前的日志文件,其inode正好分配给当天新创建的日志文件,那当天的日志是不会被收集的,因为在点位文件中记录了其采集偏移量。
我们来看看flume和filebeat是怎么做的:
filebeat:device+inode
解决了如何标识文件,如何标识采集状态,那如何判断一个日志文件采集完了呢?采集到末尾返回EOF的时候就算采集完了,可是当采集速度大于日志生产速度的时候,很可能我们采集到末尾返回EOF后,又有新的内容写入。所以,问题就变成:
如何知道文件内容更新了
最简单通用的方案就是轮询要采集的文件,发现文件内容有更新就采集,采集完成后再触发下一次的轮询,既简单又通用。
那具体是轮询什么呢?
相比flume,filebeat又做了一个小优化,每次不会直接就打开文件,而是先比较文件的修改时间再决定是否打开文件进行收集。
不得不感叹,魔鬼在细节!低耗和高效如何兼得,filebeat处处都是细节
好了,知道该什么时候收集了,那我们具体收集的时候会遇到什么问题呢?
如何收集多行日志
目前的agent默认都是单行收集的,即遇到换行符就认为是一条全新的日志。可是很多情况下,我们的一条日志是多行的,比如异常堆栈、格式化后的sql&json等。
那如何判断那几行是属于同一条日志呢?
万无一失了吗?想想多行日志的最后一行按照以上的逻辑可以正常收集吗?例如下图所示:
如何处理多行日志的最后一行
当多行日志收集遇到最后一行怎么收集呢?还是来比较下flume和filebeat的做法:
目前业界貌似没有太好的办法来完美解决这个问题。个人觉得基于filebeat的多行合并的超时时间配置选项能够很大程度缓解这个问题,因为多行日志往往也是一次性写入的,超过一定时间写入的往往都是一条全新的日志。
- END -
推荐阅读 <br /><br />
使用GitLab CI和Docker自动部署SpringBoot应用记一次 Linux服务器被入侵后的排查思路Nginx为什么快到根本停不下来?用了3年Kubernetes,我们得到的5个教训Linux 运维必备的 40 个命令总结,收好了~<br />大白话理解Session和Cookie是什么?<br />系统架构性能优化思路<br />
<p style="padding-right: 0.5em;padding-left: 0.5em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-align: center;">
</p>点亮,服务器三年不宕机