大数据学习之Flume篇——未完待续

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wanghantong/article/details/84311272

Flume作为现在最常用的日志收集工具之一,目前已经更新到了1.8.0版本,我们以最新版本开始进行我们的学习。整个学习过程以官方文档为主,辅助是参考了SteveHoffman编写的《Flume日志收集与MapReduce模式》一书。

首先要明确几个定义: Source、Channel、Sink
Source:源;表示我们收集日志的数据源
Channel:通道;表示数据传输过程中途径的通道,我们可以在源到Sink中间进行一些处理操作
Sink:目的地;表示我们需要最终要将收集到的日志输出到的地方

Flume官方支持的几种常见Source的实现:(这里面我只详细写了我应用过/测试过的Source类型)

  1. Avro Source:Avro Netty RPC event source
  2. exec Source:Execute a long-lived Unix process and read from stdout
  3. Thrift Source
  4. JMS Source
  5. Spooling Directory Source:
  6. Taildir Source
  7. Twitter 1% firehose Source
  8. Kafka Source
  9. NetCat TCP Source
  10. NetCat UDP Source
  11. Sequence Generator Source
  12. Syslog Sources
  13. HTTP Source
  14. Stress Source
  15. Legacy Sources
  16. Custom Source
  17. Scribe Source

Flume官方支持的几种常见Sink的实现:

  1. Flume Sinks
  2. HDFS Sink
  3. Hive Sink
  4. Logger Sink
  5. Avro Sink
  6. Thrift Sink
  7. IRC Sink
  8. File Roll Sink
  9. Null Sink
  10. HBaseSinks
  11. HBaseSink
  12. AsyncHBaseSink
  13. MorphlineSolrSink
  14. ElasticSearchSink
  15. Kite Dataset Sink
  16. Kafka Sink
  17. HTTP Sink
  18. Custom Sink

Flume官方支持的Channel的实现:

  1. Flume Channels
  2. Memory Channel
  3. JDBC Channel
  4. Kafka Channel
  5. File Channel
  6. Spillable Memory Channel
  7. Pseudo Transaction Channel
  8. Custom Channel

我用过的几种组合:

  • Spooldir / Exec / Avro Source + Memory Channel + Kafka Sink

了解Flume基本的组成之后,我以实际的业务场景为例来讲述最终如何落地实践,(关于Flume运维的知识我们放在最后讲)我们现在就以单点为基础,目的是让大家快速的了解、实践。

项目背景: 目前公司整体架构采用的微服务架构、分布式部署,各个业务由多个服务组成,由于业务的不断迭代和复杂性日益加深,在各个服务调用的逻辑上越来越难梳理,排查问题也越来越困难(有人会说,不是可以做分布式跟踪吗?这个应该是微服务架构生态下所具备的一个功能啊),但是由于企业的快速发展,这部分建设并不完善,也就是没有对应的平台来支持,同时类似于阿里系的APM应用级的监控,也并不能完全解决我们日常迭代中的需要,因为们可能需要的时候更多的是业务日志,也就是服务内部处理过程中对数据操作的日志,这部分需要开发同学自主的去记录。那么我们现在就需要这样一个平台/环境来对这部分日志进行收集、清洗、展示,来辅助我们开发同学定位、排查问题,帮助测试同学提升测试效率,做到尽可能的全面覆盖。

技术选型:在方案调研期间,曾经考虑过多种,结合实际场景分析,期望对业务日志直接使用,并且尽可能的减少对RD代码的修改工作。现有的日志记录分为两种:1.log4j 2.IO写文件(不要追问为什么…遗留问题…);于是各种方案应运而生:

  1. Flume基于文件目录的模式对日志文件进行收集
  2. 使用Exec + tail 模式对日志文件监听,实时收集
  3. 使用log4j2直接分发至Flume的Avro源,实时收集

下面分析一下为什么选择了这几种方案: (最终没有采用Flume,后面会讲,当前只是结合讲解Flume的使用)
第一种方案是最直接的也就是不用动脑子的,也是最容易的;
参考配置:

第一种方案分析:此时Flume会监控指定的目录文件,也就是说当有日志文件产生的时候,Flume就会读取数据,并在完成时修改文件状态或者删除(加标识表示已经处理完成),但是这样会影响真实业务的数据日志记录,如果说是隔日提取,这种方案是可以的,也就是说提取的是前一天或者N天的数据,原因是我们一般都是按天+文件大小去记录日志的。所以这种方案想做实时被Pass了。

第二种方案是在第一种方案失败后想到的,因为想做实时,那么就用了tail -f的模式:
参考配置:

第二种方案分析:虽然表面上完成了实时日志的收集,但是存在着大量的隐患工作,我们在查阅官方文档时方向,Flume已经摒弃了这种tail模式,从而衍生出了exec + tail 模式,但是这样依旧会存在线程后台存活的问题,也就是说当tail -f这个线程出现异常或者Flume代理关闭或者重启时,派生出来的进程不能保证100%关闭,就会产生永不退出的孤立tail进程,那么其占用的系统资源就一直无法被释放,根据定义,tail -f是没有结束的,即使是删掉了被tail的文件,运行中的tail进程也会一直开启该文件句柄,直至系统资源被耗尽。在官方文档中,明确的指出:非常不建议使用该模式,可能会引发未知的灾难。

第三种方案分析: 能否让日志直接写入Flume的Agent呢?这样就可以解决实时的问题,又不会带来额外的风险。答案是可以的,Log4J2已经支持了这种模式,此时就需要在log4j2上做了配置了,这种方案的利弊又是如何呢?
log4j2参考配置如下:
A sample FlumeAppender configuration that is configured with a primary and a secondary agent using Flume configuration properties, compresses the body, formats the body using RFC5424Layout and passes the events to an embedded Flume Agent.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" name="MyApp" packages="">
  <Appenders>
    <Flume name="eventLogger" compress="true" type="Embedded">
      <Property name="channels">file</Property>
      <Property name="channels.file.type">file</Property>
      <Property name="channels.file.checkpointDir">target/file-channel/checkpoint</Property>
      <Property name="channels.file.dataDirs">target/file-channel/data</Property>
      <Property name="sinks">agent1 agent2</Property>
      <Property name="sinks.agent1.channel">file</Property>
      <Property name="sinks.agent1.type">avro</Property>
      <Property name="sinks.agent1.hostname">192.168.10.101</Property>
      <Property name="sinks.agent1.port">8800</Property>
      <Property name="sinks.agent1.batch-size">100</Property>
      <Property name="sinks.agent2.channel">file</Property>
      <Property name="sinks.agent2.type">avro</Property>
      <Property name="sinks.agent2.hostname">192.168.10.102</Property>
      <Property name="sinks.agent2.port">8800</Property>
      <Property name="sinks.agent2.batch-size">100</Property>
      <Property name="sinkgroups">group1</Property>
      <Property name="sinkgroups.group1.sinks">agent1 agent2</Property>
      <Property name="sinkgroups.group1.processor.type">failover</Property>
      <Property name="sinkgroups.group1.processor.priority.agent1">10</Property>
      <Property name="sinkgroups.group1.processor.priority.agent2">5</Property>
      <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
    </Flume>
    <Console name="STDOUT">
      <PatternLayout pattern="%d [%p] %c %m%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Logger name="EventLogger" level="info">
      <AppenderRef ref="eventLogger"/>
    </Logger>
    <Root level="warn">
      <AppenderRef ref="STDOUT"/>
    </Root>
  </Loggers>
</Configuration>

上述的三种配置Channel都是基于内存的模式,这是为了保证传输速度,当然现在固态硬盘的速度已经很快了,用文件的模式也是可以的,而我在使用的时候,由于偷懒,只使用了内存的通道。

​​​​​​​

展开阅读全文

没有更多推荐了,返回首页