主流日志采集器,阴暗潮湿的地底世界

优采云 发布时间: 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>

  点亮,服务器三年不宕机

  

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线