日志agent对于使用日志平台的用户来说,是一个黑盒。对于用户来说,agent有些不好的地方:

•agent私底下偷偷摸摸都做了些什么事情呢?(阴暗的)•agent的设计实现其实有一些dirty、creepy的地方(潮湿的)

所以我觉得日志收集agent对大家来说是一个阴暗潮湿的地底世界:

就让我举起火把,照亮所有dark、dirty、creepy的地方。

背景提要

日志收集我们知道是在宿主服务器通过一个agent来收集日志数据,并且将收集到的数据源源不断的发送到日志平台的下游链路消费。

正是因为日志收集agent是整个日志平台的唯一数据来源,所以日志收集的地位非常重要。一旦日志收集agent出现问题,轻则影响后续链路的报警和查询,重则影响宿主服务器,反客为主,影响更为重要的应用系统。

所以,先来看看我们选型agent的时候有些什么阴暗的地方:

日志收集agent方案

由于日志收集agent的特殊性,我们对于agent的要求优先级由高到低如下:

低耗>稳定>高效>轻量

以此原则,我们逐步推动agent的演进。

日志收集agent初期方案

其实日志平台一开始并没有对比太多其他的agent方案,直接就是使用的flume作为agent。

why?

基于MVP(minimum viable product)原则,日志平台第一版的选项更看重能快速上线、快速试错、快速验证。而且严选这边其实之前就存在一套日志收集系统是用的flume,我们决定先复用flume,再对其定制。然后其实还有一个更重要的原因:为了兼容一些历史问题(例如收集的日志要写到北京kafka的情况),我一开始不得不沿用flume作为agent的方案。

then?

以为我们agent就此受困于历史的漩涡中束手束脚,止步不前?不存在的,我们同步调研了filebeat的方案。来看看我们对filebeat的调研工作:

filebeat作为日志收集agent

先来看下2者之间的对比:

权衡优劣后,我更倾向于选择filebeat作为日志收集的agent,原因如下:

•我们对于agent的需求是低耗、稳定、高效、轻量。扩展性显得并不那么重要,功能丰富与稳定性,我更倾向于后者•对于输入源,我们的场景也正好只是基于文件的日志数据收集,filebeat已经满足我们的需求场景•对于输出源,filebeat需要定制开发,支持http/grpc,有一定开发成本,但是完全可以接受•目前flume-agent的方案,日志切分是在flink任务中,导致后续架构链路冗长。使用filebeat完全可以把切分的工作放在agent端来简化架构链路,这对于后续日志平台的运维也大有裨益

同时,我们做了filebeat的压测,压测数据如下:

其结果让我们震惊,在内存占用很低的情况下(3%以下),最高cpu占用只有70%,flume(平均145%)的一半不到。这使我们以后的agent方案逐渐向filebeat倾斜。

好了,是时候来点干货了,我们来看看日志收集都有哪些问题?哪些creepy的设计?

如何发现日志文件

agent如何发现哪些日志文件是要被收集的呢?主要有如下几种方式:

1、用户配置

•优点:简单高效。用户直接把需要采集的日志文件给配进来,可以说是最简单高效的办法。•缺点:日志文件很可能是会按天滚动(rotate)的,提前配置肯定覆盖不了后面新创建的日志文件。

2、正则匹配(例如:access_log.\d{4}-\d{2}-\d{2}.\d{2})

•优点:灵活。能够很好的覆盖到各种滚动新建的日志文件•缺点:正则由用户输入,效率堪忧,一旦发生大量回溯,很可能cpu100%。这也是我们最不希望发生在agent端的问题

3、占位符匹配(例如:access_log.yyyy-MM-dd.log)

•优点:灵活高效。即能很好的匹配新创建的日志文件,agent端的匹配效率也非常高•缺点:对于一些奇葩命名滚动规则的日志文件不太好适应

日志平台使用的是占位符匹配的方式,但是后端其实是兼容正则匹配的,这是出于兼容历史的原因,后面将逐步去掉正则的匹配的方式。

解决了如何发现文件后,紧接着就会遇到另一个问题:

如何发现新创建的文件

直觉做法肯定是轮询目录中的日志文件,显然这不是个完美的方案。因为轮询的周期太长会导致不够实时,太短又会耗CPU。

这真是一个艰难的trade-off

我们来对比下flume(以下所说的flume都是我们基于flume改造定制的yanxuan-flume)和filebeat的做法:

•yanxuan-flume:轮询

flume目前是每隔500ms去轮询查找是否有新的日志文件,基本上就我们前面提到的”直觉做法”。实现简单,但是我们很难衡量这个500ms是否是一个合适合理的值。

•fliebeat:OS内核指令+轮询

filebeat的方案就完善优雅很多。依赖OS内核提供的高效指令,分别是:

+ linux:inotify
+ macos:fsevents
+ windows:ReadDirectoryChangesW

来通知是否有新文件,并且辅助一个周期相对较长的轮询来避免内核指令的bug(具体参考其man page)),取长补短,低耗与高效兼得

又多了一个使用filebeat的理由

好了,现在我们已经清楚如何发现文件了,那么问题又来了,我们如何知道这个文件是否已经收集过了?如果没有收集完,应该从什么位置开始接着收集?

如何标识一个日志文件收集的位置

一般是用一个文件(这里我们称之为点位文件)来记录收集的文件名(包含文件路径)与收集位置(偏移量)的对应关系,key就是文件名称,value就是偏移量。记录到文件的好处是,在机器宕掉后修复,我们还能从文件中恢复出上次采集的位置来继续收集。如下图所示:

那么,点位文件存在什么问题呢?点位文件使用日志文件名称作为key,但是一个日志文件的名称是有可能被更改的,当文件被改名后,由于点位文件中查询不到对应的采集位置,agent会认为是一个全新的日志文件而重头重新收集。所以用文件名称不能识别一个文件。那么问题又来了:

如何识别一个文件

如何识别一个文件,最简单的就是根据文件路径+文件名称。但是我们上面说了,文件很可能被改名。每个文件其实都有个inode属性(可以使用命令stat test.log查看),这个inode由OS保证同一个device下inode唯一。所以自然而然的我们就会想到用device+inode来唯一确定一个文件。然而inode是会重新分配的,即当我们删除一个文件后,其inode是会被重复利用,分配给新创建的文件。

举个常见例子:假如日志文件配置为保留30天,那30天以前的日志文件是会被自动删除的。当删除30天前的日志文件,其inode正好分配给当天新创建的日志文件,那当天的日志是不会被收集的,因为在点位文件中记录了其采集偏移量。

我们来看看flume和filebeat是怎么做的:

1、yanxuan-flume:device+inode+首行内容MD5

•优点:无需用户干预,能保证唯一识别一个文件•缺点:需要打开文件读取文件内容,而且首行内容MD5还是太暴力了,因为首行很可能是一个超长日志,再加上MD5,不仅耗CPU,而且判断效率有点低。

可以考虑读取首行N个字节的内容md5,但是N到底取多大呢? 越大相同的概率越小,效率越低。反过来,N越小重复的概率越大,效率越高。这又是一个艰难的trade-off啊

2、filebeat:device+inode

•优点:判断效率高。无需打开文件读取内容即可判断•缺点:可能会误判

filebeat提供了一个配置选项来决定何时删除点位文件中的记录:clean_inactive:72h表示清除72h不活跃的文件对应的点位文件中的记录。基本上我们的文件都是每天(24h)滚动(rotated)的,那前一天的日志文件是不会写入的,所以设置clean_inactive:72h是合理的。

那为什么不在日志文件被删除后直接删除点位文件中对应的记录呢?因为假如我们的日志文件在一个共享的存储分区中,当这个分区消失了一会(接触不良等情况)又重新出现后,里面的所有日志文件都会重头开始重新收集,因为他们的收集状态已经从点位文件中删除了。

我觉得这是一个合理的”甩锅”给使用者的配置选项。

解决了如何标识文件,如何标识采集状态,那如何判断一个日志文件采集完了呢?采集到末尾返回EOF的时候就算采集完了,可是当采集速度大于日志生产速度的时候,很可能我们采集到末尾返回EOF后,又有新的内容写入。所以,问题就变成:

如何知道文件内容更新了

最简单通用的方案就是轮询要采集的文件,发现文件内容有更新就采集,采集完成后再触发下一次的轮询,既简单又通用。

那具体是轮询什么呢?

•yanxuan-flume:按照文件的修改时间排序,轮询文件内容,尝试收集,如果返回是EOF则继续下一份文件•filebeat:按照文件的修改时间排序,轮询文件的stat状态,修改时间大于点位文件中记录的时间,则打开文件收集,返回EOF则继续下一份文件

相比flume,filebeat又做了一个小优化,每次不会直接就打开文件,而是先比较文件的修改时间再决定是否打开文件进行收集。

不得不感叹,魔鬼在细节!低耗和高效如何兼得,filebeat处处都是细节

好了,知道该什么时候收集了,那我们具体收集的时候会遇到什么问题呢?

如何收集多行日志

目前的agent默认都是单行收集的,即遇到换行符就认为是一条全新的日志。可是很多情况下,我们的一条日志是多行的,比如异常堆栈、格式化后的sql&json等。

那如何判断那几行是属于同一条日志呢?

•yanxuan-flume:flume原生是不支持的,我们自己写了个插件,通过配置一条日志的开头字符S来判断。假如一行日志的开头不是S,则认为是和上一行属于同一条日志•filebeat:支持flume类似的方式,同时提供了配置项negate:true 或 false;默认是false,匹配开头字符S的行合并到上一行;true,不匹配S的行合并到上一行。能够覆盖更多的多行日志场景。

当然还有其他相关配置来兜底合并行可能带来的问题,例如一次最多合并几行和合并行的超时时间来防止可能的内存溢出与卡死

万无一失了吗?想想多行日志的最后一行按照以上的逻辑可以正常收集吗?例如下图所示:

如何处理多行日志的最后一行

当多行日志收集遇到最后一行怎么收集呢?还是来比较下flume和filebeat的做法:

•yanxuan-flume:遇到EOF即认为是这条多行日志收集完了。这有个问题就是,很可能这条多行日志还没有写完,就被收集发送出去了。而且当收集速度大于日志写入速度的时候或者异步打印日志的时候,又很容易发生这种情况•filebeat:遇到EOF会回退之前读取的内容,然后一直持有这个文件句柄(直到超时),直到新一行日志写入,根据新一行日志的行首字符匹配来判断是否当前行的日志结束。所以filebeat的存在的问题是很可能最后一行永远不会被收集

目前业界貌似没有太好的办法来完美解决这个问题。个人觉得基于filebeat的多行合并的超时时间配置选项能够很大程度缓解这个问题,因为多行日志往往也是一次性写入的,超过一定时间写入的往往都是一条全新的日志。

原文地址:https://zacard.net/2019/06/15/log-agent/

日志收集Agent,阴暗潮湿的地底世界相关推荐

  1. 日志收集Agent方案和比较

    背景提要 日志收集我们知道是在宿主服务器通过一个agent来收集日志数据,并且将收集到的数据源源不断的发送到日志平台的下游链路消费. 正是因为日志收集agent是整个日志平台的唯一数据来源,所以日志收 ...

  2. Kubernetes 日志收集的原理,看这一篇就够了

    准备 关于容器日志 Docker 的日志分为两类,一类是 Docker 引擎日志:另一类是容器日志.引擎日志一般都交给了系统日志,不同的操作系统会放在不同的位置. 本文主要介绍容器日志,容器日志可以理 ...

  3. 12c集群日志位置_Kubernetes(k8s)那些套路之日志收集

    准备 关于容器日志 Docker的日志分为两类,一类是 Docker引擎日志:另一类是容器日志.引擎日志一般都交给了系统日志,不同的操作系统会放在不同的位置.本文主要介绍容器日志,容器日志可以理解是运 ...

  4. 深入浅出ELK日志收集系统搭建

    先看一下目录图 背景 试想这么一种场景:Nginx负载了2个Tomcat,那么日志查看就很麻烦了,每次查看日志都要登录2台服务器,挨个搜索,2台还好,如果5台呢?10台呢?那查看日志就可费劲了,所以需 ...

  5. 基于filebeat + logstash的日志收集方案

    日志收集是一个很普遍的需求,各个服务的log日志,打点日志都需要收集起来做离线etl或实时分析.日志收集工具也有很多开源的可供选择,flume,  logstash, filebeat等等.  目前3 ...

  6. 看不到日志_Kubernetes中常用的日志收集方案

    在kubernetes中对日志的处理方式叫做cluster-level-logging,即这个日志处理系统跟容器,Pod,Node的生命周期无关,也就是无论是容器挂了,Pod被删除了还是Node宕机了 ...

  7. 借鉴开源框架自研日志收集系统

    踏浪无痕 岂安科技高级架构师 十余年数据研发经验,擅长数据处理领域工作,如爬虫.搜索引擎.大数据应用高并发等.担任过架构师,研发经理等岗位.曾主导开发过大型爬虫,搜索引擎及大数据广告DMP系统目前负责 ...

  8. python分布式日志收集系统_Go实现海量日志收集系统(一)

    项目背景 每个系统都有日志,当系统出现问题时,需要通过日志解决问题 当系统机器比较少时,登陆到服务器上查看即可满足 当系统机器规模巨大,登陆到机器上查看几乎不现实 当然即使是机器规模不大,一个系统通常 ...

  9. 探秘Hadoop生态12:分布式日志收集系统Flume

    这位大侠,这是我的公众号:程序员江湖.  分享程序员面试与技术的那些事. 干货满满,关注就送.  在具体介绍本文内容之前,先给大家看一下Hadoop业务的整体开发流程:  从Hadoop的业务开发流程 ...

最新文章

  1. 解题报告 『生活大爆炸版石头剪刀布(模拟)』
  2. 去除tableview中每个cell的分段线
  3. asm 查看 数据文件 修改 时间_更高效的GMX分段模拟方法:修改tpr文件
  4. 吴恩达《Machine Learning》精炼笔记 12:大规模机器学习和图片文字识别 OCR
  5. 2.7.3 ecshop php7.1_ECshop 迁移到 PHP7版本时遇到的兼容性问题
  6. request body 里丢东西了_26. Scrapy 框架-模拟登录-Request、Response
  7. windows数据自动上传服务器,windows服务器间自动传输文件
  8. php 图片合成,PHP中多张图片合成一张图片例子
  9. matlab帮助_【MATLAB】使用 APP DESIGNER 模块来帮助你做参数设计
  10. 谈谈你对c语言中数据(各种常量,变量,函数参数,字符串)的存储认识,自考《高级语言程序设计》知识点总结(二)...
  11. Python 中的注意点_s2
  12. Ceylon 1.0.0
  13. 一天一小段js代码(no.4)
  14. 《Python算法教程简及PDF电子版下载
  15. 太实用了!Schedule模块, Python 周期任务神器!
  16. PLC气动机械手控制系统毕业设计【附带仿真】
  17. oracle总结: INTERVAL DAY TO SECOND, 但却获得 NUMBER
  18. 如何利用树莓派制作路由器
  19. 清华大学计算机系研究生培养方案,攻读硕士学位研究生培养方案
  20. 仿得物微信小程序(动手就会,含源码)

热门文章

  1. 统计思维——通过统计方法解决分析问题
  2. 显示单月的日历c语言编程,显示单月的日历的C程序
  3. 快来,票字版软件电子发票的设置方式(详细流程)
  4. MFC详解显示BMP格式图片
  5. 知乎ajax采集,胖鼠采集WordPress插件教程-WP自动采集和发布简书,微信公众号,知乎等任意网站...
  6. keepass使用坚果云管理我的密码
  7. AIX PowerPC体系结构及其溢出技术学习笔记
  8. 计算机机房abc标准,ABC级数据中机房建设要求.doc
  9. Diskgenius恢复硬盘误删文件及数据
  10. flash保存html,如何把网页上的flash动画保存为swf格式文件(缓存提取)