前言:里面的各种source,channel和simk时可以参考官网去满足自己的需求,看着官网可以很快的实现;
https://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html
Flume 初始的发行版本目前被统称为 Flume OG(original generation),属于 cloudera。但随着 Flume 功能的扩展,Flume OG 代码工程臃肿、核心组件设计不合理、核心配置不标准等缺点暴露出来,为了解决这些问题,2011 年 10 月 22 号,cloudera 完成了 Flume-728,对 Flume 进行了里程碑式的改动:重构核心组件、核心配置以及代码架构,重构后的版本统称为 Flume NG(next generation);纳入apache下也是促使其改动的一大原因,cloudera Flume 改名为 Apache Flume。
[外链图片转存失败(img-A9rMrBRi-1569053080012)(/C:/Users/Administrator/Desktop/1568961627511.png)]
[外链图片转存失败(img-oed3vG5A-1569053080015)(/1558868987797.png)]
flume架构如上
flume的特点如下:
流式架构:处理数据的单位很小,流失架构,来一行处理一行;
flume是一个分布式、高可靠、高可用的服务,能够有效的收集、聚合、移动大量的日志数据。(基于流式架构灵活架构)
1、它有一个简单、灵活的基于流的数据流结构。
2、具有故障转移机制和负载均衡机制。
3、使用了一个简单的可扩展的数据模型(source、channel、sink)。
4、声明式配置,可以动态更新配置 (配置修改后,不用重启服务即可生效)
flume-ng处理数据有两种方式:avro-client、agent。
avro-client:一次性将数据传输到指定的avro服务的客户端。
agent:一个持续传输数据的服务。
Agent主要组件包含:Source 、Channel、Sink
数据在组件传输的单位是Event
1、下载:http://apache.communilink.net/flume/1.8.0/apache-flume-1.8.0-bin.tar.gz
2、解压缩:tar zvxf apache-flume-1.8.0-bin.tar.gz
3、修改配置
$ cp conf/flume-env.sh.template conf/flume-env.sh
在conf/flume-env.sh配置JAVA_HOME
创建配置文件example.conf 参考 conf/flume-conf.properties.template
注意:export JAVA_OPTS
4、启动agent
bin/flume-ng agent --conf conf/ --conf-file conf/example.conf
–name a1 -Dflume.monitoring.type=http Dflume.monitoring.port=34343 -Dflume.root.logger=INFO,console &
声明agent名字a1,声明sources 包含r1 sink:k1 channel:c1
a1.sources = r1
a1.sinks = k1
a1.channels = c1
配置source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /var/log/secure
配置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
解释:对于以上配置文件中,其核心的组件如下
主要作用:从Client收集数据,传递给Channel。可以接收外部源发送过来的数据。不同的 source,可以接受不同的数据格式。 比如有目录池(spooling directory)数据源,可以监控指定文件夹中的新文件变化,如果目录中有文件产生,就会立刻读取其内容。
常见采集的数据类型:
Exec Source、Avro Source、NetCat Source、Spooling Directory Source、Kafka Source等
不同source的具体作用:
监听一个avro服务端口,采集Avro数据序列化后的数据,avro可以用来用作其他flume的sink出口或是做source的入口就是说多个flume嵌套是可以使用avro(官网释义:侦听Avro端口并从外部Avro客户端流接收事件。与另一个(以前的跃点)Flume代理上的内置Avro Sink配对时,它可以创建分层的集合拓扑)
监听一个Thrift 服务端口,采集Thrift数据序列化后的数据;(官网释义:监听Thrift端口并接收来自外部Thrift客户端流的事件。与另一个(以前的跃点)Flume代理上的内置ThriftSink配对时,它可以创建分层的集合拓扑。可通过启用kerberos身份验证将节俭源配置为以安全模式启动。agent-principal和agent-keytab是Thrift源用来验证kerberos KDC的属性。)
基于Unix的command在标准输出上采集数据;
eg:监控文件:tail -f +filename**(官网释义:Exec源代码在启动时运行给定的Unix命令,并期望该过程在标准输出上连续产生数据(除非将属性logStdErr设置为true,否则将直接丢弃stderr)。如果该过程由于某种原因而退出,则源也将退出,并且将不再产生任何数据。这意味着诸如cat [命名 管道]
或tail -F [file]之
类的配置将产生期望的结果,而日期
可能不会-前两个命令产生数据流,而后者则产生单个事件并退出。)**
Java消息服务数据源,Java消息服务是一个与具体平台无关的API,这是支持jms规范的数据源采集;(官网释义:JMS源从JMS目标(例如队列或主题)读取消息。作为JMS应用程序,它可以与任何JMS提供程序一起使用,但仅经过ActiveMQ的测试。JMS源提供了可配置的批处理大小,消息选择器,用户/传递以及消息到水槽事件转换器。请注意,应使用plugins.d目录(首选),命令行上的–classpath或通过flume-env.sh中的FLUME_CLASSPATH变量,将供应商提供的JMS jar包含在Flume类路径中。)
通过文件夹里的新增的文件作为数据源的采集;
(官网释义:通过此源,您可以通过将要摄取的文件放入磁盘上的“假脱机”目录中来摄取数据。该源将监视指定目录中的新文件,并从出现的新文件中解析事件。事件解析逻辑是可插入的。在将给定文件完全读入通道后,默认情况下将通过重命名文件来指示完成,或者可以将其删除或使用trackerDir跟踪已处理文件。)
从kafka服务中采集数据。(官网释义:Kafka Source是Apache Kafka使用者,可从Kafka主题读取消息。如果有多个Kafka源在运行,则可以为它们配置相同的Consumer Group,以便每个源都可以读取主题的唯一分区集。)
绑定的端口(tcp、udp),将流经端口的每一个文本行数据作为Event输入
Source提供了两种机制: PollableSource(轮询拉取)和EventDrivenSource(事件驱动):
[外链图片转存失败(img-zv8cgjZF-1569053080016)(/1558869962898.png)]
上图展示的Source继承关系类图。
通过类图我们可以看到NetcatSource,ExecSource和HttpSource属于事件驱动模型。KafkaSource,SequenceGeneratorSource和JmsSource属于轮询拉取模型。
Channel:一个数据的存储池,中间通道抑或是缓存队列。
**主要作用:**Channel用于连接Source和Sink,Source将日志信息发送到Channel,Sink从Channel消费日志信息;Channel是中转日志信息的一个临时存储,保存有Source组件传递过来的日志信息。Channel中的数据直到进入到下一个channel中或者进入终端才会被删除。当sink写入失败后,可以自动重写,不会造成数据丢失,因此很可靠。
channel的类型很多比如:内存中、jdbc数据源中、文件形式存储等。
常见采集的数据类型:
Memory Channel、File Channel、JDBC Channel、KafkaChannel、Spillable Memory Channel等
不同Channel具体作用:
(官方:事件存储在具有可配置最大大小的内存中队列中。对于需要更高吞吐量并准备在代理发生故障时丢失分段数据的流而言,它是理想的选择)
(官方:事件存储在由数据库支持的持久存储中。JDBC通道当前支持嵌入式Derby。这是一个持久的通道,非常适合可恢复性很重要的流程)
(官方:事件存储在Kafka集群中(必须单独安装)。Kafka提供高可用性和复制功能,因此,如果代理或kafka代理崩溃,则事件可立即用于其他接收器)
即:先存在内存中,如果内存中数据达到阀值则flush到文件中。(官方:事件存储在内存队列中和磁盘上。内存中队列充当主存储,磁盘充当溢出。使用嵌入式文件通道管理磁盘存储。当内存中队列已满时,其他传入事件将存储在文件通道中。该通道非常适合在正常操作期间需要高存储通道吞吐量的流,但同时又需要更大容量的文件通道,以更好地容忍间歇性接收器侧中断或排水速率下降。在这种异常情况下,吞吐量将大约降低到文件通道速度。如果代理崩溃或重新启动,则当代理联机时,只会恢复磁盘上存储的事件。该频道目前处于实验阶段,不建议在生产中使用。)
**主要作用:**接受channel写入的数据以指定的形式表现出来(或存储或展示)。
sink的表现形式很多比如:打印到控制台、hdfs上、avro服务中、文件中等。
常见采集的数据类型:
HDFS Sink、Hive Sink、Logger Sink、Avro Sink、Thrift Sink、File Roll Sink、HBaseSink、Kafka Sink等
不同Sink具体作用:
(官方:此接收器将事件写入Hadoop分布式文件系统(HDFS)。当前,它支持创建文本和序列文件。它支持两种文件类型的压缩。可以根据经过的时间或数据大小或事件数定期滚动文件(关闭当前文件并创建一个新文件)。它还按时间戳或事件发生的机器之类的属性对数据进行存储/分区。HDFS目录路径可能包含格式转义序列,将由HDFS接收器替换,以生成用于存储事件的目录/文件名)
(在INFO级别记录事件。通常用于测试/调试目的。)
(发送到此接收器的Flume事件将转换为Avro事件并发送到配置的主机名/端口对。这些事件是从已配置的通道中以已配置的批次大小批量获取的)
(将事件存储在本地文件系统上。)
含义:event是Flume NG传输的数据的基本单位,也是事务的基本单位。
在文本文件,通常是一行记录就是一个event。
网络消息传输系统中,一条消息就是一个event。
结构:event里有header、body
Event里面的header类型:Map
我们可以在source中自定义header的key:value,在某些channel和sink中使用header。
#example.conf:单节点Flume配置
#命名Agent a1的组件
a1.sources = r1
a1.sinks = k1
a1.channels = c1
#描述/配置Source
a1.sources.r1.type = netcat
a1.sources.r1.bind = 0.0.0.0
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
#为Channle绑定Source和Sink
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
$ bin/flume-ng agent --conf conf --conf-file example.conf --name a1 -Dflume.root.logger=INFO,console
在windows中通过nc向端口发送数据。
nc hadoop01 44444
Flume常用Sinks有Log Sink,HDFS Sink,Avro Sink,Kafka Sink,当然也可以自定义Sink。
Logger Sink以INFO 级别的日志记录到log日志中,这种方式通常用于测试。
Property Name Default Description
channel@ –
type@ – 类型指定:logger
maxBytesToLog 16 能够记录的最大Event Body字节数
Sink数据到HDFS,目前支持text 和 sequence files两种文件格式,支持压缩,并可以对数据进行分区,分桶存储。
Name Default Description
channel@ –
type@ – 指定类型:hdfs
hdfs.path@ – HDFS的路径,eg hdfs://namenode/flume/webdata/
hdfs.filePrefix FlumeData 保存数据文件的前缀名
hdfs.fileSuffix – 保存数据文件的后缀名
hdfs.inUsePrefix – 临时写入的文件前缀名
hdfs.inUseSuffix .tmp 临时写入的文件后缀名
hdfs.rollInterval 30 间隔多长将临时文件滚动成最终目标文件,单位:秒,
如果设置成0,则表示不根据时间来滚动文件
hdfs.rollSize 1024 当临时文件达到多少(单位:bytes)时,滚动成目标文件,
如果设置成0,则表示不根据临时文件大小来滚动文件
hdfs.rollCount 10 当 events 数据达到该数量时候,将临时文件滚动成目标文件,
如果设置成0,则表示不根据events数据来滚动文件
hdfs.idleTimeout 0 当目前被打开的临时文件在该参数指定的时间(秒)内,
没有任何数据写入,则将该临时文件关闭并重命名成目标文件
hdfs.batchSize 100 每个批次刷新到 HDFS 上的 events 数量
hdfs.codeC – 文件压缩格式,包括:gzip, bzip2, lzo, lzop, snappy
hdfs.fileType SequenceFile 文件格式,包括:SequenceFile, DataStream,CompressedStre,
当使用DataStream时候,文件不会被压缩,不需要设置hdfs.codeC;
当使用CompressedStream时候,必须设置一个正确的hdfs.codeC值;
hdfs.maxOpenFiles 5000 最大允许打开的HDFS文件数,当打开的文件数达到该值,
最早打开的文件将会被关闭
hdfs.minBlockReplicas – HDFS副本数,写入 HDFS 文件块的最小副本数。
该参数会影响文件的滚动配置,一般将该参数配置成1,才可以按照配置正确滚动文件
hdfs.writeFormat Writable 写 sequence 文件的格式。包含:Text, Writable(默认)
hdfs.callTimeout 10000 执行HDFS操作的超时时间(单位:毫秒)
hdfs.threadsPoolSize 10 hdfs sink 启动的操作HDFS的线程数
hdfs.rollTimerPoolSize 1 hdfs sink 启动的根据时间滚动文件的线程数
hdfs.kerberosPrincipal – HDFS安全认证kerberos配置
hdfs.kerberosKeytab – HDFS安全认证kerberos配置
hdfs.proxyUser 代理用户
hdfs.round false 是否启用时间上的”舍弃”
hdfs.roundValue 1 时间上进行“舍弃”的值
hdfs.roundUnit second 时间上进行”舍弃”的单位,包含:second,minute,hour
hdfs.timeZone Local Time 时区。
hdfs.useLocalTimeStamp false 是否使用当地时间
hdfs.closeTries 0 Number hdfs sink 关闭文件的尝试次数;
如果设置为1,当一次关闭文件失败后,hdfs sink将不会再次尝试关闭文件,
这个未关闭的文件将会一直留在那,并且是打开状态;
设置为0,当一次关闭失败后,hdfs sink会继续尝试下一次关闭,直到成功
hdfs.retryInterval 180 hdfs sink 尝试关闭文件的时间间隔,
如果设置为0,表示不尝试,相当于于将hdfs.closeTries设置成1
serializer TEXT 序列化类型
serializer.*
flume案例1
:exec -->memory -->hdfs
vi ./conf/e2h.conf
#定义source|channel|sink组件
a1.sources = r1
a1.sinks = k1
a1.channels = c1
#配置r1的属性
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /home/f_log
#配置sinks的属性
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /flume/events/dt=%y-%m-%d
a1.sinks.k1.hdfs.filePrefix = events-
a1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 10
a1.sinks.k1.hdfs.roundUnit = minute
a1.sinks.k1.hdfs.useLocalTimeStamp=true
#配置channel的属性
a1.channels.c1.type = memory
a1.channels.c1.capacity = 10000
a1.channels.c1.transactionCapacity = 10000
#绑定source与sink于channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
测试:
flume-ng agent -c conf/ -f conf/e2h.conf -n a1 -Dflume.root.logger=INFO,console
spooldir + memory + logger
vi ./conf/spooldir
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=spoolDir
a1.sources.r1.spoolDir=/home/flumedata/spool1
a1.sources.r1.fileHeader=true
a1.sources.r1.fileHeaderKey=file
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.sinks.s1.type = logger
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
启动agent:
flume-ng agent -c ./conf/ -f ./conf/exec -n a1 -Dflume.root.logger=INFO,console
vi ./conf/syslogtcp
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=syslogtcp
a1.sources.r1.port=6666
a1.sources.r1.host=hadoop01
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.sinks.s1.type = logger
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
启动agent:
flume-ng agent -c ./conf/ -f ./conf/syslogtcp -n a1 -Dflume.root.logger=INFO,console
测试:
echo "hello qianfeng" | nc hadoop01 6666
vi ./conf/http
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=org.apache.flume.source.http.HTTPSource
a1.sources.r1.port=6666
a1.sources.r1.bind=hadoop01
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.sinks.s1.type = logger
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
启动agent:
flume-ng agent -c ./conf/ -f ./conf/http -n a1 -Dflume.root.logger=INFO,console
测试:
curl -X POST -d '[{"headers":{"time":"2017-06-13"},"body":"this is http"}]' http://hadoop01:6666
vi ./conf/file
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=exec
a1.sources.r1.command= tail -f /home/flumedata/exedata
a1.channels.c1.type=file
a1.channels.c1.checkpointDir=/home/flumedata/checkpoint
a1.channels.c1.dataDirs=/home/flumedata/data
a1.sinks.s1.type = hdfs
a1.sinks.s1.hdfs.path = hdfs://qianfeng/flume/events/%y-%m-%d/%H%M/%S
a1.sinks.s1.hdfs.filePrefix = qianfeng-
a1.sinks.s1.hdfs.fileSuffix=.log
a1.sinks.s1.hdfs.inUseSuffix=.tmp
a1.sinks.s1.hdfs.rollInterval=2
a1.sinks.s1.hdfs.rollSize=1024
a1.sinks.s1.hdfs.fileType=DataStream
a1.sinks.s1.hdfs.writeFormat=Text
a1.sinks.s1.hdfs.round = true
a1.sinks.s1.hdfs.roundValue = 1
a1.sinks.s1.hdfs.roundUnit = second
a1.sinks.s1.hdfs.useLocalTimeStamp=false
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
启动agent:
flume-ng agent -c ./conf/ -f ./conf/file -n a1 -Dflume.root.logger=INFO,console
接收组(Sink groups)允许用户将多个接收器分组到一个实体中。 接收器处理器(Sink processors)可用于在组内的所有接收器上提供负载均衡功能,或在临时故障(temporal failure)的情况下实现从一个接收器到另一个接收器的故障转移。
Property Name | Default | Description |
---|---|---|
sinks | – | 以空格分隔的参与组的接收器列表 |
processor.type | default | 组件类型名称需要是default,failover或load_balance |
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = load_balance
Default Sink Processor
默认接收器只接受一个接收器。 用户不必为单个接收器创建处理器(接收器组)。 相反,用户可以遵循本用户指南中上面解释的源 - 通道 - 接收器模式。
Failover Sink Processor
故障转移接收器维护一个优先级的接收器列表,保证只要有一个可用的事件将被处理(传递)。
故障转移机制的工作原理是将故障接收器降级到池中,在池中为它们分配一个冷却期,在重试之前随顺序故障而增加。 一旦接收器成功发送事件后,它将恢复到实时池。 接收器优先级与之相关,数量越大,优先级越高。 如果在发送事件时接收器发生故障,则应尝试下一个具有最高优先级的接收器以发送事件。 例如,在优先级为80的接收器之前激活优先级为100的接收器。如果未指定优先级,则根据配置中指定接收器的顺序确定thr优先级。
要进行配置,请将接收器组处理器设置为故障转移failover
并为所有单个接收器设置优先级。 所有指定的优先级必须是唯一的 此外,可以使用maxpenalty
属性设置故障转移的时间上限(以毫秒为单位)。
Property Name | Default | Description |
---|---|---|
sinks | – | 以空格分隔的参与组的接收器列表 |
processor.type | default | The component type name, needs to be failover |
processor.priority. | - | 优先值。 必须是与当前接收器组关联的接收器实例之一。较高优先级值Sink较早被激活。 绝对值越大表示优先级越高 |
processor.maxpenalty | 30000 | 组件类型名称需要是default,failover或load_balance |
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
负载均衡接收处理器提供了在多个接收器上进行负载均衡流量的功能。 它维护一个索引的活动接收器列表,必须在其上分配负载。 实现支持使用round_robin
或随机选择机制(random selection)分配负载。默认round_robin
类型,但可以通过配置覆盖。 通过从继承AbstractSinkSelector
的实现自定义选择机制。
调用时,选择器使用其配置的选择机制选择下一个接收器并调用它。 对于round_robin
和random
如果所选接收器无法传递事件,则处理器通过其配置的选择机制选择下一个可用接收器。 此实现不会将失败的接收器列入黑名单,而是继续乐观地尝试每个可用的接收器。 如果所有接收器调用都导致失败,则选择器将故障传播到接收器运行器。
如果启用了backoff
,则接收器处理器会将失败的接收器列入黑名单,将其删除以供给定超时的选择。 当超时结束时,如果接收器仍然没有响应,则超时会呈指数级增加,以避免在无响应的接收器上长时间等待时卡住。 在禁用此功能的情况下,在循环中,所有失败的接收器负载将被传递到下一个接收器中,因此不均衡
Property Name | Default | Description |
---|---|---|
sinks | – | 以空格分隔的参与组的接收器列表 |
processor.type | default | 组件类型名称需要为load_balance |
processor.backoff | false | 失败的接收器是否会以指数方式退回。 |
processor.selector | round_robin |
选择机制。 必须是round_robin,random或自定义类的FQCN,它继承自AbstractSinkSelector |
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
Flume中的拦截器(interceptor),用户Source读取events发送到Sink的时候,在events header中加入一些有用的信息,或者对events的内容进行过滤,完成初步的数据清洗。这在实际业务场景中非常有用,Flume-ng 1.6中目前提供了以下拦截器:Timestamp Interceptor;
Host Interceptor;
Static Interceptor;
UUID Interceptor;
Morphline Interceptor;
Search and Replace Interceptor;
Regex Filtering Interceptor;
Regex Extractor Interceptor;
Timestamp Interceptor
时间戳拦截器,将当前时间戳(毫秒)加入到events header中,key名字为:timestamp,值为当前时间戳。用的不是很多。比如在使用HDFS Sink时候,根据events的时间戳生成结果文件,hdfs.path = hdfs://cdh5/tmp/dap/%Y%m%d
hdfs.filePrefix = log_%Y%m%d_%H
会根据时间戳将数据写入相应的文件中。
但可以用其他方式代替(设置useLocalTimeStamp = true)。
Host Interceptor
主机名拦截器。将运行Flume agent的主机名或者IP地址加入到events header中,key名字为:host(也可自定义)。
根据上面的Source,拦截器的配置如下:
vi ./conf/ts1
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=exec
a1.sources.r1.command= tail -f /home/flumedata/exedata
a1.sources.r1.interceptors = i1 i2 i3
a1.sources.r1.interceptors.i1.type = timestamp
a1.sources.r1.interceptors.i1.preserveExisting=true
a1.sources.r1.interceptors.i2.type = host
a1.sources.r1.interceptors.i2.hostHeader = hostname
a1.sources.r1.interceptors.i2.preserveExisting=true
a1.sources.r1.interceptors.i3.type = static
a1.sources.r1.interceptors.i3.key = city
a1.sources.r1.interceptors.i3.value = NEW_YORK
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.sinks.s1.type = hdfs
a1.sinks.s1.hdfs.path = hdfs://hadoop/flume/events/%y-%m-%d/%H%M/%S
a1.sinks.s1.hdfs.filePrefix = %{hostname}-
a1.sinks.s1.hdfs.fileSuffix=.log
a1.sinks.s1.hdfs.inUseSuffix=.tmp
a1.sinks.s1.hdfs.rollInterval=2
a1.sinks.s1.hdfs.rollSize=1024
a1.sinks.s1.hdfs.fileType=DataStream
a1.sinks.s1.hdfs.writeFormat=Text
a1.sinks.s1.hdfs.round = true
a1.sinks.s1.hdfs.roundValue = 1
a1.sinks.s1.hdfs.roundUnit = second
a1.sinks.s1.hdfs.useLocalTimeStamp=false
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
启动agent:
flume-ng agent -c ./conf/ -f ./conf/ts -n a1 -Dflume.root.logger=INFO,console
该配置用于将source的events保存到HDFS上hdfs://cdh5/tmp/lxw1234的目录下,文件名为lxw1234_<主机名>.log
Static Interceptor
静态拦截器,用于在events header中加入一组静态的key和value。
根据上面的Source,拦截器的配置如下:
source 拦截器
agent_lxw1234.sources.sources1.interceptors = i1
agent_lxw1234.sources.sources1.interceptors.i1.type = static
agent_lxw1234.sources.sources1.interceptors.i1.preserveExisting = true
agent_lxw1234.sources.sources1.interceptors.i1.key = static_key
agent_lxw1234.sources.sources1.interceptors.i1.value = static_value
# sink 1 配置
agent_lxw1234.sinks.sink1.type = hdfs
agent_lxw1234.sinks.sink1.hdfs.path = hdfs://cdh5/tmp/lxw1234
agent_lxw1234.sinks.sink1.hdfs.filePrefix = lxw1234_%{static_key}
agent_lxw1234.sinks.sink1.hdfs.fileSuffix = .log
agent_lxw1234.sinks.sink1.hdfs.fileType = DataStream
agent_lxw1234.sinks.sink1.hdfs.useLocalTimeStamp = true
agent_lxw1234.sinks.sink1.hdfs.writeFormat = Text
agent_lxw1234.sinks.sink1.hdfs.rollCount = 0
agent_lxw1234.sinks.sink1.hdfs.rollSize = 0
agent_lxw1234.sinks.sink1.hdfs.rollInterval = 600
agent_lxw1234.sinks.sink1.hdfs.batchSize = 500
agent_lxw1234.sinks.sink1.hdfs.threadsPoolSize = 10
agent_lxw1234.sinks.sink1.hdfs.idleTimeout = 0
agent_lxw1234.sinks.sink1.hdfs.minBlockReplicas = 1
agent_lxw1234.sinks.sink1.channel = fileChannel
UUID Interceptor
UUID拦截器,用于在每个events header中生成一个UUID字符串,例如:b5755073-77a9-43c1-8fad-b7a586fc1b97。生成的UUID可以在sink中读取并使用。根据上面的source,拦截器的配置如下:
## source 拦截器
agent_lxw1234.sources.sources1.interceptors = i1
agent_lxw1234.sources.sources1.interceptors.i1.type = org.apache.flume.sink.solr.morphline.UUIDInterceptor$Builder
agent_lxw1234.sources.sources1.interceptors.i1.headerName = uuid
agent_lxw1234.sources.sources1.interceptors.i1.preserveExisting = true
agent_lxw1234.sources.sources1.interceptors.i1.prefix = UUID_
# sink 1 配置
agent_lxw1234.sinks.sink1.type = logger
agent_lxw1234.sinks.sink1.channel = fileChannel
正则拦截器
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=exec
a1.sources.r1.command= tail -f /home/flumedata/exedata
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = regex_filter
a1.sources.r1.interceptors.i1.regex=^[0-9].*$
a1.sources.r1.interceptors.i1.excludeEvents=false
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.sinks.s1.type = logger
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
启动agent:
flume-ng agent -c ./conf/ -f ./conf/rex -n a1 -Dflume.root.logger=INFO,console
#####案例3、复制选择器
vi ./conf/rep
a1.sources=r1
a1.channels=c1 c2
a1.sinks=s1 s2
a1.sources.r1.type=exec
a1.sources.r1.command= tail -f /home/flumedata/exedata
a1.sources.r1.selector.type = replicating
a1.sources.r1.selector.optional = c2
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.channels.c2.type=memory
a1.channels.c2.capacity=1000
a1.channels.c2.transactionCapacity=100
a1.channels.c2.keep-alive=3
a1.channels.c2.byteCapacityBufferPercentage = 20
a1.channels.c2.byteCapacity = 800000
a1.sinks.s1.type = logger
a1.sinks.s2.type = hdfs
a1.sinks.s2.hdfs.path = hdfs://hadoop/flume/events/%y-%m-%d/%H%M/%S
a1.sinks.s2.hdfs.filePrefix = event-
a1.sinks.s2.hdfs.fileSuffix=.log
a1.sinks.s2.hdfs.inUseSuffix=.tmp
a1.sinks.s2.hdfs.rollInterval=2
a1.sinks.s2.hdfs.rollSize=1024
a1.sinks.s2.hdfs.fileType=DataStream
a1.sinks.s2.hdfs.writeFormat=Text
a1.sinks.s2.hdfs.round = true
a1.sinks.s2.hdfs.roundValue = 1
a1.sinks.s2.hdfs.roundUnit = second
a1.sinks.s2.hdfs.useLocalTimeStamp=true
a1.sources.r1.channels=c1 c2
a1.sinks.s1.channel=c1
a1.sinks.s2.channel=c2
#####案例4、复分选择器
vi ./conf/mul
a1.sources=r1
a1.channels=c1 c2
a1.sinks=s1 s2
a1.sources.r1.type=org.apache.flume.source.http.HTTPSource
a1.sources.r1.port=6666
a1.sources.r1.bind=hadoop01
a1.sources.r1.selector.type = multiplexing
a1.sources.r1.selector.header = status
a1.sources.r1.selector.mapping.CZ = c1
a1.sources.r1.selector.mapping.US = c2
a1.sources.r1.selector.default = c1
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.channels.c2.type=memory
a1.channels.c2.capacity=1000
a1.channels.c2.transactionCapacity=100
a1.channels.c2.keep-alive=3
a1.channels.c2.byteCapacityBufferPercentage = 20
a1.channels.c2.byteCapacity = 800000
a1.sinks.s1.type = logger
a1.sinks.s2.type = hdfs
a1.sinks.s2.hdfs.path = hdfs://hadoop/flume/events/%y-%m-%d/%H%M/%S
a1.sinks.s2.hdfs.filePrefix = event-
a1.sinks.s2.hdfs.fileSuffix=.log
a1.sinks.s2.hdfs.inUseSuffix=.tmp
a1.sinks.s2.hdfs.rollInterval=2
a1.sinks.s2.hdfs.rollSize=1024
a1.sinks.s2.hdfs.fileType=DataStream
a1.sinks.s2.hdfs.writeFormat=Text
a1.sinks.s2.hdfs.round = true
a1.sinks.s2.hdfs.roundValue = 1
a1.sinks.s2.hdfs.roundUnit = second
a1.sinks.s2.hdfs.useLocalTimeStamp=true
a1.sources.r1.channels=c1 c2
a1.sinks.s1.channel=c1
a1.sinks.s2.channel=c2
测试数据:
curl -X POST -d '[{"headers":{"status":"2017-06-13"},"body":"this is default"}]' http://hadoop01:6666
curl -X POST -d '[{"headers":{"status":"CZ"},"body":"this is CZ"}]' http://hadoop01:6666
curl -X POST -d '[{"headers":{"status":"US"},"body":"this is US"}]' http://hadoop01:6666
curl -X POST -d '[{"headers":{"status":"ss"},"body":"this is ss"}]' http://hadoop01:6666
flume集群搭建
hadoop01的配置:
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=syslogtcp
a1.sources.r1.port=6666
a1.sources.r1.host=hadoop01
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.sinks.s1.type =avro
a1.sinks.s1.hostname=hadoop03
a1.sinks.s1.port=6666
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
hadoop02的配置:
a1.sources=r1
a1.channels=c1
a1.sinks=s1
a1.sources.r1.type=syslogtcp
a1.sources.r1.port=6666
a1.sources.r1.host=hadoop02
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=100
a1.channels.c1.keep-alive=3
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
a1.sinks.s1.type =avro
a1.sinks.s1.hostname=hadoop03
a1.sinks.s1.port=6666
a1.sources.r1.channels=c1
a1.sinks.s1.channel=c1
hadoop03的配置:
agent.sources=r1
agent.channels=c1
agent.sinks=s1
agent.sources.r1.type=avro
agent.sources.r1.port=6666
agent.sources.r1.bind=hadoop03
agent.channels.c1.type=memory
agent.channels.c1.capacity=1000
agent.channels.c1.transactionCapacity=100
agent.channels.c1.keep-alive=3
agent.channels.c1.byteCapacityBufferPercentage = 20
agent.channels.c1.byteCapacity = 800000
agent.sinks.s1.type =logger
agent.sources.r1.channels=c1
agent.sinks.s1.channel=c1
####然后测试:
先启动master的agent:
flume-ng agent -c ./conf/ -f ./conf/master -n agent -Dflume.root.logger=INFO,console &
然后再启动slave的agent:
flume-ng agent -c ./conf/ -f ./conf/slave1 -n a1 -Dflume.root.logger=INFO,console &
flume-ng agent -c ./conf/ -f ./conf/slave2 -n a1 -Dflume.root.logger=INFO,console &
由于在实际工作中,数据的生产方式极具多样性,Flume 虽然包含了一些内置的机制来采集数据,但是更多的时候用户更希望能将应用程序和flume直接相通。所以这边运行用户开发应用程序,通过IPC或者RPC连接flume并往flume发送数据。
RPC client interface
Flume的RpcClient实现了Flume的RPC机制。用户的应用程序可以很简单的调用Flume Client SDK的append(Event) 或者appendBatch(List) 方法发送数据,不用担心底层信息交换的细节。用户可以提供所需的event通过直接实现Event接口,例如可以使用简单的方便的实现SimpleEvent类或者使用EventBuilder的writeBody()静态辅助方法。
自Flume 1.4.0起,Avro是默认的RPC协议。NettyAvroRpcClient和ThriftRpcClient实现了RpcClient接口。实现中我们需要知道我们将要连接的目标flume agent的host和port用于创建client实例,然后使用RpcClient发送数据到flume agent。
官网给了一个Avro RPCclients的例子,这边直接拿来做实际测试例子。
这里我们把client.init(“host.example.org”,41414);
改成 client.init(“192.168.233.128”,50000); 与我们的主机对接
import org.apache.flume.Event;
import org.apache.flume.EventDeliveryException;
import org.apache.flume.api.RpcClient;
import org.apache.flume.api.RpcClientFactory;
import org.apache.flume.event.EventBuilder;
import java.nio.charset.Charset;
public class MyApp {
public static voidmain(String[] args) {
MyRpcClientFacade client = new MyRpcClientFacade();
// Initializeclient with the remote Flume agent's host and port
//client.init("host.example.org",41414);
client.init("192.168.233.128",50000);
// Send 10events to the remote Flume agent. That agent should be
// configured tolisten with an AvroSource.
String sampleData = "Hello Flume!";
for (int i =0; i < 10; i++) {
client.sendDataToFlume(sampleData);
}
client.cleanUp();
}
}
class MyRpcClientFacade {
private RpcClient client;
private String hostname;
private int port;
public void init(String hostname, int port) {
// Setup the RPCconnection
this.hostname = hostname;
this.port = port;
this.client = RpcClientFactory.getDefaultInstance(hostname, port);
// Use thefollowing method to create a thrift client (instead of the above line):
// this.client = RpcClientFactory.getThriftInstance(hostname, port);
}
public void sendDataToFlume(String data) {
// Create aFlume Event object that encapsulates the sample data
Event event = EventBuilder.withBody(data, Charset.forName("UTF-8"));
// Send theevent
try {
client.append(event);
} catch (EventDeliveryException e) {
// clean up andrecreate the client
client.close();
client = null;
client = RpcClientFactory.getDefaultInstance(hostname, port);
// Use thefollowing method to create a thrift client (instead of the above line):
// this.client =RpcClientFactory.getThriftInstance(hostname, port);
}
}
public void cleanUp() {
// Close the RPCconnection
client.close();
}
}
下面是代理配置:
#配置文件:avro_client_case20.conf
# 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.port = 50000
a1.sources.r1.host = 192.168.233.128
a1.sources.r1.channels = c1
# Describe the sink
a1.sinks.k1.channel = c1
a1.sinks.k1.type = logger
# Use a channel which buffers events inmemory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
这里要注意下,之前说了,在接收端需要AvroSource或者Thrift Source来监听接口。所以配置代理的时候要把a1.sources.r1.type 写成avro或者thrift
flume-ng agent -c conf -f conf/avro_client_case20.conf-n a1 -Dflume.root.logger=INFO,console
启动成功后
在eclipse 里运行JAVA程序,当然也可以打包后在服务器上运行JAVA程序。
这里要说明下,开发代码中client.append(event)不仅仅可以发送一条数据,也可以发送一个List(string) 的数据信息,也就是批量发送。
Failover Client
这个类包封装了Avro RPCclient的类默认提供故障处理能力。hosts采用空格分开host:port所代表的flume agent,构成一个故障处理组。这Failover RPC Client目前不支持thrift。如果当前选择的host agent有问题,这个failover client会自动负载到组中下一个host中。
下面是官网开发例子:
// Setup properties for the failover
Properties props = new Properties();
props.put("client.type", "default_failover");
// List of hosts (space-separated list of user-chosen host aliases)
props.put("hosts", "h1 h2 h3");
// host/port pair for each host alias
String host1 = "host1.example.org:41414";
String host2 = "host2.example.org:41414";
String host3 = "host3.example.org:41414";
props.put("hosts.h1", host1);
props.put("hosts.h2", host2);
props.put("hosts.h3", host3);
// create the client with failover properties
RpcClient client = RpcClientFactory.getInstance(props);
下面是测试的开发例子
import org.apache.flume.Event;
import org.apache.flume.EventDeliveryException;
import org.apache.flume.api.RpcClient;
import org.apache.flume.api.RpcClientFactory;
import org.apache.flume.event.EventBuilder;
import java.nio.charset.Charset;
import java.util.Properties;
public class Failover_Client {
public static void main(String[] args) {
MyRpcClientFacade2 client = new MyRpcClientFacade2();
// Initialize client with the remote Flume agent's host and port
client.init();
// Send 10 events to the remote Flume agent. That agent should be
// configured to listen with an AvroSource.
String sampleData = "Hello Flume!";
for (int i = 0; i < 10; i++) {
client.sendDataToFlume(sampleData);
}
client.cleanUp();
}
}
class MyRpcClientFacade2 {
private RpcClient client;
private String hostname;
private int port;
public void init() {
// Setup the RPC connection
// Use the following method to create a thrift client (instead of the above line):
// this.client = RpcClientFactory.getThriftInstance(hostname, port);
// Setup properties for the failover
Properties props = new Properties();
props.put("client.type", "default_failover");
// List of hosts (space-separated list of user-chosen host aliases)
props.put("hosts", "h1 h2 h3");
// host/port pair for each host alias
String host1 = "192.168.233.128:50000";
String host2 = "192.168.233.128:50001";
String host3 = "192.168.233.128:50002";
props.put("hosts.h1", host1);
props.put("hosts.h2", host2);
props.put("hosts.h3", host3);
// create the client with failover properties
client = RpcClientFactory.getInstance(props);
}
public void sendDataToFlume(String data) {
// Create a Flume Event object that encapsulates the sample data
Event event = EventBuilder.withBody(data, Charset.forName("UTF-8"));
// Send the event
try {
client.append(event);
} catch (EventDeliveryException e) {
// clean up and recreate the client
client.close();
client = null;
client = RpcClientFactory.getDefaultInstance(hostname, port);
// Use the following method to create a thrift client (instead of the above line):
// this.client = RpcClientFactory.getThriftInstance(hostname, port);
}
}
public void cleanUp() {
// Close the RPC connection
client.close();
}
}
这边代码设三个host用于故障转移,这里偷懒,用同一个主机的3个端口模拟。代码还是将Hello Flume 发送10遍给第一个flume代理,当第一个代理故障的时候,则发送给第二个代理,以顺序进行故障转移。
下面是代理配置沿用之前的那个,并对配置文件进行拷贝,
cp avro_client_case20.conf avro_client_case21.conf
cp avro_client_case20.conf avro_client_case22.conf
分别修改avro_client_case21.conf与avro_client_case22.conf中的
a1.sources.r1.port= 50001 与a1.sources.r1.port = 50002
敲命令
flume-ng agent -c conf -f conf/avro_client_case20.conf-n a1 -Dflume.root.logger=INFO,console
flume-ng agent -c conf -f conf/avro_client_case21.conf-n a1 -Dflume.root.logger=INFO,console
flume-ng agent -c conf -f conf/avro_client_case22.conf-n a1 -Dflume.root.logger=INFO,console
启动成功后
在eclipse 里运行JAVA程序Failover_Client.java,当然也可以打包后在服务器上运行JAVA程序。
我们可以看到第一个代理终端收到了,数据而其他2个终端没有数据。
然后我们把第一个终端的进程关掉,再运行一遍client程序,然后会发现这个时候是发生到第二个终端中。当第二个终端也关闭的时候,再发送数据,则是发送到最后一个终端。这里我们可以看到,故障转移的代理主机转移是采用顺序序列的。
, port);
// Use the following method to create a thrift client (instead of the above line):
// this.client = RpcClientFactory.getThriftInstance(hostname, port);
}
}
public void cleanUp() {
// Close the RPC connection
client.close();
}
}
这边代码设三个host用于故障转移,这里偷懒,用同一个主机的3个端口模拟。代码还是将Hello Flume 发送10遍给第一个flume代理,当第一个代理故障的时候,则发送给第二个代理,以顺序进行故障转移。
下面是代理配置沿用之前的那个,并对配置文件进行拷贝,
cp avro_client_case20.conf avro_client_case21.conf
cp avro_client_case20.conf avro_client_case22.conf
分别修改avro_client_case21.conf与avro_client_case22.conf中的
a1.sources.r1.port= 50001 与a1.sources.r1.port = 50002
**敲命令**
flume-ng agent -c conf -f conf/avro_client_case20.conf-n a1 -Dflume.root.logger=INFO,console
flume-ng agent -c conf -f conf/avro_client_case21.conf-n a1 -Dflume.root.logger=INFO,console
flume-ng agent -c conf -f conf/avro_client_case22.conf-n a1 -Dflume.root.logger=INFO,console
启动成功后
在eclipse 里运行JAVA程序Failover_Client.java,当然也可以打包后在服务器上运行JAVA程序。
我们可以看到第一个代理终端收到了,数据而其他2个终端没有数据。
然后我们把第一个终端的进程关掉,再运行一遍client程序,然后会发现这个时候是发生到第二个终端中。当第二个终端也关闭的时候,再发送数据,则是发送到最后一个终端。这里我们可以看到,故障转移的代理主机转移是采用顺序序列的。
## flume的事务机制
flume的事务机制(类似数据库的事务机制):flume使用两个独立的事务分别负责从source到channel以及从channnel到sink的事件传递。比如spooling directory source为文件的每一行创建一个时间,一旦事务中所有的事件全部传递到channnel且提交成功,那么soucre就将该文件标记为完成。同理,事务以类似的方式处理从channel到sink的传递过程,如果因为某种原因使得事件无法记录,那么事务将会回滚。且所有的时事件都会保持到channel中,等待重新传递。
## flume采集数据会丢失么?
不会,channel存储可以存储在file中数据传输自身有事务