参考官网 flume.apache.org/releases/co…
介绍
概述
Apache Flume是一个分布式的、高可靠的、高可用的系统,用于有效地收集、聚合和移动来自许多不同来源的大量日志数据到一个集中的数据存储
Apache Flume的使用不仅限于日志数据聚合。由于数据源是可定制的,Flume可以用来传输大量的事件数据,包括但不限于网络流量数据、社交媒体生成的数据、电子邮件消息和几乎任何可能的数据源
Apache Flume是Apache软件基金会的一个顶级项目
系统要求
- Java 运行时环境 - Java 1.8 或更高版本
- 内存 - 为sources, channels 或 sinks使用的配置提供足够的内存
- 磁盘空间 - 为channels或sinks使用的配置提供足够的磁盘空间
- 目录权限 - 代理使用的目录的读/写权限
体系结构
数据流模型
Flume事件被定义为具有字节负载和一组可选的字符串属性的数据流单元。Flume agent是一个托管组件的(JVM)进程,事件通过这些组件从外部源流向下一个目标(hop)
Flume源使用由外部源(如web服务器)传递给它的事件。外部源以目标Flume源可识别的格式向Flume发送事件。例如,Avro Flume数据源可以从Avro客户端接收Avro事件,也可以从流中的其他Flume agent接收从Avro sink发送的事件。可以使用Thrift Flume Source来定义类似的流,以接收来自Thrift Sink或Flume Thrift Rpc客户端或从Flume Thrift协议生成的任何语言编写的Thrift客户端的事件。当Flume source接收到一个事件时,它会将事件存储到一个或多个channel中。channel是一个被动存储,它保存事件,直到它被Flume sink消费。文件channel就是一个例子–它由本地文件系统支持。sink从channel中删除事件,并将其放入像HDFS这样的外部存储库(通过Flume HDFS sink),或者将其转发到流中下一个Flume代理(next hop)的Flume source。通过将事件保存到channel中给定代理的source和sink异步运行
复杂的流
Flume允许用户构建multi-hop(多跳)流,事件在到达最终目的地之前会通过多个代理。它还允许fan-in(扇入)和fan-out(扇出)流、上下文路由和失败hop(跳)的备份路由(故障转移)
可靠性
事件在每个代理上的通道中暂存。然后将事件传递到流中的下一个代理或终端存储库(如HDFS)。事件只有在存储在下一个代理的通道或终端存储库中之后才会从通道中删除。这就是Flume中的single-hop(单跳)消息传递语义如何提供流的端到端可靠性
Flume使用事务型方法来保证事件的可靠传递。source和sink分别在事务中封装存储/检索,其事件放置在事务中或由事务提供,事务由channel提供。这确保了事件集在流中可靠地从一个点传递到另一个点。在多跳流的情况下,来自前一跳的sink和来自下一跳的source都在运行它们的事务,以确保数据安全地存储在下一跳的channel中
可恢复性
事件暂存在channel(通道)中,用于管理故障恢复。Flume支持由本地文件系统支持的持久文件通道。还有一个内存通道,它只是将事件存储在内存队列中,这样更快,但是当代理进程死亡时,仍然留在内存通道中的任何事件都无法恢复
Flume的KafkaChannel使用Apache Kafka来处理事件。使用带复制功能的Kafka主题作为通道有助于避免磁盘故障时的事件丢失
安装
安装一个代理
Flume代理配置存储在一个或多个遵循Java属性文件(property)格式的配置文件中。可以在这些配置文件中指定一个或多个代理的配置。配置包括代理中每个source, sink 和 channel的属性,以及如何将它们连接在一起以形成数据流。
配置单个组件
流中的每个组件(source, sink 或 channel)都具有特定于类型和实例化的名称、类型和一组属性。例如,Avro source需要一个主机名(或IP地址)和一个端口号来接收数据。内存channel可以有最大队列大小(capacity),HDFS sink需要知道文件系统的URI、创建文件的路径、文件旋转的频率(hdfs.rollInterval)等。组件的所有这些属性都需要在宿主Flume代理的属性文件中设置
将部件连接在一起
代理需要知道要加载哪些单独的组件,以及如何连接它们以构成流。这是通过列出代理中每个sources, sinks 和 channels的名称,然后为每个sink和source指定连接channel来实现的。例如,代理通过file-channel文件通道将事件从Avro source avroWeb传输到HDFS sink hdfs-cluster1。配置文件将包含这些组件的名称,file-channel作为avroWeb source和hdfs-cluster1 sink的共享通道
开始一个代理
代理是使用名为flume-ng的shell脚本启动的,该脚本位于Flume发行版的bin目录中。需要在命令行中指定代理名称、配置目录和配置文件
# -c 指定代理运行的配置文件,-f 指定flume运行的配置文件
flume-ng agent -n $agent_name -c conf -f conf/flume-conf.properties.template
现在代理将开始运行在给定属性文件中配置的source和sink
一个简单的例子
准备环境
# JDK安装
wget https://builds.openlogic.com/downloadJDK/openlogic-openjdk/8u392-b08/openlogic-openjdk-8u392-b08-linux-x64.tar.gz
tar xf openlogic-openjdk-8u392-b08-linux-x64.tar.gz
mv openlogic-openjdk-8u392-b08-linux-x64 /usr/local/jdk8
rm -f openlogic-openjdk-8u392-b08-linux-x64.tar.gz
echo 'export JAVA_HOME=/usr/local/jdk8' >> /etc/profile
echo 'export PATH=$PATH:${JAVA_HOME}/bin' >> /etc/profile
source /etc/profile
# flume安装
wget https://archive.apache.org/dist/flume/1.10.1/apache-flume-1.10.1-bin.tar.gz
tar xf apache-flume-1.10.1-bin.tar.gz
mv apache-flume-1.10.1-bin /usr/local/flume-1.10.1
rm -f apache-flume-1.10.1-bin.tar.gz
echo 'export FLUME_HOME=/usr/local/flume-1.10.1' >> /etc/profile
echo 'export PATH=$PATH:${FLUME_HOME}/bin' >> /etc/profile
source /etc/profile
# 修改配置
cp $FLUME_HOME/conf/flume-env.sh.template $FLUME_HOME/conf/flume-env.sh
sed -i '/# export JAVA_HOME=/a export JAVA_HOME=/usr/local/jdk8' $FLUME_HOME/conf/flume-env.sh
# 查看部署的flume版本
flume-ng version
在这里,我们给出一个示例配置文件,描述一个单节点Flume部署。此配置允许用户生成事件并随后将其记录到控制台
# example.conf: 单节点Flume配置
# 为这个代理上的组件命名
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 描述/配置 source
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
# 描述 sink
a1.sinks.k1.type = logger
# 使用在内存中缓冲事件的channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# 将source和sink绑定到channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
这个配置定义了一个名为a1的代理。a1有一个在端口44444上侦听数据的source、一个在内存中缓冲事件数据的channel和一个将事件数据记录到控制台的sink。配置文件为各种组件命名,然后描述它们的类型和配置参数。给定的配置文件可能定义几个已命名的代理;当一个给定的Flume进程启动时,会传递一个标志,告诉它要显示哪个命名代理
有了这个配置文件,我们可以这样启动Flume
mkdir ~/flume_test;cd ~/flume_test
# 创建conf
mkdir conf;cp $FLUME_HOME/conf/{flume-env.sh,log4j2.xml} ./conf
# 修改 ./conf/log4j2.xml 配制文件,使INFO日志在控制台显示,否则下面启动Flume时不会在控制台显示INFO日志
# 在 <Root level="INFO"> 下一行添加 <AppenderRef ref="Console" />
sed -i '/<Root level="INFO">/a \\ <AppenderRef ref="Console" />' ./conf/log4j2.xml
# 创建上面的example.conf配置文件,然后执行如下命令
flume-ng agent --conf conf --conf-file example.conf --name a1
...
Created serverSocket:sun.nio.ch.ServerSocketChannelImpl[/127.0.0.1:44444]
注意,在完整部署中,我们通常会包含一个选项:--conf=<conf-dir>
。<conf-dir>
目录将包括一个shell脚本flume-env.sh和一个log4j配置文件
在另一个终端中,可以telnet 44444端口,并向Flume发送一个事件
yum -y install telnet
# 可以输入发送的数据,然后按回车发送数据,接着可以继续发送;Ctrl ] 可以结束输入;结束输入之后quit可以退出telnet
telnet localhost 44444
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello world
OK
hello flume
OK
^]
telnet> quit
Connection closed.
原始的Flume终端会将事件输出为日志消息
# 启动 flume agent 的终端可以看到如下输出
2024-04-25 13:48:14,841 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.LoggerSink.process(LoggerSink.java:95)] Event: { headers:{} body: 68 65 6C 6C 6F 20 77 6F 72 6C 64 0D hello world. }
2024-04-25 13:48:18,869 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.LoggerSink.process(LoggerSink.java:95)] Event: { headers:{} body: 68 65 6C 6C 6F 20 66 6C 75 6D 65 0D hello flume. }
你已经成功配置并部署了一个Flume agent ! 后续部分将更详细地介绍代理配置
通过uri进行配置
从版本1.10.0开始,Flume支持使用uri进行配置,而不仅仅是从本地文件进行配置。其中包括对HTTP(S)、文件和类路径URI的直接支持。HTTP支持包括对使用基本授权的身份验证的支持,但是可以通过使用–auth-provider
选项指定实现AuthorizationProvider接口的类的完全限定名来支持其他授权机制。如果目标服务器正确响应If-Modified-Since
标头,HTTP还支持使用轮询重新加载配置文件
要指定HTTP认证的凭据,请在startup命令中添加--conf-user userid --conf-password password
多个配置文件
从1.10.0版本开始,Flume支持从多个配置文件而不是一个配置文件进行配置。这样可以更容易地根据特定环境重写或添加值。每个文件都应该使用自己的–conf-file
或–conf-uri
选项来配置。但是,所有文件都应该使用–conf-file
或–conf-uri
提供。如果–conf-file
和–conf-uri
同时作为选项出现,所有–conf-uri
配置将在–conf-file
配置之前被合并处理
例如下面的配置,这将导致flume.conf首先被读取,override.conf与之合并,example.conf最后被合并
flume-ng agent --conf conf --conf-file example.conf --conf-uri http://localhost:80/flume.conf --conf-uri http://localhost:80/override.conf --name a1
如果希望将example.conf作为基本配置,则应该使用–conf-uri
选项指定为--conf-uri classpath://example.conf
或--conf-uri file:///example.conf
,这依赖于它应该如何被访问
使用环境变量、系统属性或其他属性配置文件
Flume能够在配置中替换环境变量。例如
a1.sources = r1
a1.sources.r1.type = netcat
a1.sources.r1.bind = 0.0.0.0
a1.sources.r1.port = ${env:NC_PORT}
a1.sources.r1.channels = c1
注:它目前只适用于值,不适用于键。(即仅在配置行=标记的“右侧”)
从1.10.0版本开始,Flume使用Apache Commons Text的StringSubstitutor类解析配置值,使用默认的查找集以及使用配置文件作为替换值源的查找
例如:NC_PORT=44444 flume-ng agent –conf conf –conf-file example.conf –name a1
注意,以上只是一个示例,环境变量可以通过其他方式配置,包括在conf/flume-env.sh
中设置
如前所述,还支持系统属性,因此配置
a1.sources = r1
a1.sources.r1.type = netcat
a1.sources.r1.bind = 0.0.0.0
a1.sources.r1.port = ${sys:NC_PORT}
a1.sources.r1.channels = c1
可以使用,启动命令将是
flume-ng agent --conf conf --conf-file example.conf --name a1 -DNC_PORT=44444
此外,由于允许使用多个配置文件,第一个文件可能包含
a1.sources = r1
a1.sources.r1.type = netcat
a1.sources.r1.bind = 0.0.0.0
a1.sources.r1.port = ${NC_PORT}
a1.sources.r1.channels = c1
覆盖文件可能包含
NC_PORT = 44444
在这种情况下,启动命令将是
flume-ng agent --conf conf --conf-file example.conf --conf-file override.conf --name a1
请注意,在以前的版本中指定环境变量的方法仍然有效,但已被弃用,取而代之的是使用${env:varName}
使用命令选项文件
从1.10.0版本开始,命令选项可以放在/etc/flume/flume.opts
或类路径上的flume.opts
中,而不是在命令行上指定所有命令选项
一个例子可能是
conf-file = example.conf
conf-file = override.conf
name = a1
记录原始数据
在许多生产环境中,记录流经摄取管道的原始数据流并不是理想的行为,因为这可能导致敏感数据或安全相关配置(如密钥)泄露到Flume日志文件中。默认情况下,Flume不会记录此类信息。另一方面,如果数据管道被破坏,Flume将尝试为调试问题提供线索
调试事件管道问题的一种方法是建立一个连接到Logger Sink的额外内存通道,它将把所有事件数据输出到Flume日志。然而,在某些情况下,这种方法是不够的
为了启用事件和配置相关数据的日志记录,除了log4j属性之外,还必须设置一些Java系统属性
要启用与配置相关的日志记录,请设置Java系统属性-Dorg.apache.flume.log.printconfig=true
,这可以在命令行上传递,也可以在flume-env.sh的JAVA_OPTS变量中设置
要启用数据的日志记录,请按照上述相同的方式设置Java系统属性-Dorg.apache.flume.log.rawdata=true
。对于大多数组件,log4j日志级别还必须设置为DEBUG或TRACE,以便在Flume日志中显示特定于事件的日志
# 下面是同时启用配置日志记录和原始数据日志记录的示例
flume-ng agent --conf conf --conf-file example.conf --name a1 -Dorg.apache.flume.log.printconfig=true -Dorg.apache.flume.log.rawdata=true
基于Zookeeper的配置
Flume支持通过Zookeeper进行Agent配置。这是一个实验性的功能。配置文件需要上传到Zookeeper中,在一个可配置的前缀下。配置文件保存在"Zookeeper Node data"中。下面是agent a1和a2的Zookeeper节点树的样子
- /flume
|- /a1 [Agent config file]
|- /a2 [Agent config file]
# 上传配置文件后,使用以下选项启动agent
flume-ng agent –conf conf -z zkhost:2181,zkhost1:2181 -p /flume –name a1
# -z Zookeeper连接字符串。以逗号分隔的 hostname:port 列表,没有默认值
# -p Zookeeper中存储Agent配置的基本路径,默认为 /flume
安装第三方插件
Flume有一个完全基于插件的架构。虽然Flume提供了许多开箱即用的源、通道、接收器、序列化器等,但存在许多独立于Flume的实现
虽然一直可以通过将自定义Flume组件的jar添加到flume-env.sh文件中的FLUME_CLASSPATH变量来包含这些组件,但Flume现在支持一个名为plugins.d
的特殊目录,该目录可以自动选择以特定格式打包的插件。这样可以更容易地管理插件打包问题,也可以更简单地调试和排除某些类型的问题,特别是库依赖冲突
plugins.d目录
plugins.d
目录位于$FLUME_HOME/plugins.d
。启动时,flume-ng启动脚本会在plugins.d
目录中查找符合以下格式的插件,并在启动java时将它们包含在正确的路径中
插件的目录布局
plugins.d
中的每个插件(子目录)最多可以有三个子目录
- lib 插件jar包所在的目录
- libext 插件依赖的jar包所在的目录
- native 任何必需的本机库,例如
.so
文件
plugins.d
目录下的两个插件示例
plugins.d/
plugins.d/custom-source-1/
plugins.d/custom-source-1/lib/my-source.jar
plugins.d/custom-source-1/libext/spring-core-2.5.6.jar
plugins.d/custom-source-2/
plugins.d/custom-source-2/lib/custom.jar
plugins.d/custom-source-2/native/gettext.so
数据摄取
Flume支持多种从外部源(source)摄取数据的机制
RPC
Flume发行版中包含的Avro客户端可以使用Avro RPC机制将给定的文件发送到Flume Avro source(源)
# 下面的命令将把/usr/logs/log.10的内容发送到监听这些端口的 Flume source
flume-ng avro-client -H localhost -p 41414 -F /usr/logs/log.10
执行命令
有一个 exec source,它执行给定的命令并消耗输出。输出的单个'行',即文本后面跟着回车符(' \r ')或换行符(' \n '),或者两者一起
网络流
Flume支持以下机制从流行的日志流类型中读取数据,例如
- Avro
- Thrift
- Syslog
- Netcat
设置多agent流
为了跨多个代理(agent)或跳(hop)传输数据,前一个代理的接收器(sink)和当前跳的源(source)需要是avro类型,接收器指向源的主机名(或IP地址)和端口
整合
日志收集中一个非常常见的场景是大量日志生产客户端将数据发送给几个连接到存储子系统的消费者代理。例如,从数百个web服务器收集的日志发送给十几个写HDFS集群的代理
这可以在Flume中通过配置一些带有avro sink的第一级代理来实现,所有这些代理都指向单个代理的一个avro source(同样,您可以在这种情况下使用 thrift sources/sinks/clients)。第二级代理上的source将接收到的事件合并到单个通道中,该通道由sink消费到其最终目的地
多路复用流
Flume支持将事件流复用到一个或多个目的地。这是通过定义一个流多路复用器来实现的,该多路复用器可以将事件复制或有选择地路由到一个或多个通道
上面的示例显示了一个来自代理"foo"的源,它将流扇形地分发到三个不同的通道。此扇出可以是复制或多路复用。在复制流的情况下,每个事件都被发送到所有三个通道。对于多路复用情况,当事件的属性与预先配置的值匹配时,事件将被发送到可用通道的子集。例如,如果一个名为"txnType"的事件属性设置为"customer",那么它应该转到channel1和channel3,如果它是"vendor",那么它应该转到channel2,否则应该转到channel3。可以在代理的配置文件中设置映射
配置
如前一节所述,Flume代理配置是从一个类似于具有分层属性设置的Java属性文件格式的文件中读取的
定义流
要在单个代理中定义流,需要通过通道链接源和接收器。您需要列出给定代理的源、接收器和通道,然后将源和接收器指向一个通道。源实例可以指定多个通道,但接收实例只能指定一个通道。格式如下
# 列出代理的 sources, sinks 和 channels
<Agent>.sources = <Source>
<Agent>.sinks = <Sink>
<Agent>.channels = <Channel1> <Channel2>
# set channel for source
<Agent>.sources.<Source>.channels = <Channel1> <Channel2> ...
# set channel for sink
<Agent>.sinks.<Sink>.channel = <Channel1>
例如,一个名为agent_foo的代理正在从外部avro客户端读取数据,并通过内存通道将其发送到HDFS。配置文件weblog.config如下所示
# 列出代理的 sources, sinks 和 channels
agent_foo.sources = avro-appserver-src-1
agent_foo.sinks = hdfs-sink-1
agent_foo.channels = mem-channel-1
# set channel for source
agent_foo.sources.avro-appserver-src-1.channels = mem-channel-1
# set channel for sink
agent_foo.sinks.hdfs-sink-1.channel = mem-channel-1
这将使事件通过内存通道mem-channel-1从avro-AppSrv-source流到hdfs-Cluster1-sink。当代理以weblog.config作为其配置文件启动时,它将实例化该流
配置单个组件
定义流之后,您需要设置每个源、接收器和通道的属性。这是通过相同的层次命名空间方式完成的,您可以为每个组件特定的属性设置组件类型和其他值
# properties for sources
<Agent>.sources.<Source>.<someProperty> = <someValue>
# properties for channels
<Agent>.channels.<Channel>.<someProperty> = <someValue>
# properties for sinks
<Agent>.sinks.<Sink>.<someProperty> = <someValue>
属性"type"需要为每个组件设置,以便Flume理解它需要的对象类型。每个源、接收器和通道类型都有自己的一组属性,以便按预期的方式工作。所有这些都需要根据需要进行设置。在前面的示例中,我们有一个通过内存通道mem-channel-1从avro-AppSrv-source到hdfs-Cluster1-sink的流。下面的示例显示了每个组件的配置
agent_foo.sources = avro-AppSrv-source
agent_foo.sinks = hdfs-Cluster1-sink
agent_foo.channels = mem-channel-1
# set channel for sources, sinks
# properties of avro-AppSrv-source
agent_foo.sources.avro-AppSrv-source.type = avro
agent_foo.sources.avro-AppSrv-source.bind = localhost
agent_foo.sources.avro-AppSrv-source.port = 10000
# properties of mem-channel-1
agent_foo.channels.mem-channel-1.type = memory
agent_foo.channels.mem-channel-1.capacity = 1000
agent_foo.channels.mem-channel-1.transactionCapacity = 100
# properties of hdfs-Cluster1-sink
agent_foo.sinks.hdfs-Cluster1-sink.type = hdfs
agent_foo.sinks.hdfs-Cluster1-sink.hdfs.path = hdfs://namenode/flume/webdata
在一个代理中添加多个流
一个Flume代理可以包含几个独立的流。你可以在一个配置中列出多个源、接收器和通道。这些组件可以链接起来形成多个流
# 列出代理的 sources, sinks and channels
<Agent>.sources = <Source1> <Source2>
<Agent>.sinks = <Sink1> <Sink2>
<Agent>.channels = <Channel1> <Channel2>
然后,您可以将源和接收器链接到它们相应的通道(用于源)或通道(用于接收器),以设置两个不同的流。例如,如果您需要在代理中设置两个流,一个从外部avro客户端到外部HDFS,另一个从tail输出到avro sink,那么这里有一个配置:
# 列出代理的 sources, sinks and channels
agent_foo.sources = avro-AppSrv-source1 exec-tail-source2
agent_foo.sinks = hdfs-Cluster1-sink1 avro-forward-sink2
agent_foo.channels = mem-channel-1 file-channel-2
# flow #1 configuration
agent_foo.sources.avro-AppSrv-source1.channels = mem-channel-1
agent_foo.sinks.hdfs-Cluster1-sink1.channel = mem-channel-1
# flow #2 configuration
agent_foo.sources.exec-tail-source2.channels = file-channel-2
agent_foo.sinks.avro-forward-sink2.channel = file-channel-2
配置多代理流
要设置一个多层流,需要让第一跳的avro/thrift接收器指向下一跳的avro/thrift源。这将导致第一个Flume代理将事件转发给下一个Flume代理。例如,如果您使用avro客户端定期向本地Flume代理发送文件(每个事件一个文件),那么该本地代理可以将其转发到另一个已挂载了存储空间的代理上
Weblog 代理配置
# 列出代理的 sources, sinks and channels
agent_foo.sources = avro-AppSrv-source
agent_foo.sinks = avro-forward-sink
agent_foo.channels = file-channel
# define the flow
agent_foo.sources.avro-AppSrv-source.channels = file-channel
agent_foo.sinks.avro-forward-sink.channel = file-channel
# avro sink properties
agent_foo.sinks.avro-forward-sink.type = avro
agent_foo.sinks.avro-forward-sink.hostname = 10.1.1.100
agent_foo.sinks.avro-forward-sink.port = 10000
# 配置其他部分
HDFS 代理配置
# 列出代理的 sources, sinks and channels
agent_foo.sources = avro-collection-source
agent_foo.sinks = hdfs-sink
agent_foo.channels = mem-channel
# define the flow
agent_foo.sources.avro-collection-source.channels = mem-channel
agent_foo.sinks.hdfs-sink.channel = mem-channel
# avro source properties
agent_foo.sources.avro-collection-source.type = avro
agent_foo.sources.avro-collection-source.bind = 10.1.1.100
agent_foo.sources.avro-collection-source.port = 10000
# 配置其他部分
这里我们将来自weblog代理的avro-forward-sink链接到hdfs代理的avro-collection-source。这将导致来自外部appserver源的事件最终存储在HDFS中
扇出(分散)流(Fan out flow)
如前一节所讨论的,Flume支持将流从一个源分散到多个通道。扇出有复制和多路复用两种模式。在复制流中,事件被发送到所有配置的通道。在多路复用的情况下,事件只发送到合格通道的一个子集。要将流展开,需要为源指定通道列表和将其展开的策略。这是通过添加一个可以复制或复用的通道“选择器”来完成的。如果是多路复用器,则进一步指定选择规则。如果你没有指定选择器,那么默认情况下它是复制的
# 列出代理的 sources, sinks and channels
<Agent>.sources = <Source1>
<Agent>.sinks = <Sink1> <Sink2>
<Agent>.channels = <Channel1> <Channel2>
# 设置源的通道列表(以空格分隔)
<Agent>.sources.<Source1>.channels = <Channel1> <Channel2>
# set channel for sinks
<Agent>.sinks.<Sink1>.channel = <Channel1>
<Agent>.sinks.<Sink2>.channel = <Channel2>
<Agent>.sources.<Source1>.selector.type = replicating
多路复用选择器还有一组额外的属性来对数据流进行分流。这需要指定一个事件属性到一组通道的映射。选择器会检查事件头中配置的每个属性。如果它与指定的值匹配,则该事件会被发送到映射到该值的所有通道上。如果没有匹配项,则该事件将被发送到配置为默认的一组通道上:
# 多路选择器的映射
<Agent>.sources.<Source1>.selector.type = multiplexing
<Agent>.sources.<Source1>.selector.header = <someHeader>
<Agent>.sources.<Source1>.selector.mapping.<Value1> = <Channel1>
<Agent>.sources.<Source1>.selector.mapping.<Value2> = <Channel1> <Channel2>
<Agent>.sources.<Source1>.selector.mapping.<Value3> = <Channel2>
#...
<Agent>.sources.<Source1>.selector.default = <Channel2>
映射允许每个值的通道重叠。下面的示例有一个多路复用到两条路径的流。名为agent_foo的代理具有单个avro源和链接到两个接收器的两个通道:
# 列出代理的 sources, sinks and channels
agent_foo.sources = avro-AppSrv-source1
agent_foo.sinks = hdfs-Cluster1-sink1 avro-forward-sink2
agent_foo.channels = mem-channel-1 file-channel-2
# set channels for source
agent_foo.sources.avro-AppSrv-source1.channels = mem-channel-1 file-channel-2
# set channel for sinks
agent_foo.sinks.hdfs-Cluster1-sink1.channel = mem-channel-1
agent_foo.sinks.avro-forward-sink2.channel = file-channel-2
# channel selector configuration
agent_foo.sources.avro-AppSrv-source1.selector.type = multiplexing
agent_foo.sources.avro-AppSrv-source1.selector.header = State
agent_foo.sources.avro-AppSrv-source1.selector.mapping.CA = mem-channel-1
agent_foo.sources.avro-AppSrv-source1.selector.mapping.AZ = file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.mapping.NY = mem-channel-1 file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.default = mem-channel-1
选择器检查名为"State"的标头。如果值是"CA",那么它被发送到mem-channel-1,如果是"AZ",那么它被发送到file-channel-2,如果是"NY",那么两者都发送。如果没有设置"State"标头,或者与这三个标头中的任何一个都不匹配,则转到指定为"default"的mem-channel-1。选择器还支持可选通道。要为标头指定可选通道,配置参数'optional'的使用方式如下:
# channel selector configuration
agent_foo.sources.avro-AppSrv-source1.selector.type = multiplexing
agent_foo.sources.avro-AppSrv-source1.selector.header = State
agent_foo.sources.avro-AppSrv-source1.selector.mapping.CA = mem-channel-1
agent_foo.sources.avro-AppSrv-source1.selector.mapping.AZ = file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.mapping.NY = mem-channel-1 file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.optional.CA = mem-channel-1 file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.mapping.AZ = file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.default = mem-channel-1
选择器首先尝试将事件写入必需的通道,并且如果这些通道中有任何一个未能消费事件,事务将会失败。之后,会在所有这些通道上重新尝试该事务。一旦所有必需的通道都成功消费了事件,选择器接下来会尝试将事件写入可选通道。任何可选通道未能消费事件的失败情况都将被忽略,不会进行重试
如果针对特定头部信息,可选通道与必需通道之间存在重叠,那么该通道将被视为必需通道,该通道的写入失败会导致重新尝试整个必需的通道集。例如,在上述示例中,对于头部信息"CA",尽管mem-channel-1同时被标记为必需和可选,但它仍被视为必需通道,向该通道写入失败会导致该事件在选择器配置的所有通道上被重新尝试
需要注意的是,如果某个头部信息没有配置任何必需通道,那么该事件将被写入默认通道,并且尝试被写入该头部信息对应的可选通道。如果未指定任何必需通道,指定可选通道仍然会导致事件被写入默认通道。如果没有通道被指定为默认通道,并且也没有必需通道,选择器会尝试将事件写入可选通道。在这种情况下,任何失败都将被直接忽略
SSL/TLS support
需要时查看官网
源和sink的批量大小和通道的事务处理能力
源和接收器可以具有批处理大小参数,该参数确定它们在一个批处理中处理的最大事件数。这发生在具有称为事务容量的上限的通道事务中。批处理大小必须小于通道的事务容量。有一个显式检查来防止不兼容的设置。每当读取配置时,都会进行此检查
Flume Sources
需要时查看官网
Flume Sinks
需要时查看官网
Flume Channels
需要时查看官网
Flume Channel Selectors
如果未指定类型,则默认为"replicating"
复制通道选择器(默认)
- selector.type = replicating 默认
- selector.optional 要标记为可选的通道集
代理名为a1,它的源名为r1的例子:
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是一个可选通道。写入c3失败将被忽略。由于c1和c2未被标记为可选,因此向这些通道写入失败将导致事务失败
负载均衡通道选择器
负载均衡通道选择器提供了在多个通道上平衡数据流的能力。这实质上允许在多个线程上处理传入的数据。它维护了一个活跃通道的索引列表,必须在这些通道上分配负载。实现支持通过轮询(round_robin)或随机(random)选择机制来分配负载。选择机制的默认方式是轮询类型,但可以通过配置进行覆盖调整
- selector.type = load_balancing
- selector.policy = round_robin,选择机制。必须是round_robin或random
代理名为a1,它的源名为r1的例子:
a1.sources = r1
a1.channels = c1 c2 c3 c4
a1.sources.r1.channels = c1 c2 c3 c4
a1.sources.r1.selector.type = load_balancing
a1.sources.r1.selector.policy = round_robin
多路通道选择器
- selector.type = multiplexing
- selector.header = flume.selector.header 默认
- selector.default
- selector.mapping.*
代理名为a1,它的源名为r1的例子:
a1.sources = r1
a1.channels = c1 c2 c3 c4
a1.sources.r1.selector.type = multiplexing
a1.sources.r1.selector.header = state
a1.sources.r1.selector.mapping.CZ = c1
a1.sources.r1.selector.mapping.US = c2 c3
a1.sources.r1.selector.default = c4
自定义通道选择器
自定义通道选择器是您自己对ChannelSelector接口的实现。启动Flume代理时,自定义通道选择器的类及其依赖项必须包含在代理的类路径中。自定义通道选择器的类型是它的FQCN
- selector.type 组件类型名称,需要是你的FQCN
代理名为a1,它的源名为r1的例子:
a1.sources = r1
a1.channels = c1
a1.sources.r1.selector.type = org.example.MyChannelSelector
Flume Sink Processors
接收器组允许用户将多个接收器分组到一个实体中。接收器处理器可用于在组内的所有接收器上提供负载均衡功能,或者在发生临时故障时实现从一个接收器到另一个接收器的故障转移。
- sinks 参与该组的sink列表以空格分隔
- processor.type 组件类型名称,需要是default(默认)、failover或load_balance
例如代理名为a1
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = load_balance
Default Sink Processor
默认接收器处理器只接受单个接收器。不强制用户为单个接收器创建处理器(接收器组)。相反,用户可以遵循本用户指南中上述解释的源-通道-接收模式
Failover Sink Processor
故障转移接收器处理器维护一个接收器的优先级列表,保证只要至少有一个接收器可用,事件就能得到处理(传送)
故障转移机制的工作原理是,将失败的Sink降级到一个池中,在那里它们被分配一个冷却期,随着连续失败次数的增加,这个冷却期会逐渐延长,之后才会重试。一旦Sink成功发送了一个事件,它就会被恢复到活动池中。Sink与一个优先级关联,数字越大,优先级越高。如果Sink在发送事件时失败,下一个优先级最高的Sink将被尝试用于发送事件。例如,优先级为100的Sink会比优先级为80的Sink更早被激活。如果没有指定优先级,则根据配置中指定Sink的顺序来确定优先级
要进行配置,需将Sink组的处理器设置为故障转移,并为所有单独的Sink设置优先级。所有指定的优先级必须是唯一的。此外,可以通过maxpenalty属性设置故障转移时间的上限(以毫秒为单位)
- sinks 参与该组的sink列表以空格分隔
- processor.type = failover
processor.priority.<sinkName>
优先级值。<sinkName>
必须是当前Sink组关联的Sink实例之一。优先级值较高的Sink会更早被激活。绝对值较大的数值表示更高的优先级- processor.maxpenalty 失败Sink的最大退避周期(以毫秒为单位)
例如代理名为a1
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = failover
a1.sinkgroups.g1.processor.priority.k1 = 5
a1.sinkgroups.g1.processor.priority.k2 = 10
a1.sinkgroups.g1.processor.maxpenalty = 10000
Load balancing Sink Processor
负载均衡Sink处理器提供了在多个Sink之间进行流量负载均衡的能力。它维护了一个索引列表,其中包含了必须分配负载的活动Sink。实现支持使用轮询(round_robin)或随机(random)选择机制来分配负载。选择机制的默认类型为轮询(round_robin),但可以通过配置进行覆盖。通过从AbstractSinkSelector继承的自定义类,也支持自定义选择机制
当被调用时,此选择器会使用其配置的选择机制来挑选下一个Sink并调用它。对于轮询和随机选择,如果所选Sink未能传送事件,处理器将通过其配置的选择机制挑选下一个可用Sink。此实现不将失败的Sink列入黑名单,而是继续乐观地尝试每一个可用Sink。如果所有Sink的调用都失败了,选择器会将失败传播给Sink运行器
如果启用了退避机制,Sink处理器将把失败的Sink列入黑名单,移除它们在特定超时时间内的选择资格。当超时结束时,如果Sink仍然无响应,超时时间将呈指数级增加,以避免可能因等待无响应Sink而长时间阻塞。如果不启用此功能,在轮询方式下,所有失败Sink的负载都将传递给队列中的下一个Sink,从而无法实现均匀平衡
- processor.sinks 参与该组的sink列表以空格分隔
- processor.type = load_balance
- processor.backoff 是否应对失败的Sink实施指数级的退避,默认false
- processor.selector 选择机制。必须是round_robin, random或者继承自AbstractSinkSelector的自定义类的FQCN
- processor.selector.maxTimeOut 被退避选择器用来限制指数退避的时间上限(以毫秒为单位)
例如代理名为a1
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = load_balance
a1.sinkgroups.g1.processor.backoff = true
a1.sinkgroups.g1.processor.selector = random
Custom Sink Processor
目前不支持自定义接收器处理器
Event Serializers
file_roll sink和hdfs sink都支持EventSerializer接口。下面将详细介绍Flume附带的事件序列化器
Body Text Serializer
别名:text。此拦截器将事件内容无任何转换或修改地写入输出流。事件头将被忽略
- appendNewline 是否在写入时每个事件后附加换行符。默认值为true,这是因为考虑到向后兼容性,假设事件中不包含换行符
例如代理名为a1
a1.sinks = k1
a1.sinks.k1.type = file_roll
a1.sinks.k1.channel = c1
a1.sinks.k1.sink.directory = /var/log/flume
a1.sinks.k1.sink.serializer = text
a1.sinks.k1.sink.serializer.appendNewline = false
“Flume Event” Avro Event Serializer
别名:avro_event。此拦截器将Flume事件序列化为Avro容器文件。所使用的模式与Avro RPC机制中Flume事件所使用的模式相同。这个序列化器继承自AbstractAvroEventSerializer类
- syncIntervalBytes Avro同步间隔,以字节为单位,默认2048000
- compressionCodec Avro压缩编解码器。支持的编解码器,请查看Avro的CodecFactory文档
例如代理名为a1
a1.sinks.k1.type = hdfs
a1.sinks.k1.channel = c1
a1.sinks.k1.hdfs.path = /flume/events/%Y-%m-%d/%H%M/%S
a1.sinks.k1.serializer = avro_event
a1.sinks.k1.serializer.compressionCodec = snappy
Avro Event Serializer
别名:此序列化器没有别名,必须使用完全限定的类名进行指定。
此序列化器像“Flume Event”Avro事件序列化器一样,将Flume事件序列化为Avro容器文件,但是记录模式是可以配置的。记录模式可以通过Flume配置属性或事件头传递来指定。要将记录模式作为Flume配置的一部分传递,请使用如下列出的属性schemaURL。要在事件头中传递记录模式,请指定事件头flume.avro.schema.literal,其中包含模式的JSON格式表示,或者使用flume.avro.schema.url,其中包含可找到模式的URL(支持hdfs:/...类型的URI)。这个序列化器继承自AbstractAvroEventSerializer类
- syncIntervalBytes Avro同步间隔,以字节为单位,默认2048000
- compressionCodec Avro压缩编解码器。支持的编解码器,请查看Avro的CodecFactory文档
- schemaURL Avro模式URL。头文件中指定的模式将覆盖此选项
例如代理名为a1
a1.sinks.k1.type = hdfs
a1.sinks.k1.channel = c1
a1.sinks.k1.hdfs.path = /flume/events/%y-%m-%d/%H%M/%S
a1.sinks.k1.serializer = org.apache.flume.sink.hdfs.AvroEventSerializer$Builder
a1.sinks.k1.serializer.compressionCodec = snappy
a1.sinks.k1.serializer.schemaURL = hdfs://namenode/path/to/schema.avsc
Flume Interceptors
Flume 具备在事件传输过程中修改或丢弃事件的能力。这是通过拦截器(interceptors)来实现的。拦截器是实现了 org.apache.flume.interceptor.Interceptor
接口的类。一个拦截器可以根据开发人员选择的任何标准来修改甚至丢弃事件。Flume 支持拦截器的链式调用,这可以通过在配置中指定拦截器构建器类名列表来实现。拦截器在源配置中被指定为以空格分隔的列表,它们被调用的顺序即为在配置中列出的顺序。一个拦截器返回的事件列表会被传递给链中的下一个拦截器。拦截器可以修改或丢弃事件。如果一个拦截器需要丢弃某些事件,它只需不在其返回的列表中包含这些事件即可。如果要丢弃所有事件,则仅需返回一个空列表。拦截器是命名组件,以下是一个如何通过配置创建它们的例子:
a1.sources = r1
a1.sinks = k1
a1.channels = c1
a1.sources.r1.interceptors = i1 i2
a1.sources.r1.interceptors.i1.type = org.apache.flume.interceptor.HostInterceptor$Builder
a1.sources.r1.interceptors.i1.preserveExisting = false
a1.sources.r1.interceptors.i1.hostHeader = hostname
a1.sources.r1.interceptors.i2.type = org.apache.flume.interceptor.TimestampInterceptor$Builder
a1.sinks.k1.filePrefix = FlumeData.%{CollectorHost}.%Y-%m-%d
a1.sinks.k1.channel = c1
请注意,拦截器构建器是传递给类型配置参数的。拦截器本身是可配置的,并且可以像传递给其他任何可配置组件一样传递配置值。在上述示例中,事件首先被传递给 HostInterceptor
,而 HostInterceptor
返回的事件随后被传递给 TimestampInterceptor
。你可以指定完全限定的类名(FQCN)或者别名,例如 timestamp
。如果你有多个收集器写入到同一个 HDFS 路径上,那么你也可以使用 HostInterceptor
Timestamp Interceptor
这个拦截器会在事件头中插入事件被处理时的时间(毫秒级)。此拦截器会插入一个键为 timestamp
(或由 header
属性指定的其它键名)的头部信息,其值就是相关的事件处理时间戳。如果配置中已经存在一个时间戳,这个拦截器能够保留已有的时间戳而不覆盖它
- type 组件的类型名称必须是
timestamp
或者是全限定类名(FQCN) - headerName 放置生成的时间戳所在的头部(header)的名称(默认是timestamp)
- preserveExisting 如果时间戳已经存在,是否应该保留它(默认是true)
例如代理名为a1
a1.sources = r1
a1.channels = c1
a1.sources.r1.channels = c1
a1.sources.r1.type = seq
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = timestamp
Host Interceptor
此拦截器插入运行此代理的主机的主机名或IP地址。它根据配置插入一个带有键host或已配置键的标头,其值为主机的主机名或IP地址
- type 组件的类型名称必须是host
- preserveExisting 如果主机头已经存在,是否应该保留,默认为false
- useIP 如果为true,则使用IP地址,否则使用主机名,默认为true
- hostHeader 要使用的头部(header)键名,默认为host
例如代理名为a1
a1.sources = r1
a1.channels = c1
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = host
Static Interceptor
静态拦截器(Static interceptor)允许用户向所有事件附加一个具有固定值的静态头部(header)。当前的实现并不支持一次性指定多个头部。相反,用户可能需要串联多个静态拦截器,每个拦截器定义一个静态头部
- type 组件的类型名称必须是static
- preserveExisting 如果配置的头部(header)已经存在,是否应该保留它,默认为true
- key 应创建的头部(header)的名称,默认是key
- value 应创建的静态值,默认是value
例如代理名为a1
a1.sources = r1
a1.channels = c1
a1.sources.r1.channels = c1
a1.sources.r1.type = seq
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = static
a1.sources.r1.interceptors.i1.key = datacenter
a1.sources.r1.interceptors.i1.value = NEW_YORK