目录
[(2) Source](#(2) Source)
[1)安装使用netcat 工具](#1)安装使用netcat 工具)
[6)在HDFS 上查看文件](#6)在HDFS 上查看文件)
[1、Flume 事务](#1、Flume 事务)
[2、Flume Agent 内部原理](#2、Flume Agent 内部原理)
[3、Flume 拓扑结构](#3、Flume 拓扑结构)
一、概述
1、介绍
Flume 是Cloudera 提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传 输的系统。Flume基于流式架构,灵活简单。
Flume官网地址
http://flume.apache.org/文档查看地址
http://flume.apache.org/FlumeUserGuide.html
2、基本架构

组件说明:
(1)Agent
Agent 是一个JVM进程,它以事件的形式将数据从源头送至目的。 Agent 主要有3个部分组成,Source、Channel、Sink。
(2) Source
Source 是负责接收数据到Flume Agent的组件。Source组件可以处理各种类型、各种格式的日志数据,包括avro 、thrift、exec 、jms、spooling directory、netcat、sequence generator、syslog、http、legacy。
(3)Sink
Sink 不断地轮询 Channel 中的事件且批量地移除它们,并将这些事件批量写入到存储或索引系统、或者被发送到另一个Flume Agent。
Sink 组件目的地包括hdfs、logger、avro 、thrift、ipc、file、HBase、solr、自定义。
(4)Channel
Channel 是位于Source 和Sink之间的缓冲区。因此,Channel允许Source和Sink运作在不同的速率上。Channel 是线程安全的,可以同时处理几个Source 的写入操作和几个 Sink 的读取操作。
Flume 自带两种Channel:Memory Channel 和 File Channel 以及 Kafka Channel。
Memory Channel 是内存中的队列。Memory Channel在不需要关心数据丢失的情景下适用。如果需要关心数据丢失,那么Memory Channel就不应该使用,因为程序死亡、机器宕 机或者重启都会导致数据丢失。 File Channel 将所有事件写到磁盘。因此在程序关闭或机器宕机的情况下不会丢失数据。
(5)Event
传输单元,Flume 数据传输的基本单元,以 Event 的形式将数据从源头送至目的地。 Event 由Header 和Body两部分组成,Header用来存放该event的一些属性,为K-V结构, Body 用来存放该条数据,形式为字节数组。
二、安装与入门
1、Flume安装
(1)下载
下载地址
http://archive.apache.org/dist/flume/
(2)上传并解压
tar -zxvf apache-flume-1.7.0-bin.tar.gz -C /opt/module/
mv apache-flume-1.7.0-bin/ flume

(3)修改配置文件
将flume/conf 下的 flume-env.sh.template 文件修改为flume-env.sh,并配置 flume env.sh 文件
mv flume-env.sh.template flume-env.sh
vi flume-env.sh
export JAVA_HOME=/opt/module/jdk1.8

2、入门案例
(1)监控端口数据
使用Flume监听一个端口,收集该端口数据,并打印到控制台。
netcat Source官网参数
https://flume.apache.org/FlumeUserGuide.html#netcat-tcp-source
1)安装使用netcat 工具
a、安装netcat 工具
sudo yum install -y nc
b、开启一个服务端监听4444端口
nc -lk 4444

c、开启一个客户端向4444端口发送数据
nc ip 端口

观察服务端, 收到客户端数据

2)创建配置文件
官网示例
https://flume.apache.org/FlumeUserGuide.html#a-simple-example 创建Flume Agent 配置文件flume-netcat-logger.conf;在flume 目录下创建job文件夹并进入job文件夹。
mkdir job
cd job/
在job文件夹下创建Flume Agent配置文件flume-netcat-logger.conf。
vim flume-netcat-logger.conf
在flume-netcat-logger.conf 文件中添加如下内容
# Name the components on this agent
# a1 表示agent的名字 r1 表示a1的source的名称
a1.sources = r1
# k1 表示a1的sinks的名称
a1.sinks = k1
# c1 表示a1的channels的名称
a1.channels = c1
# Describe/configure the source
# 表示a1的输入源类型为netcat端口类型
a1.sources.r1.type = netcat
# 表示a1的监听的主机
a1.sources.r1.bind = localhost
# 表示a1的监听的端口号
a1.sources.r1.port = 44444
# Describe the sink
# 表示a1的输出目的地是控制台logger类型
a1.sinks.k1.type = logger
# Use a channel which buffers events in memory
# 表示a1的channel类型是memory内存型
a1.channels.c1.type = memory
# 表示a1的channel总容量1000个event
a1.channels.c1.capacity = 1000
# 表示a1的channel传输时收集到了100条event以后再去提交事务
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
# 表示将r1和c1连接起来
a1.sources.r1.channels = c1
# 表示将k1和c1连接起来
a1.sinks.k1.channel = c1
3)开启flume监听端口
bin/flume-ng agent --conf conf/ --name a1 --conf-file job/flume-netcat-logger.conf -Dflume.root.logger=INFO,console
或者简写
bin/flume-ng agent -c conf/ -n a1 -f job/flume-netcat-logger.conf -Dflume.root.logger=INFO,console
参数说明:
- --conf/-c:表示配置文件存储在conf/目录
- --name/-n:表示给agent起名为a1
- --conf-file/-f:flume 本次启动读取的配置文件是在job文件夹下的flume-netcat-logger.conf文件。 -Dflume.root.logger=INFO,console:-D 表示flume运行时动态修改 flume.root.logger参数属性值,并将控制台日志打印级别设置为INFO级别。日志级别包括:log、info、warn、error

4)发送数据
使用netcat工具向本机的44444端口发送内容

5)查看Flume监听
在Flume监听页面观察接收数据情况

(2)实时监控单个追加文件
实时监控Hive日志,并上传到HDFS中
1)输出控制台
a、创建输出控制台配置文件
在输出到hdfs之前可以先将日志输出到控制台
vim flume-file-logger.conf
添加如下内容
# Name the components on this agent
# a1 表示agent的名字 r1 表示a1的source的名称
a1.sources = r1
# k1 表示a1的sinks的名称
a1.sinks = k1
# c1 表示a1的channels的名称
a1.channels = c1
# Describe/configure the source
# 定义source类型为exec可执行命令的
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/hive/logs/hive.log
a1.sources.r1.shell = /bin/bash -c
# Describe the sink
# 表示a1的输出目的地是控制台logger类型
a1.sinks.k1.type = logger
# Use a channel which buffers events in memory
# 表示a1的channel类型是memory内存型
a1.channels.c1.type = memory
# 表示a1的channel总容量1000个event
a1.channels.c1.capacity = 1000
# 表示a1的channel传输时收集到了100条event以后再去提交事务
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
# 表示将r1和c1连接起来
a1.sources.r1.channels = c1
# 表示将k1和c1连接起来
a1.sinks.k1.channel = c1
b、启动命令
bin/flume-ng agent --conf conf/ --name a1 --conf-file job/flume-file-logger.conf -Dflume.root.logger=INFO,console

c、启动hive

d、观察Flume
发现控制台一直在持续输出日志

2)添加依赖jar包
Flume 要想将数据输出到HDFS,须持有Hadoop相关jar包
将jar包拷贝到flume/lib 文件夹下
commons-configuration-1.6.jar
hadoop-auth-2.7.2.jar
hadoop-common-2.7.2.jar
hadoop-hdfs-2.7.2.jar
commons-io-2.4.jar
htrace-core-3.1.0-incubating.jar
3)创建配置文件
exec-source官网参数
https://flume.apache.org/FlumeUserGuide.html#exec-source
hdfs-sink官网参数
https://flume.apache.org/FlumeUserGuide.html#hdfs-sink
vim flume-netcat-logger.conf
在flume-netcat-logger.conf 文件中添加如下内容
# Name the components on this agent
a2.sources = r2
a2.sinks = k2
a2.channels = c2
# Describe/configure the source
# 定义source类型为exec可执行命令的
a2.sources.r2.type = exec
a2.sources.r2.command = tail -F /opt/module/hive/logs/hive.log
a2.sources.r2.shell = /bin/bash -c
# Describe the sink
# 表示输出到hdfs
a2.sinks.k2.type = hdfs
# hdfs的地址
a2.sinks.k2.hdfs.path = hdfs://hd01:9000/flume/%Y%m%d/%H
#上传文件的前缀
a2.sinks.k2.hdfs.filePrefix = logs-
#是否按照时间滚动文件夹
a2.sinks.k2.hdfs.round = true
#多少时间单位创建一个新的文件夹
a2.sinks.k2.hdfs.roundValue = 1
#重新定义时间单位
a2.sinks.k2.hdfs.roundUnit = hour
#是否使用本地时间戳
a2.sinks.k2.hdfs.useLocalTimeStamp = true
#积攒多少个Event才flush到HDFS一次
a2.sinks.k2.hdfs.batchSize = 1000
#设置文件类型,可支持压缩
a2.sinks.k2.hdfs.fileType = DataStream
#多久生成一个新的文件
a2.sinks.k2.hdfs.rollInterval = 30
#设置每个文件的滚动大小
a2.sinks.k2.hdfs.rollSize = 134217700
#文件的滚动与Event数量无关
a2.sinks.k2.hdfs.rollCount = 0
# Use a channel which buffers events in memory
a2.channels.c2.type = memory
a2.channels.c2.capacity = 1000
a2.channels.c2.transactionCapacity = 100
# Bind the source and sink to the channel
a2.sources.r2.channels = c2
a2.sinks.k2.channel = c2
注意: 对于所有与时间相关的转义序列,Event Header中必须存在以 "timestamp"的key(除非 hdfs.useLocalTimeStamp设置为true,此方法会使用TimestampInterceptor自动添加timestamp)
a3.sinks.k3.hdfs.useLocalTimeStamp = true
4)运行Flume
bin/flume-ng agent --conf conf/ --name a2 --conf-file job/flume-file-hdfs.conf
5)启动hive
bin/hive
6)在HDFS 上查看文件

当有日志数据增加时,会写入到hdfs临时文件,当触发条件后会将临时文件转为真实文件
(3)实时监控目录下多个新文件
使用Flume监听整个目录的文件,并上传至HDFS
spooling-directory-source官网参数
https://flume.apache.org/FlumeUserGuide.html#spooling-directory-source
1)创建配置文件
vim flume-dir-hdfs.conf
添加如下内容
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# source 配置
# 定义source类型为目录
a1.sources.r1.type = spooldir
# 定义监控目录
a1.sources.r1.spoolDir = /opt/module/flume/upload
# 定义文件上传完,后缀
a1.sources.r1.fileSuffix = .COMPLETED
# 是否有文件头
a1.sources.r1.fileHeader = true
# 忽略所有以.tmp结尾的文件,不上传
a1.sources.r1.ignorePattern = ([^ ]*\.tmp)
# sink配置
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://hd01:9000/flume/upload/%Y%m%d/%H
# 上传文件的前缀
a1.sinks.k1.hdfs.filePrefix = upload-
#是否按照时间滚动文件夹
a1.sinks.k1.hdfs.round = true
#多少时间单位创建一个新的文件夹
a1.sinks.k1.hdfs.roundValue = 1
#重新定义时间单位
a1.sinks.k1.hdfs.roundUnit = hour
#是否使用本地时间戳
a1.sinks.k1.hdfs.useLocalTimeStamp = true
#积攒多少个Event才flush到HDFS一次
a1.sinks.k1.hdfs.batchSize = 100
#设置文件类型,可支持压缩
a1.sinks.k1.hdfs.fileType = DataStream
#多久生成一个新的文件
a1.sinks.k1.hdfs.rollInterval = 60
#设置每个文件的滚动大小大概是128M
a1.sinks.k1.hdfs.rollSize = 134217700
#文件的滚动与Event数量无关
a1.sinks.k1.hdfs.rollCount = 0
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
2)运行Flume
bin/flume-ng agent --conf conf/ --name a1 --conf-file job/flume-dir-hdfs.conf
说明:在使用Spooling Directory Source 时不要在监控目录中创建并持续修改已经上传完成的文件会以;.COMPLETED结尾被监控文件夹每500毫秒扫描一次文件变动
3)测试
创建文件夹并添加文件
在flume 目录下创建upload 文件夹
mkdir upload
touch hello.txt
echo java >> hello.txt
mv hello.txt upload/


touch hello2.tmp
echo java >> hello2.tmp
mv hello2.tmp upload/
发现hdfs不会产生新的文件,upload里面也不会产生.COMPLETED文件,因为.tmp的文件会过滤掉。

(4)实时监控目录下的多个追加文件
Exec source 适用于监控一个实时追加的文件,但不能保证数据不丢失;
Spooldir Source 能够保证数据不丢失,且能够实现断点续传,但延迟较高,不能实时监控;
而 Taildir Source 既能够实现断点续传,又可以保证数据不丢失,还能够进行实时监控。
案例:使用Flume监听整个目录的实时追加文件,并输出到控制台
taildir-source官网参数
https://flume.apache.org/FlumeUserGuide.html#taildir-source
1)创建配置文件
vim flume-taildir-hdfs.conf
添加如下内容
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
# 定义source类型
a1.sources.r1.type = TAILDIR
# 指定position_file位置
a1.sources.r1.positionFile = /opt/module/flume/tail_dir.json
# 定义监控目录文件
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /opt/module/flume/upload/hello.*
# Describe the sink
a1.sinks.k1.type = logger
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
2)运行Flume
bin/flume-ng agent --conf conf/ --name a1 --conf-file job/flume-taildir-logger.conf -Dflume.root.logger=INFO,console
3)测试
向文件中写入数据
touch hello.txt
echo java >> hello.txt


关闭flume,再次向文件中写入数据后,再次启动flume,发现新写入的数据也会输出不会丢失


Taildir Source 维护了一个json 格式的position File,其会定期的往position File 中更新每个文件读取到的最新的位置,因此能够实现断点续传。

Position File的格式如下:
{"inode":36391382,"pos":16,"file":"/opt/module/flume/upload/hello.txt"}

注:Linux 中储存文件元数据的区域就叫做inode,每个inode都有一个号码,操作系统 用inode 号码来识别不同的文件,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。
三、进阶
1、Flume 事务

Put事务流程
doPut:将批数据先写入临时缓冲区putList
doCommit:检查channel内存队列是否足够合并。
doRollback:channel内存队列空间不足,回滚数据
Take事务
doTake:将数据取到临时缓冲区takeList,并将数据发送到HDFS
doCommit:如果数据全部发送成功,则清除临时缓冲区takeList
doRollback:数据发送过程中如果出现异常,rollback将临时缓冲区takeList中的数据归还给channel内存队列。
2、Flume Agent 内部原理

重要组件:
1)ChannelSelector
ChannelSelector 的作用就是选出Event将要被发往哪个Channel。其共有两种类型, 分别是Replicating(复制)和Multiplexing(多路复用)
ReplicatingSelector 会将同一个Event发往所有的Channel,Multiplexing 会根据相应的原则,将不同的Event发往不同的Channel。
2)SinkProcessor
SinkProcessor共有三种类型 ,分别是DefaultSinkProcessor 、LoadBalancingSinkProcessor 和 FailoverSinkProcessor
DefaultSinkProcessor 对应的是单个的 Sink,LoadBalancingSinkProcessor 和 FailoverSinkProcessor 对应的是 Sink Group,LoadBalancingSinkProcessor 可以实现负载均衡的功能, FailoverSinkProcessor可以实现故障转移的功能。
3、Flume 拓扑结构
(1)简单串联

这种模式是将多个flume顺序连接起来了,从最初的source开始到最终sink 传送的目的存储系统。此模式不建议桥接过多的flume数量,flume数量过多不仅会影响传输速率, 而且一旦传输过程中某个节点flume宕机,会影响整个传输系统。
(2)复制和多路复用
1)说明

Flume 支持将事件流向一个或者多个目的地。这种模式可以将相同数据复制到多个 channel 中,或者将不同数据分发到不同的 channel 中,sink 可以选择传送到不同的目的 地。
2)案例
需求:使用Flume-1 监控文件变动,Flume-1 将变动内容传递给Flume-2,Flume-2 负责存储 到HDFS。同时Flume-1将变动内容传递给Flume-3,Flume-3负责输出到Local FileSystem。

所使用的配置文档
exec-source文档、replicating-channel-selector文档、memory-channel文档、avro-sink文档、avro-source文档、hdfs-sink文档、file-roll-sink文档
a、创建flume-1的配置文件
cd job/test1/
vim flume-file-flume.conf
添加如下内容
# agent
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1 c2
# 配置channel选择器 将数据流复制给所有channel
a1.sources.r1.selector.type = replicating
# 配置source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/hive/logs/hive.log
a1.sources.r1.shell = /bin/bash -c
# 配置sink sink端的avro是一个数据发送者
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hd01
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hd01
a1.sinks.k2.port = 4142
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
a1.channels.c2.type = memory
a1.channels.c2.capacity = 1000
a1.channels.c2.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1 c2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2
b、创建flume-2的配置文件
vim flume-flume-hdfs.conf
添加如下内容
# agent
a2.sources = r1
a2.sinks = k1
a2.channels = c1
# 配置source
a2.sources.r1.type = avro
a2.sources.r1.bind = hd01
a2.sources.r1.port = 4141
# 配置sink
a2.sinks.k1.type = hdfs
a2.sinks.k1.hdfs.path = hdfs://hd01:9000/flume2/%Y%m%d/%H
#上传文件的前缀
a2.sinks.k1.hdfs.filePrefix = flume2-
#是否按照时间滚动文件夹
a2.sinks.k1.hdfs.round = true
#多少时间单位创建一个新的文件夹
a2.sinks.k1.hdfs.roundValue = 1
#重新定义时间单位
a2.sinks.k1.hdfs.roundUnit = hour
#是否使用本地时间戳
a2.sinks.k1.hdfs.useLocalTimeStamp = true
#积攒多少个Event才flush到HDFS一次
a2.sinks.k1.hdfs.batchSize = 100
#设置文件类型,可支持压缩
a2.sinks.k1.hdfs.fileType = DataStream
#多久生成一个新的文件
a2.sinks.k1.hdfs.rollInterval = 600
#设置每个文件的滚动大小大概是128M
a2.sinks.k1.hdfs.rollSize = 134217700
#文件的滚动与Event数量无关
a2.sinks.k1.hdfs.rollCount = 0
# 配置channel
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100
# bind
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1
c、创建flume-3的配置文件
vim flume-flume-dir.conf
添加如下内容
# agent
a3.sources = r1
a3.sinks = k1
a3.channels = c1
# 配置source
a3.sources.r1.type = avro
a3.sources.r1.bind = hd01
a3.sources.r1.port = 4142
# 配置sink
a3.sinks.k1.type = file_roll
a3.sinks.k1.sink.directory = /opt/module/flume/datas/flume3
# 配置channel
a3.channels.c1.type = memory
a3.channels.c1.capacity = 1000
a3.channels.c1.transactionCapacity = 100
# bind
a3.sources.r1.channels = c1
a3.sinks.k1.channel = c1
提示:输出的本地目录必须是已经存在的目录,如果该目录不存在,并不会创建新的目录。
d、启动flume
先启动flume-flume-dir和flume-flume-hdfs,后启动flume-file-flume
bin/flume-ng agent --conf conf/ --name a3 --conf-file job/test1/flume-flume-dir.conf
bin/flume-ng agent --conf conf/ --name a2 --conf-file job/test1/flume-flume-hdfs.conf
bin/flume-ng agent --conf conf/ --name a1 --conf-file job/test1/flume-file-flume.conf
e、启动hive
bin/hive
f、查看日志输出
查看文件夹

查看HDFS

(3)负载均衡和故障转移
1)说明

Flume支持使用将多个sink逻辑上分到一个sink组,sink组配合不同的SinkProcessor 可以实现负载均衡和错误恢复的功能。
2)案例:故障转移
使用Flume1 监控一个端口,其 sink 组中的 sink 分别对接 Flume2 和 Flume3,采用 FailoverSinkProcessor,实现故障转移的功能。

所使用的配置文档
netcat-tcp-source文档、failover-sink-processor文档、memory-channel文档、avro-sink文档、avro-source文档、logger-sink文档
a、创建flume-1的配置文件
cd job/test2/
vim flume-netcat-flume.conf
添加如下内容
# agent
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1
a1.sinkgroups = g1
# 配置source
a1.sources.r1.type = netcat
a1.sources.r1.bind = hd01
a1.sources.r1.port = 44444
# 配置processor
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
# 配置sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hd01
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hd01
a1.sinks.k2.port = 4142
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c1
a1.sinkgroups.g1.sinks = k1 k2
b、创建flume-2的配置文件
vim flume-flume-console1.conf
添加如下内容
# agent
a2.sources = r1
a2.sinks = k1
a2.channels = c1
# 配置source
a2.sources.r1.type = avro
a2.sources.r1.bind = hd01
a2.sources.r1.port = 4141
# 配置sink
a2.sinks.k1.type = logger
# 配置channel
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100
# bind
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1
c、创建flume-3的配置文件
vim flume-flume-console2.conf
添加如下内容
# agent
a3.sources = r1
a3.sinks = k1
a3.channels = c1
# 配置source
a3.sources.r1.type = avro
a3.sources.r1.bind = hd01
a3.sources.r1.port = 4142
# 配置sink
a3.sinks.k1.type = logger
# 配置channel
a3.channels.c1.type = memory
a3.channels.c1.capacity = 1000
a3.channels.c1.transactionCapacity = 100
# bind
a3.sources.r1.channels = c1
a3.sinks.k1.channel = c1
d、启动flume
先启动flume-flume-console1和flume-flume-console2,后启动flume-netcat-flume
bin/flume-ng agent --conf conf/ --conf-file job/test2/flume-flume-console1.conf --name a2 -Dflume.root.logger=INFO,console
bin/flume-ng agent --conf conf/ --conf-file job/test2/flume-flume-console2.conf --name a3 -Dflume.root.logger=INFO,console
bin/flume-ng agent --conf conf/ --conf-file job/test2/flume-netcat-flume.conf --name a1
e、使用netcat 工具向44444端口发送内容
nc hd01 44444

f、查看flume2和flume3
发现总是flume3接收到数据,因为flume3的权重比flume2高


g、将Flume2 kill,观察Flume3的控制台打印情况
jps -ml

kill -9 86849

再次发送数据

发下flume3依然能接收数据
3)案例:负载均衡
所使用的配置文档
load-balancing-sink-processor文档
a、修改flume-1的配置文件
配置processor
a1.sinkgroups.g1.processor.type = load_balance
a1.sinkgroups.g1.processor.backoff = true
a1.sinkgroups.g1.processor.selector = random
# agent
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1
a1.sinkgroups = g1
# 配置source
a1.sources.r1.type = netcat
a1.sources.r1.bind = hd01
a1.sources.r1.port = 44444
# 配置processor
a1.sinkgroups.g1.processor.type = load_balance
a1.sinkgroups.g1.processor.backoff = true
a1.sinkgroups.g1.processor.selector = random
# 配置sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hd01
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hd01
a1.sinks.k2.port = 4142
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c1
a1.sinkgroups.g1.sinks = k1 k2
b、启动flume
先启动flume-flume-console1和flume-flume-console2,后启动flume-netcat-flume
bin/flume-ng agent --conf conf/ --conf-file job/test2/flume-flume-console1.conf --name a2 -Dflume.root.logger=INFO,console
bin/flume-ng agent --conf conf/ --conf-file job/test2/flume-flume-console2.conf --name a3 -Dflume.root.logger=INFO,console
bin/flume-ng agent --conf conf/ --conf-file job/test2/flume-netcat-flume.conf --name a1
c、使用netcat 工具向44444端口发送内容
nc hd01 44444

d、查看flume2和flume3


(4)聚合
1)说明

这种模式是最常见的,也非常实用,日常web应用通常分布在上百个服务器,甚至更多。产生的日志,处理起来也非常麻烦。用flume的这种组合方式 能很好的解决这一问题,每台服务器部署一个flume采集日志,传送到一个集中收集日志的 flume,再由此flume上传到hdfs、hive、hbase等,进行日志分析。
2)案例
hd01 上的Flume-1 监控文件/opt/module/flume/datas/group.log, hd02上的Flume-2 监控某一个端口的数据流, Flume-1 与 Flume-2 将数据发送给 hd03上的 Flume-3,Flume-3 将最终数据打印到控制台。

a、安装flume
hd01、hd02、hd03上都要安装flume
b、创建flume-1的配置文件
在hd01上创建配置文件
cd job/test3
vim flume-logger-flume.conf
添加如下内容
# agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/flume/datas/group.log
a1.sources.r1.shell = /bin/bash -c
# 配置sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hd03
a1.sinks.k1.port = 4141
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
b、创建flume-2的配置文件
在hd02上创建配置文件
cd job/test3
vim flume-netcat-flume.conf
添加如下内容
# agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置source
a1.sources.r1.type = netcat
a1.sources.r1.bind = hd02
a1.sources.r1.port = 44444
# 配置sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hd03
a1.sinks.k1.port = 4141
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
c、创建flume-3的配置文件
在hd03上创建配置文件
cd job/test3
vim flume-flume-logger.conf
添加如下内容
# agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置source
a1.sources.r1.type = avro
a1.sources.r1.bind = hd03
a1.sources.r1.port = 4141
# 配置sink
a1.sinks.k1.type = logger
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
d、启动flume
先启动flume3,后启动flume2和flume1
hd03上启动
bin/flume-ng agent --conf conf/ --conf-file job/test3/flume-flume-logger.conf --name a1 -Dflume.root.logger=INFO,console
hd02上启动
bin/flume-ng agent --conf conf/ --conf-file job/test3/flume-netcat-flume.conf --name a1
hd01上启动
bin/flume-ng agent --conf conf/ --conf-file job/test3/flume-logger-flume.conf --name a1
e、在hd01上向group.log追加内容,查看hd03的输出


c、在hd02向44444端口发送内容,查看hd03的输出

4、自定义Interceptor
在实际的开发中,一台服务器产生的日志类型可能有很多种,不同类型的日志可能需要发送到不同的分析系统。此时会用到Flume拓扑结构中的Multiplexing结构,Multiplexing 的原理是,根据event中Header的某个key的值,将不同的event发送到不同的Channel中,所以需要自定义一个Interceptor,为不同类型的event的Header中的key赋予不同的值。
案例:使用Flume采集服务器本地日志,需要按照日志类型的不同,将不同种类的日志发往不同的分析系统。

所使用的配置文档
(1)创建项目

(2)添加依赖
XML
<dependencies>
<dependency>
<groupId>org.apache.flume</groupId>
<artifactId>flume-ng-core</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies
(3)定义CustomInterceptor 类
java
package com.hk;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;
import java.util.ArrayList;
import java.util.List;
public class CustomInterceptor implements Interceptor {
List<Event> eventList;
// 初始化
@Override
public void initialize() {
eventList = new ArrayList<>();
}
// 核心业务
@Override
public Event intercept(Event event) {
String s = new String(event.getBody());
if (s.contains("hello")) {
event.getHeaders().put("type", "java");
} else {
event.getHeaders().put("type", "php");
}
return event;
}
@Override
public List<Event> intercept(List<Event> list) {
// 清空集合
eventList.clear();
for (Event event : list) {
eventList.add(intercept(event));
}
return eventList;
}
@Override
public void close() {
}
public static class Builder implements Interceptor.Builder {
@Override
public Interceptor build() {
return new CustomInterceptor();
}
@Override
public void configure(Context context) {
}
}
}
(4)打包上传

(5)编辑flume1配置文件
在hd01上创建配置文件
cd job/test4
vim flume-netcat-flume.conf
添加如下内容
java
# agent
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1 c2
# 配置source
a1.sources.r1.type = netcat
a1.sources.r1.bind = hd01
a1.sources.r1.port = 44444
# 自定义拦截器
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = com.hk.CustomInterceptor$Builder
# 配置选择器
a1.sources.r1.selector.type = multiplexing
a1.sources.r1.selector.header = type
a1.sources.r1.selector.mapping.java = c1
a1.sources.r1.selector.mapping.php = c2
# 配置sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hd02
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hd03
a1.sinks.k2.port = 4141
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
a1.channels.c2.type = memory
a1.channels.c2.capacity = 1000
a1.channels.c2.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1 c2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2
(6)编辑flume2配置文件
在hd02上创建配置文件
cd job/test4
vim flume-flume-logger.conf
添加如下内容
java
# agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置source
a1.sources.r1.type = avro
a1.sources.r1.bind = hd02
a1.sources.r1.port = 4141
# 配置sink
a1.sinks.k1.type = logger
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
(7)编辑flume3配置文件
在hd03上创建配置文件
cd job/test4
vim flume-flume-logger.conf
添加如下内容
java
# agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置source
a1.sources.r1.type = avro
a1.sources.r1.bind = hd03
a1.sources.r1.port = 4141
# 配置sink
a1.sinks.k1.type = logger
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
(8)启动 flume
先启动flume2、flume3,后启动flume1
hd03上启动
bin/flume-ng agent --conf conf/ --conf-file job/test4/flume-flume-logger.conf --name a1 -Dflume.root.logger=INFO,console
hd02上启动
bin/flume-ng agent --conf conf/ --conf-file job/test4/flume-flume-logger.conf --name a1 -Dflume.root.logger=INFO,console
hd01上启动
bin/flume-ng agent --conf conf/ --conf-file job/test4/flume-netcat-flume.conf --name a1
(9)测试
向hd01的44444端口发送内容,查看hd02的输出和查看hd03的输出

hd02输出

hd03输出

5、自定义Source
Source 是负责接收数据到Flume Agent的组件。Source组件可以处理各种类型、各种格式的日志数据,包括avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy。官方提供的 source 类型已经很多,但是有时候并不能满足实际开发当中的需求,此时需要根据实际需求自定义某些source。
官方文档
https://flume.apache.org/releases/content/1.11.0/FlumeDeveloperGuide.html#source
根据官方说明自定义 MySource 需要继承AbstractSource 类并实现Configurable 和PollableSource 接口。
实现相应方法:
- configure(Context context)//初始化 context(读取配置文件内容)
- process()//获取数据封装成event并写入channel,这个方法将被循环调用。 使用场景:读取MySQL数据或者其他文件系统。
案例:使用flume接收数据,并给每条数据添加前缀,输出到控制台。前缀可从flume配置文件中配置。
(1)编写自定义类
java
package com.hk;
import org.apache.flume.Context;
import org.apache.flume.EventDeliveryException;
import org.apache.flume.PollableSource;
import org.apache.flume.conf.Configurable;
import org.apache.flume.event.SimpleEvent;
import org.apache.flume.source.AbstractSource;
public class MySource extends AbstractSource implements Configurable, PollableSource {
private String prefix;
private String suffix;
// 获取配置信息
@Override
public void configure(Context context) {
// 获取前缀
prefix = context.getString("prefix");
// 获取后缀
suffix = context.getString("suffix", "-student");
}
@Override
public Status process() throws EventDeliveryException {
//创建事件
SimpleEvent simpleEvent = new SimpleEvent();
try {
for (int i = 0; i < 5; i++) {
simpleEvent.setBody((prefix + i + suffix).getBytes());
//将事件写入channel
getChannelProcessor().processEvent(simpleEvent);
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
return Status.BACKOFF;
}
return Status.READY;
}
@Override
public long getBackOffSleepIncrement() {
return 0;
}
@Override
public long getMaxBackOffSleepInterval() {
return 0;
}
}
(2)打包上传
并放到flume的lib目录

(3)编写配置文件
vim mysource.conf
添加如下内容
java
# agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置source
a1.sources.r1.type = com.hk.MySource
a1.sources.r1.prefix = hk-
a1.sources.r1.suffix = -hk
# 配置sink
a1.sinks.k1.type = logger
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
(4)运行flume
bin/flume-ng agent --conf conf/ --conf-file job/mysource.conf --name a1 -Dflume.root.logger=INFO,console
(5)测试

不配置后缀,使用默认后缀

6、自定义Sink
Sink 不断地轮询 Channel 中的事件且批量地移除它们,并将这些事件批量写入到存储或索引系统、或者被发送到另一个Flume Agent。
Sink 是完全事务性的。在从Channel批量删除数据之前,每个Sink用Channel启动一 个事务。批量事件一旦成功写出到存储系统或下一个Flume Agent,Sink就利用Channel提交事务。事务一旦被提交,该Channel从自己的内部缓冲区删除事件。
Sink 组件目的地包括hdfs、logger、avro、thrift、ipc、file、null、HBase、solr、 自定义。官方提供的Sink类型已经很多,但是有时候并不能满足实际开发当中的需求,此时就需要根据实际需求自定义某些Sink。
官方文档
https://flume.apache.org/releases/content/1.11.0/FlumeDeveloperGuide.html#sink自定义 MySink 需要继承AbstractSink类并实现Configurable接口。
实现相应方法:
- configure(Context context)//初始化 context(读取配置文件内容)
- process()//从 Channel 读取获取数据(event),这个方法将被循环调用。
- 使用场景:读取Channel数据写入MySQL或者其他文件系统。
案例:使用flume接收数据,并在Sink端给每条数据添加前缀和后缀,输出到控制台。前后缀可在flume任务配置文件中配置。
(1)编写自定义类
java
package com.hk;
import org.apache.flume.*;
import org.apache.flume.conf.Configurable;
import org.apache.flume.sink.AbstractSink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MySink extends AbstractSink implements Configurable {
//创建Logger对象
private static final Logger logger = LoggerFactory.getLogger(MySink.class);
private String prefix;
private String suffix;
@Override
public void configure(Context context) {
// 获取前缀
prefix = context.getString("prefix");
// 获取后缀
suffix = context.getString("suffix", "-student");
}
@Override
public Status process() throws EventDeliveryException {
//获取当前Sink绑定的Channel
Channel channel = getChannel();
//获取事务
Transaction transaction = channel.getTransaction();
// 开启事务
transaction.begin();
//读取Channel中的事件
try {
Event take = channel.take();
if (take != null) {
String s = new String(take.getBody());
//处理事件(打印)
logger.info(prefix + s + suffix);
}
//事务提交
transaction.commit();
return Status.READY;
} catch (ChannelException e) {
e.printStackTrace();
transaction.rollback();
return Status.BACKOFF;
} finally {
transaction.close();
}
}
}
(2)打包上传
并放到flume的lib目录

(3)编写配置文件
vim mysink.conf
添加如下内容
java
# agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置source
a1.sources.r1.type = netcat
a1.sources.r1.bind = hd01
a1.sources.r1.port = 44444
# 配置sink
a1.sinks.k1.type = com.hk.MySink
a1.sinks.k1.prefix = hello-
a1.sinks.k1.suffix = -hello
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
(4)运行flume
bin/flume-ng agent --conf conf/ --conf-file job/mysink.conf --name a1 -Dflume.root.logger=INFO,console
(5)测试
向44444端口发送数据

查看flume

不配置后缀,使用默认后缀

