1、Flume架构
Flume架构的三个部分:Client、Agent、Event
1.1 Agent:
是Flume的代理,是一个JVM进程,承载组件(Source、Channel、Sink等等),事件Event通过组件从外部源流向下一个目标
1.2 Event:
定义:数据流的一个单元,通常对应一行数据
源码中,是由Map结构的headers和一个字节数组的body组成
Event是数据流的数据对象,Flume数据流描述了数据从产生、传输、处理、最终写入目标的一条路径。
1.3 Client:
客户端,数据产生的地方,比如说:Web服务器(网页上用户行为信息记录的地方)
2、Flume特性
2.1 可靠性
- 在把收集来的数据送到目的地之前,缓存数据
- 使用事务性的方式保证Event会被成功存储,保障可靠性。
- Sink在Events被成功存入在Channel后、或已经成功传到下一个Agent里、或已经成功被存入外部数据目的地之后,才会remove掉缓存的Channel
2.2 可恢复性
- Events在通道中执行,由对应通道 来管理失败任务的恢复
- 分为本地文件系统支持的持久稳健通道和内存通道。内存通道把Events存储在内存队列中速度快,但Agent死亡后,内存通道中的任何Events无法恢复
2.3 可靠性保证(面试)
2.3.1 故障转移
- 故障转移组逻辑处理器维护了一个发送Event 失败的 sink 的列表,保证有一个 sink 是可用的来发送 Event。
- 故障转移机制的工作原理是将故障 Sink 降级到一个池中,在池中为它们分配冷却期(超时时间),在重试之前随顺序故障而增加。 Sink 成功发送事件后,它将恢复到实时池。Sink 具有与之相关的优先级,数值越大,优先级越高。 如果在发送Event 时Sink 发生故障,会继续尝试下一个具有最高优先级的 Sink。例如,在优先级为 80 的 Sink 之前激活优先级为 100 的 Sink。如果未指定优先级, 则根据配置中的顺序来选取。
- 要使用故障转移选择器,不仅要设置 Sink 组的选择器为failover,还有为每一个 Sink 设置一个唯一的优先级数值。可以使用 maxpenalty 属性设置故障转移时间的上限(毫秒)。
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2 #Sink 组逻辑器
a1.sinkgroups.g1.processor.type = failover
#组内 sink 的权重值,<sinkName>必须是当前组关联的 sink 之一。数值(绝对值)越高越早被激活
a1.sinkgroups.g1.processor.priority.k1 = 5
a1.sinkgroups.g1.processor.priority.k2 = 10
#发生异常的 sink 最大故障转移时间(默认 30000 毫秒)
a1.sinkgroups.g1.processor.maxpenalty = 10000
2.3.2 负载均衡
- 负载均衡 Sink 选择器提供了在多个 Sink 上进行负载均衡流量的功能。 它维护一个活动Sink 列表的索引来实现负载的分配。默认支持了轮询(round_robin) 和随机(random)两种选择机制分配负载。 默认是轮询,可以通过配置来更改。也可以从 AbstractSinkSelector 继承写一个自定义的选择器。
- 工作时,此选择器使用其配置的选择机制选择下一个 Sink 并调用它。 如果所选 Sink 无法正常工作,则处理器通过其配置的选择机制选择下一个可用 Sink。此实现不会将失败的 Sink 列入黑名单,而是继续乐观地尝试每个可用的 Sink。
- 如果所有 Sink 调用都失败了,选择器会将故障抛给 Sink 的运行器。
- 如果 backoff 设置为 true 则启用了退避机制,失败的Sink 会被放入黑名单, 达到一定的超时时间后会自动从黑名单移除。如从黑名单出来后Sink 仍然失败, 则再次进入黑名单而且超时时间会翻倍,以避免在无响应的 Sink 上浪费过长时间。 如果没有启用退避机制,在禁用此功能的情况下,发生Sink 传输失败后,会将本次负载传给下一个 Sink 继续尝试,因此这种情况下是不均衡的。
a1.sinkgroups = g1 a1.sinkgroups.g1.sinks = k1 k2 #Sink 组逻辑器
a1.sinkgroups.g1.processor.type = load_balance
#失败的 sink 是否成倍地增加退避它的时间。
a1.sinkgroups.g1.processor.backoff = true
#负载均衡机制,可选值:round_robin (轮询)、 random (随机选择)、「自定义选择器的全限定类名」
a1.sinkgroups.g1.processor.selector = random
2.3.3 多层代理
- 当我们用 Flume 采集日志时,由于数据源的多样性,则往往需要配置多个Flume 进行采集,如果只是使用单层 Flume 的话,那么往往会产生很多个文件夹, 单个文件夹也只是来自同一个节点的数据组成的。而实际开发中,为了减少HDFS 的压力,同时提高后续 MR 的处理效率。往往会将同一组多个节点的数据汇聚到同一个文件中,这样同时也较少了数据从生产到分析的时间。
- 如下图,第一次 agent 负责采集原始数据,第二层 agent 负责对第一层数据进行汇聚。这种多层代理的方式尤其适合 source 源数据量庞大的时候,效率会高很多。
2.3.4 多路复用
如果没有手动配置,source 的默认 channel 选择器类型是 replicating(复制),当然这个选择器只针对 source 配置了多个 channel 的时候。前面介绍过,一个source 可以向多个 channel 同时写数据,所以也就产生了以何种方式向多个channel 写的问题(比如自带的复制选择器 ,会把数据完整地发送到每一个channel,而多路复用选择器 就可以通过配置来按照一定的规则进行分发,听起来很像负载均衡),channel 选择器也就应运而生。
复制选择器
#c3 配置成了可选的。向 c3 发送数据如果失败了会被忽略。
c1 和 c2 没有配置成可选的,向 c1 和 c2 写数据失败会导致事务失败回滚。
a1.sources = r1 a1.channels = c1 c2 c3
a1.sources.r1.selector.type = replicating a1.sources.r1.channels = c1 c2 c3
a1.sources.r1.selector.optional = c3 #向 c3 发送失败将忽略
多路复用选择器
a1.sources = r1 a1.channels = c1 c2 c3 c4
a1.sources.r1.selector.type = multiplexing
#以每个 Event 的 header 中的 state 这个属性的值作为选择 channel 的依据
a1.sources.r1.selector.header = state
#如果 state=CZ,则选择 c1 这个 channel a1.sources.r1.selector.mapping.CZ = c1
#如果 state=US,则选择 c2 和 c3 这两个 channel a1.sources.r1.selector.mapping.US = c2 c3
#默认使用 c4 这个 channel,如果没有被规则匹配到,默认会发到此 channel
a1.sources.r1.selector.default = c4
3、Flume原理
3.1主要组件及其作用
Source、Channel 及 Sink 为核心组件
3.1.1 source
- 可以理解为进入形式,也就是数据将通过怎样的一种形式进入,比较常用的为Taildr Source(可以断点续传,优化很好)
3.1.2 channel
- 通道,也就是source在将文件传给Sink时的临时缓冲区,分为内存和落盘两种形式,如果在内存中,agent挂掉的话有可能会丢失数据
3.1.3 Sink
- 出水口,也就是数据流出的形式,一般我们放在hdfs上的话就用hdfs sink
以上三点即是flume的主要整体架构,也就是jvm中的一个进程
综上所述,flume的作用就是监视给定的一片地方,这个地方一单有数据进来,我们就通过source,channel,sink等过程写入到hdfs中,形成流式数据存储。
完整组件包括: Source 、SourceRunner 、Interceptor 、Channel 、ChannelSelector 、ChannelProcessor、Sink,SinkRunner、SinkProcessor、SinkSelector。
3.2 各组件作用如下
3.2.1 Source相关
-
Source:用来获取 Event 并写入 Channel。
-
SourceRunner:SourceRunner 则负责启动 Source,一个 SourceRunner 包含一个 Source 对象。
-
Interceptor:(过滤器的意思?)即为拦截器,是简单的插件式组件,设置在 Source 和 Channel 之间。Source 接收到的事件Event,在写入 Channel 之前,拦截器都可以进行转换或者删除这些事件。每个拦截器只处理同一个 Source 接收到的事件。可以自定义拦截器。
3.2.2 Channel相关
- Channel:中转 Event 的一个临时存储,保存有 Source 组件传递过来的Event,可以认为是一个队列。
- ChannelSelector:作用是为 Source 选择下游的 Channel。有两种选择方式,复制和多路复用(面试)。所谓复制就是把 Source 中传递过来的 Event 复制给所有对应的下游的 Channel。多路复用是可以把 Source 传递过来的 Event 按照不同的属性传递到不同的下游 Channel 中去。
- ChannelProcessor:通过 ChannelSelector 获取到 Channels 后,如何发送Event 到 Channel。一个 Source 对象包含一个 ChannelProcessor 对象,一个ChannelProcessor 对象包含多个Interceptor 对象和一个ChannelSelector 对象。如下图所示。
3.2.3 Sink相关
- Sink:从 Channel 中读取并移除 Event,将 Event 传递到 Flow Pipeline 中的下一个 Agent 或者其他存储系统。一个 SinkRunner 对象包含一个SinkProcessor 对象, 一个 SinkProcessor 包含多 个 Sink 或者一个SinkSelector。
- SinkRunner:负责启动 Sink。在 Agent 启动时,会同时启动 Channel, SourceRunner,SinkRunner,如下图所示。
- SinkProcessor : Flume 提 供 FailoverSinkProcessor 和LoadBalancingSinkProcessor,顾名思义,一个是失效备援,一个是负载均衡,那么 SinkProcessor 不同子类的存在就是为了实现不同的分配操作和策略,而 sink 的 start()通常是启动线程去执行消费操作。
- SinkSelector : LoadBalancingSinkProcessor 包含 SinkSelector , 会根据SinkSelector 在 SinkGroup(逻辑上的一组 Sink)中选择 Sink 并启动。从源码中可看出,其为 LoadBalancingSinkProcessor 的内部接口。如下图所示。
3.3 Flume工作流程
下面从两个阶段分别描述。
3.3.1Source->Channel
数据由 Source 写入 Channel,主动模式,主要步骤如下:
- 1)SourceRunner 启 动 Source,Source 接 收 Event;
- 2)Source 调用 ChannelProcessor;
- 3)ChannelProcessor 调 用 Interceptor 进 行 过 滤 Event 操 作 ;
- 4)ChannelProcessor 调用 ChannelSelector 对象根据配置的策略选择 Event 对应的 Channel(replication 和 multiplexing 两种);
- 5)Source 将 Event 发送到对应的 Channel 中。
3.3.2 Channel->Sink
数据由 Sink 主动从 Channel 中拉取:
- 1)SinkRunner 启动 SinkProcesso(r DefaultSinkProcessor,FailoverSinkProcessor,LoadBalancingSinkProcessor 3 种);
- 2)如果是 DefaultSinkProcessor 的话,直接启动单个 Sink;
- 3)FailoverSinkProcessor,LoadBalancingSinkProcessor 对应的是 SinkGroup;
- 4)FailoverSinkProcessor 从 SinkGroup 中选择出 Sink 并启动;
- 5)LoadBalancingSinkProcessor 包含 SinkSelector , 会根据 SinkSelector 在SinkGroup 中选择 Sink 并启动;
- 6) Sink 从 Channel 中消费 Event 信息。
3.3.3Flume 工作流程图
4、核心常用组件
4.1 Source
4.1.1 Exec Source
Exec Source 在启动时运行一个给定的 Unix 命令,并期望该进程不断地在标准输出上产生数据。
4.1.2 Spooling Directory Source
该 Source 将监视指定目录的新文件,一旦有新文件产生立即解析它们。将给定的文件完全读入 Channel 后,默认情况下通过重命名该文件来表示完成,或者可以删除该文件,或者使用 trackerDir 跟踪已处理的文件。
4.1.3 Avro Source
监听Avro 端口并从外部Avro 客户端流接收事件。当与另一个(前一跳)Flume Agent 上的 Avro Sink 一起使用时,它可以创建分层收集拓扑。
4.1.4 Netcat Source(TCP)
一个类似 netcat 的源,它监听给定的端口并将每行文本转换成一个事件。就像 nc -k -l主机。换句话说,它打开指定的端口并侦听数据。期望提供的数据是换行分隔的文本。每行文本被转换成一个 Flume 事件并通过连接的通道发送。
4.1.5 Taildir Source
Taildir Source 监控指定的一些文件,并在检测到新的一行数据产生的时候实时地读取它们,如果新的一行数据还没写完,Taildir Source 会等到这行写完后再读取。
- Taildir Source 可以从任意指定的位置开始读取文件。默认情况下,它将从每个文件的第一行开始读取。
- 文件按照修改时间的顺序来读取。修改时间最早的文件将最先被读取(简单记成:先来先走)。
- Taildir Source 不重命名、删除或修改它监控的文件。
- 当前不支持读取二进制文件。只能逐行读取文本文件。
- Taildir Source 目前不能运行在windows 系统上。
4.2 Channel
Channel 接口中主要声明了 Channel 中的三个方法:
-
put 方法从指定的 Source 中获得 Event 放入指定的 Channel 中
#public void put(Event event) throws ChannelException;
-
take 方法主要是从 Channel 中取出 event 放入 Sink 中
#public Event take() throws ChannelException;
-
getTransaction 方法是获得当前 Channel 的事务实例
#public Transaction getTransaction();
常用的 Channel 有:
4.2.1 Memory Channel
event 保存在指定大小的内存队列中,高吞吐量。如果允许数据小量丢失, 推荐使用。type设置“memory”
4.2.2 File Channel
event 保存在本地文件中写入磁盘,可靠性高,容量大,不会丢失文件,但吞吐量低于 Memory Channel。type设置“file”
4.2.3 Kafka Channel
event 保存在 Kafka 中。Kafka 提供了高可用性和可复制性,所以当 Flume Agent 或 Kafka broker 崩溃时,event 可以提供给其他Sinks。
4.2.4 JDBC Channel
event 保存在关系数据中,一般不推荐使用。
4.3 Sink
Sink 用于消费 Channel 中的 Event。在 Channel 的事务中进行处理,在成功交付时提交事务,在失败时回滚事务。
注意:一个 Sink 只能消费一个 Channel 的 Event。
4.3.1 Logger Sink
记录 INFO 级别的日志,一般用于调试。要求必须在“–conf”参数指定的目录下有 log4j 的配置文件,可以通过“-Dflume.root.logger=INFO,console”在命令启动时手动指定 log4j 参数。
Logger Sink 是唯一不需要额外配置的组件
4.3.2 HDFS Sink
HDFS Sink 将 Event 写入 Hadoop 分布式文件系统 HDFS。目前支持创建文本和序列文件。支持两种文件类型的压缩。可以根据写入的时间、文件大小或Event 数量定期滚动文件(关闭当前文件并创建新文件)。 它还可以根据 Event自带的时间戳或系统时间等属性对数据进行分区。存储文件的 HDFS 目录路径可以使用格式转义符,会由 HDFS Sink 进行动态地替换,以生成用于存储 Event的目录或文件名。 使用此 Sink 需要安装 Hadoop,以便 Flume 可以使用 Hadoop的客户端与 HDFS 集群进行通信。
4.3.3 Hive Sink
此 Sink 将包含分隔文本或 JSON 数据的 Event 直接流式传输到 Hive 表或分区上。 Event 使用 Hive 事务进行写入,一旦将一组 Event 提交给 Hive,它们就会立即显示给 Hive 查询。
即将写入的目标分区既可以预先自己创建,也可以选择让 Flume 创建它们。
写入的 Event 数据中的字段将映射到 Hive 表中的相应列。
4.3.4 HBase Sink
此 Sink 将数据写入 HBase。 Hbase 配置是从 classpath 中遇到的第一个hbase-site.xml 中获取的。 配置指定的 HbaseEventSerializer 接口的实现类用于将Event 转换为 HBase put 或 increments。然后将这些 put 和 increments 写入 HBase。
该 Sink 提供与 HBase 相同的一致性保证,HBase 是当前行的原子性。如果 Hbase无法写入某些 Event,则 Sink 将重试该事务中的所有 Event
4.3.5 Avro Sink
这个 Sink 可以作为 Flume 分层收集特性的下半部分。发送到此 Sink 的Event 将转换为 Avro Event 发送到指定的主机/端口上。Event 从 Channel 中批量获取,数量根据配置的 batch-size 而定。
4.4 拦截器
Flume 支持在运行时对 Event 进行修改或丢弃,可以通过拦截器来实现。Flume 里面的拦截器是实现了 org.apache.flume.interceptor.Interceptor 接口的类。拦截器可以根据开发者的意图随意修改甚至丢弃 Event, Flume 也支持链式的拦截器执行方式,在配置文件里面配置多个拦截器就可以了。
拦截器的顺序取决于它们被初始化的顺序(实际也就是配置的顺序),Event就这样按照顺序经过每一个拦截器,如果想在拦截器里面丢弃 Event, 在传递给下一级拦截器的 list 里面把它移除就行了。如果想丢弃所有的 Event,返回一个空集合就行了。
提示:Event 在拦截器之间流动的时候是以集合的形式,并不是逐个 Event 传输的,这样就能理解上面所说的“从 list 里面移除”、“返回一个空集合”了。做过Java web 开发的应该很容易理解拦截器,Flume 拦截器与spring MVC、struts2等框架里面的拦截器思路十分相似。
拦截器也是通过命名配置的组件
5、企业真实面试题(重点)
5.1 你是如何实现 Flume数据传输的监控的
使用第三方框架 Ganglia 实时监控 Flume。
5.2 Flume的 Source,Sink,Channel 的作用?你们 Source是什么类型?
- 1) Source 组件是专门用来收集数据的,可以处理各种类型、各种格式的日志数据, 包括 avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy
- 2) Channel 组件对采集到的数据进行缓存,可以存放在 Memory 或File 中。
- 3) Sink 组件是用于把数据发送到目的地的组件,目的地包括HDFS、Logger、avro 、thrift、ipc、file、Hbase、solr、自定义。
我公司采用的 Source 类型为
- 1) 监控后台日志:exec
- 2) 监控后台产生日志的端口:netcat Exec spooldir
5.3 Flume的 Channel Selectors
5.4 Flume 参数调优
5.4.1 Source
- 增加 Source 个(使用Tair Dir Source 时可增加FileGroups 个数)可以增大 Source 的读取数据的能力。例如:当某一个目录产生的文件过多时需要将这个文件目录拆分成多个文件目录,同时配置好多个Source 以保证 Source 有足够的能力获取到新产生的数据。
- batchSize 参数决定 Source 一次批量运输到 Channel 的 event 条数,适当调大这个参数可以提高Source 搬运Event 到Channel 时的性能。
5.4.2 Channel
- type 选择 memory 时Channel 的性能最好,但是如果 Flume 进程意外挂掉可能会丢失数据。type 选择 file 时 Channel 的容错性更好,但是性能上会比 memory channel 差。
- 使用 file Channel 时dataDirs 配置多个不同盘下的目录可以提高性能。
- Capacity 参数决定Channel 可容纳最大的event 条数。transactionCapacity 参数决定每次 Source 往 channel 里面写的最大 event 条数和每次 Sink 从 channel 里面读的最大 event 条数。\transactionCapacity 需要大于 Source 和 Sink 的 batchSize 参数。
5.4.3 Sink
- 增加 Sink 的个数可以增加 Sink 消费 event 的能力。Sink 也不是越多越好够用就行,过多的 Sink 会占用系统资源,造成系统资源不必要的浪费。
- batchSize 参数决定 Sink 一次批量从 Channel 读取的 event 条数,适当调大这个参数可以提高 Sink 从Channel 搬出 event 的性能。
5.5 Flume 的事务机制
- Flume 的事务机制(类似数据库的事务机制):Flume 使用两个独立的事务分别负责从 Soucrce 到 Channel,以及从 Channel 到 Sink 的事件传递。比如 spooling directory source 为文件的每一行创建一个事件,一旦事务中所有的事件全部传递到 Channel 且提交成功,那么 Soucrce 就将该文件标记为完成。
- 同理,事务以类似的方式处理从 Channel 到 Sink 的传递过程,如果因为某种原因使得事件无法记录,那么事务将会回滚。且所有的事件都会保持到Channel 中,等待重新传递。
5.6 Flume 采集数据会丢失吗?
- 根据 Flume 的架构原理,Flume 是不可能丢失数据的,其内部有完善的事务机制, Source 到Channel 是事务性的,Channel 到Sink 是事务性的,因此这两个环节不会出现数据的丢失,唯一可能丢失数据的情况是 Channel 采用 memoryChannel,agent 宕机导致数据丢失,或者 Channel 存储数据已满,导致 Source 不再写入,未写入的数据丢失。
- Flume 不会丢失数据,但是有可能造成数据的重复,例如数据已经成功由 Sink 发出, 但是没有接收到响应,Sink 会再次发送数据,此时可能会导致数据的重复。
种原因使得事件无法记录,那么事务将会回滚。且所有的事件都会保持到Channel 中,等待重新传递。
5.6 Flume 采集数据会丢失吗?
- 根据 Flume 的架构原理,Flume 是不可能丢失数据的,其内部有完善的事务机制, Source 到Channel 是事务性的,Channel 到Sink 是事务性的,因此这两个环节不会出现数据的丢失,唯一可能丢失数据的情况是 Channel 采用 memoryChannel,agent 宕机导致数据丢失,或者 Channel 存储数据已满,导致 Source 不再写入,未写入的数据丢失。
- Flume 不会丢失数据,但是有可能造成数据的重复,例如数据已经成功由 Sink 发出, 但是没有接收到响应,Sink 会再次发送数据,此时可能会导致数据的重复。