flume详解

定义

flume全称Apache Flume

  • 技术角度:使用Java语言开发的一个分布式、高可靠、高可用中间件
  • 项目角度:最早是Cloudera提供的日志收集系统,现在是Apache软件基金会(ASF)的顶级项目,是Hadoop生态圈中的一个组件。当前Flume有两个版本Flume 0.9X版本的统称Flume-og,Flume1.X版本的统称Flume-ng。由于Flume-ng经过重大重构,与Flume-og有很大不同,使用时请注意区分。
  • 产品角度:用来收集、聚合、转移不同来源的大量日志数据到中央数据仓库的工具(Flume是一种日志采集工具)

官方文档:https://flume.apache.org/rele...
民间中文网:https://flume.liyifeng.org/

使用背景

为什么要进行日志数据采集?

在现在的数据技术时代中,数据有着不可替代的地位,抛开数据谈大数据服务就是瞎扯,没有数据作支撑的大数据平台就是一个空壳。数据是一切数据分析、数据挖掘、大数据处理、ai算法的核心。

在目前的来看,绝大多数公司或者组织做大数据处理时,他们的数据来源于:设备收集、数据库、日志、爬虫等等。

“只有在程序出问题以后才会知道打一个好的日志有多么重要”,因此现在许多公司的业务平台都有非常严格的日志规范,每天都会产生大量的日志数据,因此这些日志数据中就隐含着巨大的价值。

常用的日志数据采集工具

类型 Logstash Filebeat Flume Fluentd
运行环境 java go java ruby
资源环境 非常小
配置 简单 简单 较复杂 复杂
可靠性 不稳定 稳定 高可靠 可靠

初步认识并使用flume

用一个故事理解:有一个池子,它一头进水,另一头出水,进水口可以配置各种管子,出水口也可以配置各种管子,可以有多个进水口、多个出水口。水术语称为Event,进水口术语称为Source、出水口术语成为Sink、池子术语成为Channel,Source+Channel+Sink,术语称为Agent。如果有需要,还可以把多个Agent连起来。

flume详解_第1张图片

flume的名词详细介绍

  • Event
数据在flume内部是以Event封装的形式存在的。因此source组件在获取到原始数据后,需要封装成Event后发送到channel中,然后sink从channel取出Event后,根据配置要求再转成其他的形式进行数据输出。
Event封装的对象主要有两部分:Headers和Body;
Headers是一个集合Map类型,用于存储元数据(如标志、描述等)
Body就是一个字节数组,装载具体的数据内容

flume详解_第2张图片

  • agent
flume最核心的角色就是agent。flume日志采集系统是由一个个agent连接起来的数据传输通道。
对于每个agent来说就是一个独立的守护进程(JVM),它负责从数据源接收数据,并发送到下一个目的地。
agent内部有三个重要的组件:source,channel,sink
  • source
Source是数据的收集端,负责将数据捕获后进行特殊的格式化,将数据封装到事件(event) 里,然后将事件推入Channel中。并将接收的数据以Event的形式传递给一个或多个channel。Flume提供多种数据接收方式,比如直接读取本地文件,Avro,Thrift等。

flume详解_第3张图片

  • channel
channel是一种短暂的存储容器,它从source处接收到event格式数据后进行缓存,直到被消费掉。它在source和sink之间起到了桥梁作用,channel是一个完整的事务,这一点保障了数据在收发时的一致性,并且可以和任意数量的source和sink连接。
支持的类型有:FileSystem Channel,Memory channel,Kafka channel等。
  • sink
sink将数据存储到集中存储器比如Hbase和HDFS,它从channels消费数据(events)并将其传递给目标地. 目标地可能是另一个sink,也可能HDFS,HBase.

Flume启动基本上是基于本地配置文件的(遵循Java properties文件格式的文本文件),目前还有一个实验性的功能可以基于Zookeeper的在线配置。
基于以上这些,可以进行一个简单的demo,实时监控服务器/root/tmp.txt文件,将收集到的信息打印到控制台。

a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.type = TAILDIR
a1.sources.r1.channels = c1
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /root/tmp.txt

a1.channels.c1.type = memory

a1.sinks.k1.type = logger
a1.sinks.k1.channel = c1

flume启动命令bin/flume-ng agent -n a1 -c conf -f conf/example.conf -Dflume.root.logger=INFO,console

flume组件详解

Source配置

Source Desc
Avro Source 通过监听一个网络端口来接受数据,而且接受的数据必须是使用avro序列化框架序列化后的数据;
Thrift Source 通过监听一个网络端口来接受数据,而且接受的数据必须是使用thrift序列化框架序列化后的数据;
HTTP Source 监听一个网络端口,通过http post/get来接收数据,GET方式目前还只是实验性的;该source基于Jetty 9.4,可以解析为JSON或Blob
NetCat Source 监听一个网络端口,获取通过TCP或UDP协议的数据
Kafka Source Kafka Source就是一个Apache Kafka消费者,它从Kafka的topic中读取消息。 如果运行了多个Kafka Source,则可以把它们配置到同一个消费者组,以便每个source都读取一组唯一的topic分区。
Exec Source 启动一个用户所指定的linux shell命令;采集这个linux shell命令的标准输出,作为收集到的数据,转为event写入channel
Spooling Directory Source 监视一个指定的文件夹,如果文件夹下有没采集过的新文件,则将这些新文件中的数据采集,并转成event写入channel;注意:spooling目录中的文件必须是不可变的,而且是不能重名的!否则,source会loudly fail!
Taildir Source 监视指定目录下的一批文件,只要某个文件中有新写入的行,则会被tail到;它会记录每一个文件所tail到的位置,记录到一个指定的positionfile保存目录中,格式为json(如果需要的时候,可以人为修改,就可以让source从任意指定的位置开始读取数据);它对采集完成的文件,不会做任何修改
Syslog Sources 读取系统日志数据生成event。
JMS Source 从JMS目标(例如队列或主题)读取消息;作为JMS应用程序,它应可与任何JMS提供程序一起使用,但仅经过ActiveMQ的测试;注意,应该使用plugins.d目录(首选),命令行上的–classpath或通过flume-env.sh中的FLUME_CLASSPATH变量将提供的JMS jar包含在Flume类路径中
Stress Source StressSource 是一个内部负载生成Source的实现, 对于压力测试非常有用 。可以配置每个Event的大小(headers为空)、也可以配置总共发送Event数量以及发送成功的Event最大数量。
Custom Source 自定义source

Channel配置

Channel Desc
Memory Channel event存储在内存中,且可以配置最大值。对于需要高吞吐而且可以容忍数据丢失的情况下,可以选择该channel
File Channel event被缓存在本地磁盘文件中;可靠性高,不会丢失;
Kafka Channel agent利用kafka作为channel数据缓存;kafka channel要跟 kafka source、 kafka sink区别开来;kafka channel在应用时,可以没有source
JDBC Channel event被持久到数据库中,目前支持derby.适用于可恢复的场景
Spillable Memory Channel event存储在内存和磁盘上。内存充当主存储,磁盘充当溢出。这个channel目前是实验性的,不建议用于生产环境 。
Custom Channel 自定义channel

Sink配置

Sink Desc
Null Sink 直接丢弃
Logger Sink 数据输出到日志中,通常用于debug
File Roll Sink 数据存储到本地文件系统
HDFS Sink 数据被最终发往hdfs;可以生成text文件或 sequence 文件,而且支持压缩;支持生成文件的周期性roll机制:基于文件size,或者时间间隔,或者event数量;目标路径,可以使用动态通配符替换,比如用%D代表当前日期;当然,它也能从event的header中,取到一些标记来作为通配符替换
Hive Sink 可将text或json数据直接存储到hive分区表
HBaseSink 数据存储到hbase中
ElasticSearchSink 直接存储到es中
Kafka Sink 存储到kafka中
Kite Dataset Sink 将事件写入Kite数据集。该接收器将反序列化每个传入事件的主体,并将结果记录存储在Kite数据集中。它通过按URI加载数据集来确定目标数据集。(kite是专门来操纵大数据集的,可以通过kite将数据存储到hdfs、local、hive、hbase中,并且还提供了partition分区机制,加快数据访问速度。并且kite支持avro、parquet、csv、json等几种存储数据的方式。)
MorphlineSolrSink (Solr是一个独立的企业级搜索应用服务器)该接收器从Flume事件中提取数据,对其进行转换,并将其几乎实时地加载到Apache Solr服务器中,后者再为最终用户或搜索应用程序提供查询
Avro Sink avro sink用来向avro source发送avro序列化数据,这样就可以实现agent之间的级联
Thrift Sink 同avro sink
HTTP Sink 将接收到的数据通过post请求发生到远程服务,event内容作为请求体发送
IRC Sink 因特网中继聊天(Internet Relay Chat),一般称为互联网中继聊天,简称:IRC。它是由芬兰人Jarkko Oikarinen于1988年首创的一种网络聊天协议。
Custom Sink 自定义sink

拦截器 Interceptor

1635849972(1).png
拦截器,就是工作在source之后,可以从source获得event,做一个逻辑处理,然后再返回处理之后的event。这也就可以让用户不需要改动source代码的情况下,插入一些处理逻辑。学过java的同学对拦截器应该比较清楚了。具体类型如下:

Interceptor Desc
host 往event的header中插入主机名信息
timestamp 向event中,写入一个kv到header里;key的名称可以随意配置,value就是当前时间戳
uuid 用于在每个event header中生成一个uuid字符串
static静态属性写入拦截器 让用户往event中添加一个自定义的header,key-value形式的,当然这个kv在配置文件中是写死的
remove_header删除属性拦截器 这个拦截器可以删除Event header里面的属性,可以是一个或多个。
search_replace查找-替换拦截器 该拦截器基于Java正则表达式提供简单的基于字符串的搜索和替换功能;类似于Java中的Matcher.replaceAll方法
regex_filter正则过滤拦截器 这个拦截器会把Event的body当做字符串来处理,并用配置的正则表达式来匹配。可以配置指定被匹配到的Event丢弃还是没被匹配到的Event丢弃。
regex_extractor正则提取拦截器 这个拦截器会使用正则表达式从Event内容体中获取一组值并与配置的key组成n个键值对,然后放入Event的header中,Event的body不会有任何更改。
Morphline 实时清洗拦截器 此拦截器通过 morphline配置文件 过滤Event,配置文件定义了一系列转换命令,用于将记录从一个命令传递到另一个命令。
custom type as FQCN 自定义实现拦截器

Source通道选择器(Flume Channel Selectors)

flume详解_第4张图片

一个source可以对接多个channel,那么问题来了,source的数据是怎么在多个channel之间进行传递的呢?这就是selector的功能了,通过selector选择器根据策略可以将event从source传递到指定的channel中去。具体的selector选择器类型如下表格:

Selector Desc
replicating 复制选择器 默认的选择器,将event进行复制分发给下游所有的节点
Multiplexing 多路复用选择器 多路选择器,可以根据event中的一个指定key对应的value来决定这条消息会被写入到那个哪个channel中
Custom Selector 自定义选择器

Sink组逻辑处理器(Flume Sink Processors)

flume详解_第5张图片
一个agent中,多个sink可以被组装到一个组中,而数据在组内多个sink之间发送。接收处理器可以在组内提供负载均衡的功能,或者是在临时故障的情况下实现从一个接收器转移到另一个接收器上。具体的接收器模式见下表格:

Processor Desc
default 默认的接收处理器仅接受一个sink,当然用户也没有必要为了一个sink去创建processor
Failover 故障转移模式,即一个组内只有优先级高的sink在工作,而其他的sink处于等待中
load_balance 负载均衡模式,允许channel中的数据在一组sink中的多个sink之间进行轮转,具体的策略有:round-robin(轮流发送);random(随记发送)
Custom processor 目前还不支持自定义Sink组逻辑处理器

flume进阶

flume的高可靠性

事务是flume高可靠性的保证

首先我们先来了解一下消息传递的可靠性保证的三种方式:

  1. At-Least-Once
  2. At-Most-Once
  3. Exactly-Once

基本上所有工具的使用用户都希望工具框架能保证消息 Exactly-once ,这样就不必在设计实现上考虑消息的丢失或者重复的处理场景。但是事实上很少有工具和框架能做到这一点,真正能做到这一点所付出的成本往往很大,或者带来的额外影响反而让你觉得不值得。假设 Flume 真的做到了 Exactly-once ,那势必降低了稳定性和吞吐量,所以 Flume 选择的策略是 At-least-once 。
Flume采用的是At-Least-Once策略,这里并不是说Flume任意一个组件就可以实现这种策略,而是通过三个组件(source,channel,sink)之间上下投递消息来保证,但是如果选择了Memory Channel的话,这个就不敢打包票能实现At-Least-Once了。Flume要保障at-least-once的基础就是Transaction。

  • Source到Channel是事务性的
  • Channel到Sink也是事务性的

flume详解_第6张图片

flume的事务工作流:
flume详解_第7张图片

这里再详解一下上图的流程,Flume的transaction是有生命周期的,分别是start、commit、rollback和close.

当source往channel投递事件的时候,会首先调用start方法开启事务,将event怼入putList中,此时putList会包裹在一层事务中(为了数据传输的原子性),当putList的数据成绩怼入channel,进行事务commit确认,当putList中的数据怼入到channel失败的时候(通常表现为channel中的数据已满了,putList中的数据没办法在放进channel里面,这里需要责怪设定channel capacity的那个家伙),进行事务rollback回滚(会将当前的putList清空,source将刚才提交的消息事件向源头进行ack确认,需要上游具备消息重发功能),然后close事务。

sink消费channel也是同样的模式,唯一不同的地方是sink在往目标源完成写入后才会对事务进行commit,通常为下游的存储系统宕机导致信息无法发出,此时会执行事务回滚(会将当前的takeList清空,并将takeList的信息回滚到channel中,如果此时channel也是满的,直接报错)。

数据可能会重复

Flume 保证事件至少一次被送到它们的目的地,只有一次倾力写数据,且不存在任何类型的故障事件只被写一次。但是像网络超时或部分写入存储系统的错误,可能导致事件不止被写一次,因为Flume 将重试写操作直到它们完全成功。

flume的分布式

flume灵活的source和sink组件,使得多个agent之间可以进行数据通信,这也是flume扩展性和分布式的基础,可以支持大量的部署方案。Flume内置了专门的RPC sink-source对。对于agent-to-agent通信,首选的RPC sink-RPC source对是Avro Sink-Avro Source对。要从其它的Flume Agent或客户端接收数据,Agent接收数据可以被配置为使用Avro Source,且发送数据的Agent必须配置用来运行Avro Sink。

flume详解_第8张图片

日志收集场景中比较常见的是数百个日志生产者发送数据到几个日志消费者Agent上,然后消费者Agent负责把数据发送到存储系统。例如从数百个web服务器收集的日志发送到十几个Agent上,然后由十几个Agent写入到HDFS集群。

flume详解_第9张图片

日志生产者到日志消费者的数据传输通常使用负载均衡的方式提高整个集群的吞吐量和稳定性。

flume详解_第10张图片

如果生产时间的服务器数量持续增加,该层从应用程序服务器接收数据的agent数量也需要增加。这意味着在某种程度上,它可能需要增加后续层来增加缓冲容量,以适应数据产量的增加。

flume详解_第11张图片

Flume支持多路复用数据流到一个或多个目的地。这是通过使用一个流的[多路复用器](multiplexer)来实现的,它可以 复制 或者 选择(多路复用) 数据流到一个或多个channel上。

flume详解_第12张图片

使用flume的channel选择器可以根据需要将数据复制或分组发送到不同的目的地

flume详解_第13张图片

根据官方的建议:向HDFS发送数据的Agent数量尽量不要超过8个;上层和下层的数量比率不要超过32:1。

Flume真的适合你吗?
如果你需要将文本日志数据提取到Hadoop / HDFS中,那么Flume最合适不过了。但是,对于其他情况,你最好看看以下建议:
Flume旨在通过相对稳定,可能复杂的拓扑部署来传输和收集定期生成的Event数据。“Event数据”定义非常广泛,对于Flume来说一个Event就是一个普通的字节数组而已。 Event大小有一些限制,它不能比你的内存或者服务器硬盘还大,实际使用中Flume Event可以是文本或图片的任何文件。关键的是这些Event应该是以连续的流的方式不断生成的。 如果你的数据不是定期生成的(比如你将大量的数据批量加载到Hadoop集群中),虽然Flume可以做这个事情,但是有点“杀鸡用牛刀”的感觉,这并不是Flume所擅长和喜欢的工作方式。 Flume喜欢相对稳定的拓扑结构,但也不是说永远一成不变,Flume可以处理拓扑中的更改而又不丢失数据,还可以处理由于故障转移或者配置的定期重新加载。如果你的拓扑结构每天都会变动, 那么Flume可能就无法正常的工作了,毕竟重新配置也是需要一定思考和开销的。

Flume的拓扑设计

FLume的监控

Flume作为一个强大的数据收集工具,虽然功能非常强大实用,但是却无法看到flume收集数据的详细信息,所以我们需要一个能展示flume实时收集数据动态信息的界面,包括flume成功收集的日志数量、成功发送的日志数量、flume启动时间、停止时间、以及flume一些具体的配置信息,像通道容量等,于是顺利成章的监控能帮我们做到这些,有了这些数据,在遇到数据收集瓶颈或者数据丢失的时候,通过分析监控数据来分析、解决问题。

source监控项:

指标项 说明
OpenConnectionCount 目前与客户端或sink保持连接的总数量
AppendBatchAcceptedCount 成功提交到channel的批次的总数量
AppendBatchReceivedCount 接收到事件批次的总数量
AppendAcceptedCount 逐条录入的次数
AppendReceivedCount 每批只有一个事件的事件总数量
EventAcceptedCount 成功写出到channel的事件总数量
EventReceivedCount 目前为止source已经接收到的事件总数量
StartTime source启动时的毫秒值时间
StopTime source停止时的毫秒值时间,为0表示一直在运行

channel监控项:

指标项 说明
EventPutAttemptCount Source尝试写入Channe的事件总次数
EventPutSuccessCount 成功写入channel且提交的事件总次数
EventTakeAttemptCount sink尝试从channel拉取事件的总次数
EventTakeSuccessCount sink成功从channel读取事件的总数量
ChannelSize 目前channel中事件的总数量
ChannelCapacity channel的容量
ChannelFillPercentage channel已填入的百分比
StartTime channel启动时的毫秒值时间
StopTime channel停止时的毫秒值时间,为0表示一直在运行

sink监控项:

指标项 说明
ConnectionCreatedCount 创建的连接数量
ConnectionClosedCount 关闭的连接数量
ConnectionFailedCount 由于错误关闭的连接数量
BatchEmptyCount 批量处理event的个数为0的数量-表示source写入数据的速度比sink处理数据的速度慢
BatchUnderflowCount 批量处理event的个数小于批处理大小的数量
BatchCompleteCount 批量处理event的个数等于批处理大小的数量
EventDrainAttemptCount sink尝试写出到存储的事件总数量
EventDrainSuccessCount sink成功写出到存储的事件总数量
StartTime channel启动时的毫秒值时间
StopTime channel停止时的毫秒值时间,为0表示一直在运行
  • JMX Reporting
    Java 管理扩展(Java Management Extension,JMX)是从jdk1.4开始的,但从1.5时才加到jdk里面,并把API放到java.lang.management包里面。MX监控可以通过在flume-env.sh脚本中修改JAVA_OPTS环境变量中的JMX参数来开启
    如果一个 Java 对象可以由一个遵循 JMX 规范的管理器应用管理,那么这个Java 对象就可以称为一个可由 JMX 管理的资源。
  • JSON Reporting
    Flume也支持以JSON格式报告运行指标。为了对外提供这些报告数据,Flume会在某个端口(可自定义)上运行一个web服务来提供这些数据。
    flume详解_第14张图片
  • Ganglia Reporting
    Ganglia是UC Berkeley发起的一个开源集群监视可视化工具,设计用于测量数以千计的节点。Ganglia的核心包含gmond、gmetad以及一个Web前端。主要是用来监控系统性能,如:cpu 、mem、硬盘利用率, I/O负载、网络流量情况等,通过曲线很容易见到每个节点的工作状态,对合理调整、分配系统资源,提高系统整体性能起到重要作用。
    flume详解_第15张图片
  • Custom Reporting
    可以通过编写自己的执行报告服务向其他系统报告运行指标。 报告类必须实现org.apache.flume.instrumentation.MonitorService 接口。

项目实践

kafka集群作为channel的方案

Memory Channel 有很大的丢数据风险,而且容量一般,File Channel 虽然能缓存更多的消息,但如果缓存下来的消息还没写入 Sink,此时 Agent 出现故障则 File Channel 中的消息一样不能被继续使用,直到该 Agent 恢复。而 Kafka Channel 容量大,容错能力强。

有了 Kafka Channel 可以在日志收集层只配置 Source 组件和 Kafka 组件,不需要再配置 Sink 组件,减少了日志收集层启动的进程数,有效降低服务器内存、磁盘等资源的使用率。而日志汇聚层,可以只配置 Kafka Channel 和 Sink,不需要再配置 Source。

  • 业务代码中实时发送日志

flume详解_第16张图片

  • 业务服务器安装flume读取本地日志文件,发送日志

flume详解_第17张图片

flume Collector配置文件:

# Name the components on this agent
a1.sources = r1
# a1.sinks = k1
a1.channels = c1

# Describe/configure the source 
a1.sources.r1.type = avro
a1.sources.r1.channels = c1
a1.sources.r1.bind = node4
a1.sources.r1.port = 4444

a1.channels.c1.type = org.apache.flume.channel.kafka.KafkaChannel
a1.channels.c1.kafka.bootstrap.servers = node1:9092,node2:9092,node3:9092
a1.channels.c1.kafka.topic = testflume
a1.channels.c1.kafka.consumer.group.id = test-consumer-group

a1.sources.r1.channels = c1

本地读取文件发送flume Collector的配置文件:

# Name the components on this agent
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1

# Describe/configure the source 
a1.sources.r1.type = TAILDIR
a1.sources.r1.positionFile = ./taildir_position.json
a1.sources.r1.filegroups = f1 f2
a1.sources.r1.filegroups.f1 = /root/tmp1.txt
a1.sources.r1.filegroups.f2 = /root/tmp2.txt
a1.sources.r1.fileHeader = false
a1.sources.r1.batchSize = 1
a1.sources.r1.channels = c1

a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

a1.sinks.k1.type = avro
a1.sinks.k1.hostname = node4
a1.sinks.k1.port = 4444
a1.sinks.k1.channel = c1

a1.sinks.k2.type = avro
a1.sinks.k2.hostname = node5
a1.sinks.k2.port = 4444
a1.sinks.k2.channel = c1

a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = load_balance
a1.sinkgroups.g1.processor.selector = random

Logback配置flume

业务系统中向flume发送日志通常要结合日志框架(Log4j、Logback等)一起使用,SpringBoot天生自带logback,我们这里只需要引入一个logback-flume依赖即可。


  com.teambytes.logback
  logback-flume-appender_2.10
  0.0.9

然后在logback的配置文件中进行相关配置:
添加一个appender,配置向flume发送消息的相关信息,配置多个flumeAgent时默认会使用负载均衡的方式进行发送


    
        192.168.197.130:4444,192.168.197.131:4444
    
    
        connect-timeout=4000;
        request-timeout=8000
    
    100
    1000
    
        myHeader = myValue
    
    wk's Application
    
        %d{HH:mm:ss.SSS} %-5level %logger{36} - \(%file:%line\) - %message%n%ex
    

然后启用这个appender即可


    
    

你可能感兴趣的:(flume详解)