大数据技术之Flume详解
一 Flume配置
Flume安装地址
1) Flume 官网地址
http://flume.apache.org/
2)文档查看地址
http://flume.apache.org/FlumeUserGuide.html
3)下载地址
http://archive.apache.org/dist/flume/
环境配置
解压
重命名为flume160
进入flume160/conf
复制flume-env.sh.templete-->flume-env.sh
修改flume-env.sh
export JAVA_HOME=/opt/jdk1.8.0_221
export JAVA_OPTS="-Xms2048m -Xmx2048m -Dcom.sun.management.jmxremote"
修改vi /etc/profile使flume命令全局生效
export FLUME_HOME=/opt/flume160
export PATH=$PATH:$FLUME_HOME/bin
验证
[root@hadoopwei bin]# flume-ng version
Flume 1.6.0-cdh5.14.0
Source code repository: https://git-wip-us.apache.org/repos/asf/flume.git
Revision: 939f6066f6056e7e8042292647eb5032628ac5a0
Compiled by jenkins on Sat Jan 6 13:37:47 PST 2018
From source with checksum c350591306508e3cdd4942fb1debefc9
二 Flume基础架构
1、定义
Flume 是 Cloudera 提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。Flume 基于流式架构,灵活简单。
Flume最主要的作用就是,实时读取服务器本地磁盘的数据,将数据写入到HDFS。
2、Flume组成架构
3、Flume组件
Agent
- Agent 是一个 JVM 进程,它以事件(Event)的形式将数据从源头送至目的,是 Flume 数据传输的基本单元。
- Agent 主要有 3 个部分组成,Source、Channel、Sink。
Source
- Source 是负责接收数据到 Flume Agent 的组件。Source 组件可以处理各种类型、各种格式的日志数据,包括 avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy。
Channel
- Channel 是位于 Source 和 Sink 之间的缓冲区。因此,Channel 允许 Source 和 Sink 运作在不同的速率上。Channel 是线程安全的,可以同时处理几个 Source 的写入操作和几个 Sink的读取操作。
- Flume 自带两种 Channel:Memory Channel 和 File Channel。
- Memory Channel 是内存中的队列。Memory Channel 在不需要关心数据丢失的情景下适
用。如果需要关心数据丢失,那么 Memory Channel 就不应该使用,因为程序死亡、机器宕机或者重启都会导致数据丢失。 - File Channel 将所有事件写到磁盘。因此在程序关闭或机器宕机的情况下不会丢失数据。
- Memory Channel 是内存中的队列。Memory Channel 在不需要关心数据丢失的情景下适
Sink
- Sink 不断地查询 Channel 中的事件且批量地移除它们,并将这些事件批量写入到存储或索引系统、或者被发送到另一个 Flume Agent。
- Sink 是完全事务性的。在从 Channel 批量删除数据之前,每个 Sink 用 Channel 启动一个事务。批量事件一旦成功写出到存储系统或下一个 Flume Agent,Sink 就利用 Channel 提交事务。事务一旦被提交,该 Channel 从自己的内部缓冲区删除事件。
- Sink 组件目的地包括 hdfs、logger、avro、thrift、ipc、file、null、HBase、solr、自定义
Event
- 传输单元,Flume 数据传输的基本单元,以事件的形式将数据从源头送至目的地。
- Event由Header和Body两部分组成,Header用来存放该event的一些属性,为K-V结构,Body用来存放该条数据,形式为字节数组。
三 Flume入门案例
1、nc
yum install -y nc
yum list telnet*
yum install -y telnet-server.x86_64
yum install -y telnet.x86_64
--------------------测试nc-----------------------------
开启服务端(7777为自定义):nc -lk 7777
再开一个窗口输入开启client端:telnet localhost 7777
2、监听端口数据Netcat Source
(1)下载telnet或者nc
//下载telnet
yum install -y telnet-server.x86_64
yum install -y telnet.x86_64
//或者下载nc
yum install -y nc
(2)判断要使用的端口7777是否被占用
//被占用时会输出连线状况
[root@hadoopwei ~]# sudo netstat -tunlp | grep 7777
tcp 0 0 0.0.0.0:7777 0.0.0.0:* LISTEN 21133/nc
tcp6 0 0 :::7777 :::* LISTEN 21133/nc
//没被占用时啥都不输出
[root@hadoopwei ~]# sudo netstat -tunlp | grep 7777
(3)创建Flume Agent配置文件netcat-flume-logger.conf
//a1:表示agent的名称
a1.sources=r1 //r1:表示a1的输入源
a1.channels=c1 // c1:表示a1的缓冲区
a1.sinks=k1 // k1:表示a1的输出目的地
a1.sources.r1.type=netcat //表示a1的输入源类型为netcat端口类型
a1.sources.r1.bind=localhost //表示a1的监听的主机
a1.sources.r1.port=7777 //表示a1的监听的端口号
a1.channels.c1.type=file //表示a1的Channel类型为file,硬盘存储
a1.channels.c1.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/netcat //file类型需要设置检查点路径,需提前创建
a1.channels.c1.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/netcat //file类型需要设置数据缓存路径,需提前创建
a1.sinks.k1.type=logger //表示a1的输出目的地是控制台logger类型
a1.sources.r1.channels=c1 //表示将r1和c1连接起来,一个Source可一个对应多个Channel
a1.sinks.k1.channel=c1 //表示将k1和c1连接起来,一个Sink只能对应一个Channel,但一个Channel可以对应多个Sink
(4)先开启flume监听端口
[root@hadoopwei flume160]# flume-ng agent --name a1 --conf ./conf/ --conf-file ./conf/jobkb09/netcat-flume-logger.conf -Dflume.root.logger=INFO,console
//两种写法等价
[root@hadoopwei flume160]# flume-ng agent -n a1 -c ./conf/ -f ./conf/jobkb09/netcat-flume-logger.conf -Dflume.root.logger=INFO,console
参数说明:
--conf/-c:表示配置文件存储在 conf/目录
--name/-n:表示给 agent 起名为 a1
--conf-file/-f:flume 本次启动读取的配置文件的具体文件目录
-Dflume.root.logger==INFO,console : -D 表 示 flume 运 行 时 动 态 修 改flume.root.logger 参数属性值,并将控制台日志打印级别设置为 INFO 级别。日志级别包括:log、
info、warn、error。
(5) 新开一个窗口使用telnet工具向本机的7777端口发送内容
[root@hadoopwei ~]# telnet localhost 7777
Trying ::1...
Connected to localhost.
Escape character is '^]'.
hello //hello为发送的内容
或者使用netcat工具向本机的7777端口发送内容也可
[root@hadoopwei ~]# nc -lk 7777
hello //hello为发送的内容
3、实时读取文件到HDFS–Exec Source
(1) 案例需求:实时监控Hive日志,并上传到HDFS中
(2) 需求分析:
注:hive日志文件目录可在/opt/hive/conf/hive-log4j.properties
文件里设置hive.log.dir=/opt/hive/logs
(3)创建Flume Agent配置文件exec-flume-hdfs.conf
注:要想读取 Linux 系统中的文件,就得按照 Linux 命令的规则执行命令。由于 Hive日志在 Linux 系统中所以读取文件的类型选择:exec 即 execute 执行的意思。表示执行 Linux命令来读取文件。
a2.sources=r1
a2.channels=c1
a2.sinks=k1
a2.sources.r1.type=exec //定义source类型为exec可执行命令的
a2.sources.r1.command=tail -f /opt/hive/logs/hive.log //从文件末尾一行行读取
a2.sources.r2.shell = /bin/bash -c //执行shell脚本的绝对路径
a2.channels.c1.type=memory //表示a2的channel类型是memory内存型
a2.channels.c1.capacity=1000 //表示a2的channel总容量1000个event
a2.channels.c1.transactionCapacity=1000 //表示a2的channel传输时收集到了1000条event以后再去提交事务
Describe the sink
a2.sinks.k1.type = hdfs
a2.sinks.k1.hdfs.path = hdfs://hadoopwei:9000/flume/%Y%m%d/%H
#上传文件的前缀
a2.sinks.k1.hdfs.filePrefix = logs-
#是否按照时间滚动文件夹
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 = 1000
#设置文件类型,可支持压缩
a2.sinks.k1.hdfs.fileType = DataStream
#多久生成一个新的文件
a2.sinks.k1.hdfs.rollInterval = 600
#设置每个文件的滚动大小
a2.sinks.k1.hdfs.rollSize = 134217700
#文件的滚动与 Event 数量无关
a2.sinks.k1.hdfs.rollCount = 0
#最小冗余数
a2.sinks.k1.hdfs.minBlockReplicas = 1
a2.sources.r1.channels=c1
a2.sinks.k1.channel=c1
(4) 执行监控配置
[root@hadoopwei flume160]# flume-ng agent --name a2 --conf ./conf/ --conf-file ./conf/jobkb09/file-flume-logger.conf -Dflume.root.logger=INFO,console
(5)开启Hadoop和Hive并操作Hive产生日志
[root@hadoopwei flume160]# start-all.sh
[root@hadoopwei flume160]# hive
4、实时读取目录文件到HDFS–Spooldir Source
- 案例需求:使用Flume监听整个目录的文件
- 需求分析:
(1)创建配置文件 flume-dir-hdfs.conf
a3.sources = r3
a3.sinks = k3
a3.channels = c3
# Describe/configure the source
#定义source类型为目录
a3.sources.r3.type = spooldir
#定义监控目录
a3.sources.r3.spoolDir = /opt/module/flume/upload
#定义文件上传完,后缀
a3.sources.r3.fileSuffix = .COMPLETED
#是否有文件头
a3.sources.r3.fileHeader = true
#忽略所有以.tmp 结尾的文件,不上传
a3.sources.r3.ignorePattern = ([^ ]*\.tmp)
#定义进入Source的文件名称样式
#a3.sources.r3.includePattern=users_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
# Describe the sink
a3.sinks.k3.type = hdfs
a3.sinks.k3.hdfs.path =
hdfs://hadoopwei:9000/flume/upload/%Y%m%d/%H
#上传文件的前缀
a3.sinks.k3.hdfs.filePrefix = upload-
#是否按照时间滚动文件夹
a3.sinks.k3.hdfs.round = true
#多少时间单位创建一个新的文件夹
a3.sinks.k3.hdfs.roundValue = 1
#重新定义时间单位
a3.sinks.k3.hdfs.roundUnit = hour
#是否使用本地时间戳
a3.sinks.k3.hdfs.useLocalTimeStamp = true
#积攒多少个 Event 才 flush 到 HDFS 一次
a3.sinks.k3.hdfs.batchSize = 100
#设置文件类型,可支持压缩
a3.sinks.k3.hdfs.fileType = DataStream
#多久生成一个新的文件
a3.sinks.k3.hdfs.rollInterval = 600
#设置每个文件的滚动大小大概是 128M
a3.sinks.k3.hdfs.rollSize = 134217700
#文件的滚动与 Event 数量无关
a3.sinks.k3.hdfs.rollCount = 0
#最小冗余数
a3.sinks.k3.hdfs.minBlockReplicas = 1
# Use a channel which buffers events in memory
a3.channels.c3.type = memory
a3.channels.c3.capacity = 1000
a3.channels.c3.transactionCapacity = 100
# Bind the source and sink to the channel
a3.sources.r3.channels = c3
a3.sinks.k3.channel = c3
注意:
对于所有与时间相关的转义序列,Event Header中必须存在以 “timestamp”的key(除非hdfs.useLocalTimeStamp设置为true,此方法会使用TimestampInterceptor自动添加timestamp)。
a3.sinks.k3.hdfs.useLocalTimeStamp = true
(2)启动监控文件夹命令
flume-ng agent --name a3 --conf ./conf/ --conf-file ./conf/jobkb09flume-dir-hdfs.conf -Dflume.root.logger=INFO,console
说明: 在使用 Spooling Directory Source 时
- 不要在监控目录中创建并持续修改文件
- 上传完成的文件会以.COMPLETED 结尾
- 被监控文件夹每 500 毫秒扫描一次文件变动
(3) 向upload文件夹中添加文件
//在/opt/module/flume 目录下创建 upload 文件夹
[root@hadoopwei flume160]$ mkdir upload
//向 upload 文件夹中添加文件
[root@hadoopwei upload]# touch 1.txt
[root@hadoopwei upload]# touch 2.tmp
[root@hadoopwei upload]# touch 3.log
(4) 等待 1s,再次查询 upload 文件夹
[root@hadoopwei upload]# ll
总用量 0
-rw-rw-r--. 1 root root 12 月 01 22:31 3.log.COMPLETED
-rw-rw-r--. 1 root root 12 月 01 22:31 2.tmp
-rw-rw-r--. 1 root root 12 月 01 22:31 1.txt.COMPLETE
5、实时监控目录下的多个追加文件–Taildir Source
Exec source适用于监控一个实时追加的文件,不能实现断点续传;Spooldir Source适合用于同步新文件,但不适合对实时追加日志的文件进行监听并同步,因为它成文件传输后会给文件加上后缀.COMPLETED这样就不会再次读取此文件;而Taildir Source适合用于监听多个实时追加的文件,并且能够实现断点续传。
(1)使用Flume监听整个目录的实时追加文件,并上传至HDFS
(2)需求分析:
(3)创建配置文件flume-taildir-hdfs.conf
a3.sources=r3
a3.channels=c3
a3.sinks=k3
a3.sources.r3.type=TAILDIR
#指定position_file位置
a3.sources.r3.positionFile=/opt/module/flume/tail_dir.json
#指定文件来源组,可以是多个不同命名的文件
a3.sources.r3.filegroups=f1 f2
#定时监控目录文件
a3.sources.r3.filegroups.f1=/opt/module/flume/files/.*file.*
a3.sources.r3.filegroups.f2=/opt/module/flume/files/.*log.*
# Describe the sink
a3.sinks.k3.type = hdfs
a3.sinks.k3.hdfs.path = hdfs://hadoopwei:9000/flume/upload2/%Y%m%d/%H
#上传文件的前缀
a3.sinks.k3.hdfs.filePrefix = upload-
#是否按照时间滚动文件夹
a3.sinks.k3.hdfs.round = true
#多少时间单位创建一个新的文件夹
a3.sinks.k3.hdfs.roundValue = 1
#重新定义时间单位
a3.sinks.k3.hdfs.roundUnit = hour
#是否使用本地时间戳
a3.sinks.k3.hdfs.useLocalTimeStamp = true
#积攒多少个Event才flush到HDFS一次
a3.sinks.k3.hdfs.batchSize = 100
#设置文件类型,可支持压缩
a3.sinks.k3.hdfs.fileType = DataStream
#多久生成一个新的文件
a3.sinks.k3.hdfs.rollInterval = 60
#设置每个文件的滚动大小大概是128M
a3.sinks.k3.hdfs.rollSize = 134217700
#文件的滚动与Event数量无关
a3.sinks.k3.hdfs.rollCount = 0
# Use a channel which buffers events in memory
a3.channels.c3.type = memory
a3.channels.c3.capacity = 1000
a3.channels.c3.transactionCapacity = 100
# Bind the source and sink to the channel
a3.sources.r3.channels = c3
a3.sinks.k3.channel = c3
(4) 创建监控文件的文件夹
//在/opt/module/flume目录下创建files文件夹
[root@hadoopwei flume]$ mkdir files
(5)启动监控文件夹命令
[root@hadoopwei flume]# flume-ng agent --conf conf/ --name a3 --conf-file ./conf/job/flume-taildir-hdfs.conf -Dflume.root.logger=INFO,console
(6)向files文件夹中追加内容
//向upload文件夹中添加文件
[root@hadoopwei files]$ echo hello >> file1.txt
[root@hadoopwei files]$ echo nihaoya >> log1.txt
Taildir说明:
Taildir Source维护了一个json格式的position File,其会定期的往position File中更新每个文件读取到的最新的位置,因此能够实现断点续传。Position File的格式如下:
[{"inode":184550250,,"pos":6,"file":"/opt/module/flume/files/file1.txt"},{"inode":184550251,"pos":8,"file":"/opt/module/flume/files/log1.txt"}]
6、Flume与Kafka集成–Kafka Sink
(1)配置flume-kafka.conf配置文件
# define
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/flume160/flume.log
# sink
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.bootstrap.servers = hadoopwei:9092
a1.sinks.k1.kafka.topic = first
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = 1
a1.sinks.k1.kafka.producer.linger.ms = 1
# 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)启动kafka消费者
[root@hadoopwei jobkb09]# kafka-console-consumer.sh --bootstrap-server hadoopwei:9092 --topic first --from-beginning
hello
nihaoya
meixiangdaoba
(3)执行flume-kafka.conf配置文件
[root@hadoopwei flume160]# flume-ng agent -c ./conf/ -n a1 -f ./conf/jobkb09/flume-kafka.conf
(4) 向 /opt/flume160/flume.log 里追加数据,查看 kafka 消费者消费情况
[root@hadoopwei flume160]# echo hello >> flume.log
[root@hadoopwei flume160]# echo nihaoya >> flume.log
[root@hadoopwei flume160]# echo meixiangdaob >> flume.log
7、HTTP Source
用于接收HTTP的Get和Post请求
(1)编写配置文件
zhu.sources=s1
zhu.channels=c1
zhu.sinks=sk1
zhu.sources.s1.type=http
zhu.sources.s1.port=0827
zhu.channels.c1.type=memory
zhu.sinks.sk1.type=logger
zhu.sources.s1.channels=c1
zhu.sinks.sk1.channel=c1
(2)启动Flume
flume-ng agent -n zhu -f http-flume-logger.conf -Dflume.root.logger=INFO,console
(3)另开一个窗口输入Post
[root@hadooptest1 ~]# curl -XPOST localhost:0827 -d'[{"headers":{"h1":"v1","h2":"v2"},"body":"hello body"}]'
8、使用exec-shell遍历linux目录
(1)编写脚本 vi /root/flume-conf/shell.sh
#!/bin/bash
for i in /root/*
do
echo $i
done
(2)编写flume配置文件
zhu.sources=s1
zhu.channels=c1
zhu.sinks=sk1
zhu.sources.s1.type=exec
zhu.sources.s1.command=bash /root/flume-conf/shell.sh
zhu.channels.c1.type=memory
zhu.sinks.sk1.type=logger
zhu.sources.s1.channels=c1
zhu.sinks.sk1.channel=c1
(3) 执行
[root@hadooptest1 flume-conf]# flume-ng agent -n zhu -f shell-flume-logger.conf -Dflume. root.logger=INFO,console
21/01/15 10:45:09 INFO sink.LoggerSink: Event: { headers:{} body: 2F 72 6F 6F 74 2F 53 7 0 61 72 6B 4C 65 61 72 6E /root/SparkLearn }
21/01/15 10:45:09 INFO sink.LoggerSink: Event: { headers:{} body: 2F 72 6F 6F 74 2F 77 6 3 69 6E 70 75 74 /root/wcinput }
21/01/15 10:45:09 INFO sink.LoggerSink: Event: { headers:{} body: 2F 72 6F 6F 74 2F 77 6 3 6F 75 74 70 75 74 /root/wcoutput }
21/01/15 10:45:09 INFO sink.LoggerSink: Event: { headers:{} body: 2F 72 6F 6F 74 2F 77 6 F 72 64 2E 74 78 74 /root/word.txt }
21/01/15 10:45:09 INFO sink.LoggerSink: Event: { headers:{} body: 2F 72 6F 6F 74 2F 7A 6 F 6F 6B 65 65 70 65 72 2E /root/zookeeper. }
spooling directory source
9、Avro Source & Avro Sink
(1)编写配置文件
vi sink_avro.conf
------------------
zhu.sources=s1
zhu.channels=c1
zhu.sinks=sk1
zhu.sources.s1.type=http
zhu.sources.s1.port=0827
zhu.channels.c1.type=memory
zhu.sinks.sk1.type=avro
zhu.sinks.sk1.hostname=localhost
zhu.sinks.sk1.port=0225
zhu.sources.s1.channels=c1
zhu.sinks.sk1.channel=c1
vi source_avro.conf
----------------------------
zhu.sources=s1
zhu.channels=c1
zhu.sinks=sk1
zhu.sources.s1.type=avro
zhu.sources.s1.bind=localhost
zhu.sources.s1.port=0225
zhu.channels.c1.type=memory
zhu.sinks.sk1.type=logger
zhu.sources.s1.channels=c1
zhu.sinks.sk1.channel=c1
(2)先启动source_avro.conf再启动sink_avro.conf(因为组件sink输出若是端口则该端口号必须事先存在,否则找不到连接拒绝,那么这时候我们先启动source_avro.conf就会启动一个0225的端口号,然后sink_avro.conf里的输出端就找到了这个端口号)
[root@hadooptest1 flume-conf]# flume-ng agent -n zhu -f source_avro.conf -Dflume.root.lo gger=INFO,console
21/01/15 11:22:06 INFO source.AvroSource: Avro source s1 started.
21/01/15 11:22:14 INFO ipc.NettyServer: [id: 0x3b6409f2, /127.0.0.1:51156 => /127.0.0.1: 225] OPEN
21/01/15 11:22:14 INFO ipc.NettyServer: [id: 0x3b6409f2, /127.0.0.1:51156 => /127.0.0.1: 225] BOUND: /127.0.0.1:225
21/01/15 11:22:14 INFO ipc.NettyServer: [id: 0x3b6409f2, /127.0.0.1:51156 => /127.0.0.1: 225] CONNECTED: /127.0.0.1:51156
[root@hadooptest1 flume-conf]# flume-ng agent -n zhu -f sink_avro.conf -Dflume.root.logg
(3)向0827端口发送数据,查看source_avro.conf有无输出
[root@hadooptest1 ~]# curl -XPOST localhost:0827 -d'[{"headers":{"h1":"v1","h2":"v2"},"body":"hello body"}]'
10、SparkStreaming Sink
四 Flume进阶
1、Flume事务
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拓扑结构
简单串联
这种模式是将多个flume顺序连接起来了,从最初的source开始到最终sink传送的目的存储系统。此模式不建议桥接过多的flume数量, flume数量过多不仅会影响传输速率,而且一旦传输过程中某个节点flume宕机,会影响整个传输系统。
复制和多路复用
Flume支持将事件流向一个或者多个目的地。这种模式可以将相同数据复制到多个channel中,或者将不同数据分发到不同的channel中,sink可以选择传送到不同的目的地。
Flume 负载均衡和故障转移
Flume支持使用将多个sink逻辑上分到一个sink组,sink组配合不同的SinkProcessor可以实现负载均衡和错误恢复的功能。
Flume Agent 聚合
这种模式是我们最常见的,也非常实用,日常web应用通常分布在上百个服务器,大者甚至上千个、上万个服务器。产生的日志,处理起来也非常麻烦。用flume的这种组合方式能很好的解决这一问题,每台服务器部署一个flume采集日志,传送到一个集中收集日志的flume,再由此flume上传到hdfs、hive、hbase等,进行日志分析。
五 Flume企业开发案例
1、复制和多路复用
(1)案例需求
使用Flume-1监控文件变动,Flume-1将变动内容传递给Flume-2,Flume-2负责存储到HDFS。同时Flume-1将变动内容传递给Flume-3,Flume-3负责输出到Local FileSystem。
(2)需求分析:
(3)创建 flume-file-flume.conf
- 配置 1 个接收日志文件的 source 和两个 channel、两个 sink,分别输送给 flume-flume-hdfs和 flume-flume-dir。
# Name the components on this agent
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1 c2
# 将数据流复制给所有 channel
a1.sources.r1.selector.type = replicating
# Describe/configure the source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/hive/logs/hive.log
# Describe the 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
# Describe the sink
# sink端的avro是一个数据发送者
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoopwei
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoopwei
a1.sinks.k2.port = 4142
# Bind the source and sink to the channel
a1.sources.r1.channels = c1 c2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2
注:Avro 是由 Hadoop 创始人 Doug Cutting 创建的一种语言无关的数据序列化和 RPC 框 架。
注:RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
(4) 创建 flume-flume-hdfs.conf
- 配置上级 Flume 输出的 Source,输出是到 HDFS 的 Sink。
# Name the components on this agent
a2.sources = r1
a2.sinks = k1
a2.channels = c1
# Describe/configure the source
a2.sources.r1.type = avro
a2.sources.r1.bind = hadoopwei
a2.sources.r1.port = 4141
# Describe the channel
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100
# Describe the sink
a2.sinks.k1.type = hdfs
a2.sinks.k1.hdfs.path = hdfs://hadoopwei: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
#最小冗余数
a2.sinks.k1.hdfs.minBlockReplicas = 1
# Bind the source and sink to the channel
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1
(5) 创建 flume-flume-dir.conf
- 配置上级 Flume 输出的 Source,输出是到本地目录的 Sink。
# Name the components on this agent
a3.sources = r1
a3.sinks = k1
a3.channels = c2
# Describe/configure the source
a3.sources.r1.type = avro
a3.sources.r1.bind = hadoopwei
a3.sources.r1.port = 4142
# Describe the sink
a3.sinks.k1.type = file_roll
a3.sinks.k1.sink.directory = /opt/module/datas/flume3
# Describe the channel
a3.channels.c2.type = memory
a3.channels.c2.capacity = 1000
a3.channels.c2.transactionCapacity = 100
# Bind the source and sink to the channel
a3.sources.r1.channels = c2
a3.sinks.k1.channel = c2
提示:输出的本地目录必须是已经存在的目录,如果该目录不存在,并不会创建新的目录
(6)执行配置文件
分别开启对应配置文件:flume-flume-dir,flume-flume-hdfs,flume-file-flume。
[root@hadoopwei flume160]# flume-ng agent --conf conf/ --name
a3 --conf-file job/group1/flume-flume-dir.conf
[root@hadoopwei flume160]# flume-ng agent --conf conf/ --name
a2 --conf-file job/group1/flume-flume-hdfs.conf
[root@hadoopwei flume160]# flume-ng agent --conf conf/ --name
a1 --conf-file job/group1/flume-file-flume.conf
(7)启动 Hadoop 和 Hive
[root@hadoopwei flume160]# start-all.sh
[root@hadoopwei flume160]# hive
2、负载均衡和故障转移
(1)案例需求
使用Flume1监控一个端口,其sink组中的sink分别对接Flume2和Flume3,采用FailoverSinkProcessor,实现故障转移的功能。
(2)需求分析:
(3)创建 flume-netcat-flume.conf
配 置 1 个接收 日 志 文 件 的 source 和 1 个 channel、 两 个 sink , 分 别 输 送 给flume-flume-console1 和 flume-flume-console2。
# Name the components on this agent
a1.sources = r1
a1.channels = c1
a1.sinkgroups = g1
a1.sinks = k1 k2
# Describe/configure the source
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
#负载均衡
#a1.sinkgroups.g1.processor.type = load_balance
#a1.sinkgroups.g1.processor.backoff = true
#a1.sinkgroups.g1.processor.selector = round_robin
#a1.sinkgroups.g1.processor.selector.maxTimeOut=10000
#故障转移
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
# Describe the sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoopwei
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoopwei
a1.sinks.k2.port = 4142
# Describe the channel
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.sinkgroups.g1.sinks = k1 k2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c1
(4)创建 flume-flume-console1.conf
配置上级 Flume 输出的 Source,输出是到本地控制台。
# Name the components on this agent
a2.sources = r1
a2.sinks = k1
a2.channels = c1
# Describe/configure the source
a2.sources.r1.type = avro
a2.sources.r1.bind = hadoopwei
a2.sources.r1.port = 4141
# Describe the sink
a2.sinks.k1.type = logger
# Describe the channel
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1
(5)创建 flume-flume-console2.conf
配置上级 Flume 输出的 Source,输出是到本地控制台。
# Name the components on this agent
a3.sources = r1
a3.sinks = k1
a3.channels = c2
# Describe/configure the source
a3.sources.r1.type = avro
a3.sources.r1.bind = hadoopwei
a3.sources.r1.port = 4142
# Describe the sink
a3.sinks.k1.type = logger
# Describe the channel
a3.channels.c2.type = memory
a3.channels.c2.capacity = 1000
a3.channels.c2.transactionCapacity = 100
# Bind the source and sink to the channel
a3.sources.r1.channels = c2
a3.sinks.k1.channel = c2
(6)执行配置文件
分别开启对应配置文件:flume-flume-console2,flume-flume-console1,flume-netcat-flume
[root@hadoopwei flume160]# bin/flume-ng agent --conf conf/ --name
a3 --conf-file job/group2/flume-flume-console2.conf
-Dflume.root.logger=INFO,console
[root@hadoopwei flume160]# bin/flume-ng agent --conf conf/ --name
a2 --conf-file job/group2/flume-flume-console1.conf
-Dflume.root.logger=INFO,console
[root@hadoopwei flume160]# bin/flume-ng agent --conf conf/ --name
a1 --conf-file job/group2/flume-netcat-flume.conf
(7)使用 telnet 工具向本机的 44444 端口发送内容
[root@hadoopwei flume160]# telnet localhost 44444
(8)查看 Flume2 及 Flume3 的控制台打印日志
(9)将Flume2 kill,观察Flume3的控制台打印情况。
注:使用jps -ml查看Flume进程。
3、多数据源聚合案例
(1)案例需求:
hadoop102上的Flume-1监控文件/opt/module/group.log,
hadoop103上的Flume-2监控某一个端口的数据流,
Flume-1与Flume-2将数据发送给hadoop104上的Flume-3,Flume-3将最终数据打印
(2)需求分析:
(3)创建 flume1-logger-flume.conf
配置 Source 用于监控 hive.log 文件,配置 Sink 输出数据到下一级 Flume。
在 hadoop103 上创建配置文件并打开
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/group.log
a1.sources.r1.shell = /bin/bash -c
# Describe the sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop104
a1.sinks.k1.port = 4141
# Describe the channel
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
(4)创建 flume2-netcat-flume.conf
配置 Source 监控端口 44444 数据流,配置 Sink 数据到下一级 Flume:
在 hadoop102 上创建配置文件并打开
# Name the components on this agent
a2.sources = r1
a2.sinks = k1
a2.channels = c1
# Describe/configure the source
a2.sources.r1.type = netcat
a2.sources.r1.bind = hadoop102
a2.sources.r1.port = 44444
# Describe the sink
a2.sinks.k1.type = avro
a2.sinks.k1.hostname = hadoop104
a2.sinks.k1.port = 4141
# Use a channel which buffers events in memory
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1
(5)创建 flume3-flume-logger.conf
配置 source 用于接收 flume1 与 flume2 发送过来的数据流,最终合并后 sink 到控制台。
在 hadoop104 上创建配置文件并打开
# Name the components on this agent
a3.sources = r1
a3.sinks = k1
a3.channels = c1
# Describe/configure the source
a3.sources.r1.type = avro
a3.sources.r1.bind = hadoop104
a3.sources.r1.port = 4141
# Describe the sink
a3.sinks.k1.type = logger
# Describe the channel
a3.channels.c1.type = memory
a3.channels.c1.capacity = 1000
a3.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a3.sources.r1.channels = c1
a3.sinks.k1.channel = c1
(6)执行配置文件
分 别 开 启 对 应 配 置 文 件 : flume3-flume-logger.conf , flume2-netcat-flume.conf ,flume1-logger-flume.conf。
[root@hadoop104 flume]# bin/flume-ng agent --conf conf/ --name
a3 --conf-file job/group3/flume3-flume-logger.conf
-Dflume.root.logger=INFO,console
[root@hadoop102 flume]#bin/flume-ng agent --conf conf/ --name
a2 --conf-file job/group3/flume2-netcat-flume.conf
[root@hadoop103 flume]# bin/flume-ng agent --conf conf/ --name
a1 --conf-file job/group3/flume1-logger-flume.conf
(7)在 hadoop103 上向/opt/module 目录下的 group.log 追加内容
[root@hadoop103 module]# echo 'hello' > group.log
(8)在 hadoop102 上向 44444 端口发送数据
[root@hadoop102 flume]# telnet hadoop102 44444
(9)检查hadoop104上数据
4、interceptors拦截器
--------------------------编写user-flume-hdfs.conf(含有interceptors拦截器)----------------
[root@hadoopwei jobkb09]# vi user-flume-hdfs.conf
[root@hadoopwei jobkb09]# cat user-flume-hdfs.conf
users.sources=userSource //定义Sources中的其中一个为userSource
users.channels=userChannel
users.sinks=userSink
users.sources.userSource.type=spooldir //来源为文件目录,可实时传输该目录下的本地文件到hdfs
users.sources.userSource.spoolDir=/opt/flume160/conf/jobkb09/dataSourceFile/user //文件来源
users.sources.userSource.includePattern=users_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv //文件名称
users.sources.userSource.deserializer=LINE //按行序列化
users.sources.userSource.deserializer.maxLineLength=10000 //一行最大长度
users.sources.userSource.interceptors=head_filter //给拦截器定义个名字
users.sources.userSource.interceptors.head_filter.type=regex_filter //拦截器类型为正则匹配拦截器
users.sources.userSource.interceptors.head_filter.regex=^user_id* //正则匹配
users.sources.userSource.interceptors.head_filter.excludeEvents=true //符合条件的删除,保留不符合条件的
users.channels.userChannel.type=file //管道类型为缓存到硬盘
users.channels.userChannel.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/user //检查点路径
users.channels.userChannel.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/user //管道缓存路径
users.sinks.userSink.type=hdfs //文件输出位置
users.sinks.userSink.hdfs.fileType=DataStream //文件输出方式
users.sinks.userSink.hdfs.filePrefix=users //输出文件前缀
users.sinks.userSink.hdfs.fileSuffix=.csv //输出文件后缀
users.sinks.userSink.hdfs.path=hdfs://192.168.198.201:9000/kb09file/user/users/%Y-%m-%d //文件输出路径,可采用本地日期
users.sinks.userSink.hdfs.useLocalTimeStamp=true //使用本地时间戳作为文件名的一部分
users.sinks.userSink.hdfs.batchSize=640 //一次批输出的大小
users.sinks.userSink.hdfs.rollCount=0 //一次输出的数量,定义为0意味着这个参数失效
users.sinks.userSink.hdfs.rollSize=120000000 //一次输出大小达到120M就输出
users.sinks.userSink.hdfs.rollInterval=20 //或者达到20秒就输出
users.sources.userSource.channels=userChannel //一个Source可对应多个Channel
users.sinks.userSink.channel=userChannel //一个Sink只对应一个Channel,但一个Channel可对应多个Sink
--------------------------执行-----------------------
[root@hadoopwei flume160]# flume-ng agent --name users --conf ./conf/ --conf-file ./conf/jobkb09/user-flume-hdfs.conf -Dflume.root.logger=INFO,console
//上下等价
[root@hadoopwei flume160]# flume-ng agent -n users -c ./conf/ -f ./conf/jobkb09/user-flume-hdfs.conf -Dflume.root.logger=INFO,console
--------------------------加载执行文件到Source文件夹---------------
[root@hadoopwei jobkb09]# cp tmp/users.csv /opt/flume160/conf/jobkb09/dataSourceFile/user/users_2020-12-01.csv
六 自定义Flume Agent组件
1、自定义拦截器-两个Channel
(1)需求分析: 根据一行的开头不同分发到不同的hdfs目录下
(2) 在IDEA里写Mave工程
- 首先添加依赖
<dependency>
<groupId>org.apache.flume</groupId>
<artifactId>flume-ng-core</artifactId>
<version>1.6.0</version>
</dependency>
- 然后写程序
package nj.zb.kb09;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author: Zhuuu_ZZ
* @Date 2020/12/1
* @Description:
*/
public class InterceptorDemo implements Interceptor {
private List<Event> addHeaderEvents;
@Override
public void initialize() {
addHeaderEvents=new ArrayList<>();
}
@Override
public Event intercept(Event event) {
byte[] body=event.getBody();
Map<String, String> headers = event.getHeaders();
String bodyStr = new String(body);
if(bodyStr.startsWith("hello")){
headers.put("type","hello");
}else {
headers.put("type","zhu");
}
return event;
}
@Override
public List<Event> intercept(List<Event> events) {
addHeaderEvents.clear(); //因为addHeaderEvents定义在外部,所以每次调用本方法都没有重新创建会有残留数据所以要清洗下。
for (Event event : events) {
addHeaderEvents.add(intercept(event)) ;
}
return addHeaderEvents;
}
@Override
public void close() {
}
public static class Builder implements Interceptor.Builder{ //静态内部类
@Override
public Interceptor build() {
return new InterceptorDemo();
}
@Override
public void configure(Context context) {
}
}
}
(3) 打成jar包并上传到/opt/flume160/lib下
具体打FarJar胖包方式请点击链接查看:
链接: Maven项目打FatJar胖包.
(4) 编写agent文件
[root@hadoopwei jobkb09]# vi netcat-flume-interceptor-hdfs.conf
[root@hadoopwei jobkb09]# cat netcat-flume-interceptor-hdfs.conf
ictdemo.sources=ictSource
ictdemo.channels=ictChannel1 ictChannel2
ictdemo.sinks=ictSink1 ictSink2
ictdemo.sources.ictSource.type=netcat
ictdemo.sources.ictSource.bind=localhost
ictdemo.sources.ictSource.port=7777
ictdemo.sources.ictSource.interceptors=interceptor1
ictdemo.sources.ictSource.interceptors.interceptor1.type=nj.zb.kb09.InterceptorDemo$Builder
ictdemo.sources.ictSource.selector.type=multiplexing
ictdemo.sources.ictSource.selector.header=type
ictdemo.sources.ictSource.selector.mapping.hello=ictChannel1
ictdemo.sources.ictSource.selector.mapping.zhu=ictChannel2
ictdemo.channels.ictChannel1.type=memory
ictdemo.channels.ictChannel1.capacity=1000
ictdemo.channels.ictChannel1.transactionCapacity=1000
ictdemo.channels.ictChannel2.type=memory
ictdemo.channels.ictChannel2.capacity=1000
ictdemo.channels.ictChannel2.transactionCapacity=1000
ictdemo.sinks.ictSink1.type=hdfs
ictdemo.sinks.ictSink1.hdfs.fileType=DataStream
ictdemo.sinks.ictSink1.hdfs.filePrefix=hello
ictdemo.sinks.ictSink1.hdfs.fileSuffix=.csv
ictdemo.sinks.ictSink1.hdfs.path=hdfs://192.168.198.201:9000/kb09file/user/hello/%Y-%m-%d
ictdemo.sinks.ictSink1.hdfs.useLocalTimeStamp=true
ictdemo.sinks.ictSink1.hdfs.batchSize=640
ictdemo.sinks.ictSink1.hdfs.rollCount=0
ictdemo.sinks.ictSink1.hdfs.rollSize=1000
ictdemo.sinks.ictSink1.hdfs.rollInterval=3
ictdemo.sinks.ictSink2.type=hdfs
ictdemo.sinks.ictSink2.hdfs.fileType=DataStream
ictdemo.sinks.ictSink2.hdfs.filePrefix=zhu
ictdemo.sinks.ictSink2.hdfs.fileSuffix=.csv
ictdemo.sinks.ictSink2.hdfs.path=hdfs://192.168.198.201:9000/kb09file/user/zhu/%Y-%m-%d
ictdemo.sinks.ictSink2.hdfs.useLocalTimeStamp=true
ictdemo.sinks.ictSink2.hdfs.batchSize=640
ictdemo.sinks.ictSink2.hdfs.rollCount=0
ictdemo.sinks.ictSink2.hdfs.rollSize=1000
ictdemo.sinks.ictSink2.hdfs.rollInterval=3
ictdemo.sources.ictSource.channels=ictChannel1 ictChannel2
ictdemo.sinks.ictSink1.channel=ictChannel1
ictdemo.sinks.ictSink2.channel=ictChannel2
(5) 执行agent
[root@hadoopwei jobkb09]# flume-ng agent -n ictdemo -c ./conf/ -f ./conf/jobkb09/netcat-flume-interceptor-hdfs.conf -Dflume.root.logger=INFO,console
(6)控制台输入
[root@hadoopwei dataSourceFile]# telnet localhost 7777
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hellofjieg
OK
lalafeif
OK
2、自定义拦截器-三个Channel
(1)IDEA自定义拦截器代码
- 比较测试7,最好不要在第7个测试的IDEA的源程序上修改拦截器内容打Jar包覆盖,这样会导致Jar包冲突,使得代码运行不报错但是没结果。建议:把原先的target文件夹删除,新建一个类,编写代码,重新打Jar包。
package nj.zb.kb09;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author: Zhuuu_ZZ
* @Date 2020/12/1
* @Description:
*/
public class zhu implements Interceptor {
private List<Event> addHeaderEvents;
@Override
public void initialize() {
addHeaderEvents=new ArrayList<>();
}
@Override
public Event intercept(Event event) {
byte[] body=event.getBody();
Map<String, String> headers = event.getHeaders();
String bodyStr = new String(body);
if(bodyStr.contains("kb09")){
headers.put("type","kb09");
}else if (bodyStr.contains("kb07")){
headers.put("type","kb07");
}
else {
headers.put("type","kb05");
}
return event;
}
@Override
public List<Event> intercept(List<Event> events) {
addHeaderEvents.clear();
for (Event event : events) {
addHeaderEvents.add(intercept(event)) ;
}
return addHeaderEvents;
}
@Override
public void close() {
}
public static class Builder implements Interceptor.Builder{
@Override
public Interceptor build() {
return new zhu();
}
@Override
public void configure(Context context) {
}
}
}
(2)编写agent文件kb-flume-hdfs.conf
ict.sources=ictSource
ict.channels=ictChannel1 ictChannel2 ictChannel3
ict.sinks=ictSink1 ictSink2 ictSink3
ict.sources.ictSource.type=netcat
ict.sources.ictSource.bind=localhost
ict.sources.ictSource.port=7777
ict.sources.ictSource.interceptors=interceptor1
ict.sources.ictSource.interceptors.interceptor1.type=nj.zb.kb09.zhu$Builder
ict.sources.ictSource.selector.type=multiplexing
ict.sources.ictSource.selector.header=type
ict.sources.ictSource.selector.mapping.kb09=ictChannel1
ict.sources.ictSource.selector.mapping.kb07=ictChannel2
ict.sources.ictSource.selector.mapping.kb05=ictChannel3
ict.channels.ictChannel1.type=file
ict.channels.ictChannel1.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/ict1 //这里每个管道检查点路径不能是一样
ict.channels.ictChannel1.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/ict1 //管道缓存路径也是。因为管道加载一个event后会暂时锁起来
ict.channels.ictChannel2.type=file
ict.channels.ictChannel2.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/ict2
ict.channels.ictChannel2.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/ict2
ict.channels.ictChannel3.type=file
ict.channels.ictChannel3.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/ict3
ict.channels.ictChannel3.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/ict3
ict.sinks.ictSink1.type=hdfs
ict.sinks.ictSink1.hdfs.fileType=DataStream
ict.sinks.ictSink1.hdfs.filePrefix=kb09
ict.sinks.ictSink1.hdfs.fileSuffix=.csv
ict.sinks.ictSink1.hdfs.path=hdfs://192.168.198.201:9000/kb09file/user/kb09/%Y-%m-%d
ict.sinks.ictSink1.hdfs.useLocalTimeStamp=true
ict.sinks.ictSink1.hdfs.batchSize=640
ict.sinks.ictSink1.hdfs.rollCount=0
ict.sinks.ictSink1.hdfs.rollSize=1000
ict.sinks.ictSink1.hdfs.rollInterval=3
ict.sinks.ictSink2.type=hdfs
ict.sinks.ictSink2.hdfs.fileType=DataStream
ict.sinks.ictSink2.hdfs.filePrefix=kb07
ict.sinks.ictSink2.hdfs.fileSuffix=.csv
ict.sinks.ictSink2.hdfs.path=hdfs://192.168.198.201:9000/kb09file/user/kb07/%Y-%m-%d
ict.sinks.ictSink2.hdfs.useLocalTimeStamp=true
ict.sinks.ictSink2.hdfs.batchSize=640
ict.sinks.ictSink2.hdfs.rollCount=0
ict.sinks.ictSink2.hdfs.rollSize=1000
ict.sinks.ictSink2.hdfs.rollInterval=3
ict.sinks.ictSink3.type=hdfs
ict.sinks.ictSink3.hdfs.fileType=DataStream
ict.sinks.ictSink3.hdfs.filePrefix=kb05
ict.sinks.ictSink3.hdfs.fileSuffix=.csv
ict.sinks.ictSink3.hdfs.path=hdfs://192.168.198.201:9000/kb09file/user/kb05/%Y-%m-%d
ict.sinks.ictSink3.hdfs.useLocalTimeStamp=true
ict.sinks.ictSink3.hdfs.batchSize=640
ict.sinks.ictSink3.hdfs.rollCount=0
ict.sinks.ictSink3.hdfs.rollSize=1000
ict.sinks.ictSink3.hdfs.rollInterval=3
ict.sources.ictSource.channels=ictChannel1 ictChannel2 ictChannel3
ict.sinks.ictSink1.channel=ictChannel1
ict.sinks.ictSink2.channel=ictChannel2
ict.sinks.ictSink3.channel=ictChannel3
ERROR:The directory is already locked
多个管道的缓存类型如果是file,那么就需要多个管道检查点路径和多个缓存路径。
即不能把多个Channel的检查点路径或者缓存路径设为一致
因为一个管道路径被加载后就会暂时锁起来。
(3)创建管道检查点和缓存路径
//ictChannel1
mkdir /opt/flume160/conf/jobkb09/checkPointFile/ict1
mkdir /opt/flume160/conf/jobkb09/dataChannelFile/ict1
//ictChannel2
mkdir /opt/flume160/conf/jobkb09/checkPointFile/ict2
mkdir /opt/flume160/conf/jobkb09/dataChannelFile/ict2
//ictChannel3
mkdir /opt/flume160/conf/jobkb09/checkPointFile/ict3
mkdir /opt/flume160/conf/jobkb09/dataChannelFile/ict3
(4) 执行agent文件
flume-ng agent -n ict -c /opt/flume160/conf/ -f /opt/flume160/conf/jobkb09/kb-flume-hdfs.conf -Dflume.root.logger=INFO,console
(5)控制台输入语句
[root@hadoopwei dataSourceFile]# telnet localhost 7777
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
dfjsifkb09jife
OK
fjiefjekb05jivo
OK
fjiefkb07jive
OK
(6)HDFS运行结果
3、自定义Source
(1)介绍
- Source是负责接收数据到Flume Agent的组件。Source组件可以处理各种类型、各种格式的日志数据,包括avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy。官方提供的source类型已经很多,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些source。
- 官方也提供了自定义source的接口:
- 链接:官方自定义Source
- 根据官方说明自定义MySource需要继承AbstractSource类并实现Configurable和PollableSource接口。
- 实现相应方法:
- getBackOffSleepIncrement()//暂不用
- getMaxBackOffSleepInterval()//暂不用
- configure(Context context)//初始化context(读取配置文件内容)
- process()//获取数据封装成event并写入channel,这个方法将被循环调用。
- 使用场景:读取MySQL数据或者其他文件系统。
(2)需求
使用flume接收数据,并给每条数据添加前缀,输出到控制台。前缀可从flume配置文件中配置。
(3)需求分析:
(4)编码
- 导入pom依赖
<dependencies>
<dependency>
<groupId>org.apache.flume</groupId>
<artifactId>flume-ng-core</artifactId>
<version>1.6.0</version>
</dependency>
</dependencies>
- 编写代码
package com.cn
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;
import java.util.HashMap;
public class MySource extends AbstractSource implements Configurable, PollableSource {
//定义配置文件将来要读取的字段
private Long delay;
private String field;
//初始化配置信息
@Override
public void configure(Context context) {
delay = context.getLong("delay");
field = context.getString("field", "Hello!");
}
@Override
public Status process() throws EventDeliveryException {
try {
//创建事件头信息
HashMap<String, String> hearderMap = new HashMap<>();
//创建事件
SimpleEvent event = new SimpleEvent();
//循环封装事件
for (int i = 0; i < 5; i++) {
//给事件设置头信息
event.setHeaders(hearderMap);
//给事件设置内容
event.setBody((field + i).getBytes());
//将事件写入channel
getChannelProcessor().processEvent(event);
Thread.sleep(delay);
}
} catch (Exception e) {
e.printStackTrace();
return Status.BACKOFF;
}
return Status.READY;
}
@Override
public long getBackOffSleepIncrement() {
return 0;
}
@Override
public long getMaxBackOffSleepInterval() {
return 0;
}
}
(5)测试
- 打包
将写好的代码打包,并放到flume的lib目录下。
- 配置文件
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = com.cn.MySource
a1.sources.r1.delay = 1000
#a1.sources.r1.field = atguigu
# 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
- 开启任务
[root@hadoopwei flume160]# bin/flume-ng agent -c conf/ -f job/mysource.conf -n a1 -Dflume.root.logger=INFO,console
- 查看结果
4、自定义Sink
(1)介绍
-
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。
-
官方也提供了自定义sink的接口:
-
根据官方说明自定义MySink需要继承AbstractSink类并实现Configurable接口。
-
实现相应方法:
- configure(Context context)//初始化context(读取配置文件内容)
- process()//从Channel读取获取数据(event),这个方法将被循环调用。
-
使用场景:读取Channel数据写入MySQL或者其他文件系统。
(2)需求
使用flume接收数据,并在Sink端给每条数据添加前缀和后缀,输出到控制台。前后缀可在flume任务配置文件中配置。
(3)编码
package com.cn;
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 LOG = LoggerFactory.getLogger(AbstractSink.class);
private String prefix;
private String suffix;
@Override
public Status process() throws EventDeliveryException {
//声明返回值状态信息
Status status;
//获取当前Sink绑定的Channel
Channel ch = getChannel();
//获取事务
Transaction txn = ch.getTransaction();
//声明事件
Event event;
//开启事务
txn.begin();
//读取Channel中的事件,直到读取到事件结束循环
while (true) {
event = ch.take();
if (event != null) {
break;
}
}
try {
//处理事件(打印)
LOG.info(prefix + new String(event.getBody()) + suffix);
//事务提交
txn.commit();
status = Status.READY;
} catch (Exception e) {
//遇到异常,事务回滚
txn.rollback();
status = Status.BACKOFF;
} finally {
//关闭事务
txn.close();
}
return status;
}
@Override
public void configure(Context context) {
//读取配置文件内容,有默认值
prefix = context.getString("prefix", "hello:");
//读取配置文件内容,无默认值
suffix = context.getString("suffix");
}
}
(4)测试
- 打包
将写好的代码打包,并放到flume的lib目录(/opt/module/flume)下。
- 配置文件
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
# Describe the sink
a1.sinks.k1.type = com.cn.MySink
#a1.sinks.k1.prefix = atguigu:
a1.sinks.k1.suffix = :atguigu
# 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
- 开启任务
[root@hadoopwei flume160]$ bin/flume-ng agent -c conf/ -f job/mysink.conf -n a1 -Dflume.root.logger=INFO,console
[root@hadoopwei ~]$ nc localhost 44444
hello
OK
atguigu
OK
- 结果展示
七 Flume数据流监控-Ganglia
#单机
yum -y install epel-release
sudo yum install ganglia-gmond
sudo yum install ganglia-gmetad
yum install httpd php
service httpd restart
#重启httpd服务后,此时浏览器访问你的ip应该有界面,否则重新安装httpd并重启服务
yum install -y wget
wget https://jaist.dl.sourceforge.net/project/ganglia/ganglia-web/3.7.2/ganglia-web-3.7.2.tar.gz
tar -xvzf ganglia-web-3.7.2.tar.gz
mv ganglia-web-3.7.2 /opt
cd /opt/ganglia-web-3.7.2/
adduser www-data
cp -r /opt/ganglia-web-3.7.2 /var/www/html/ganglia
mkdir -p /var/lib/ganglia-web/conf
touch /var/lib/ganglia-web/conf/events.json
touch /var/lib/ganglia-web/conf/event_color.json
mkdir -p /var/lib/ganglia-web/dwoo/compiled
mkdir -p /var/lib/ganglia-web/dwoo/cache
chmod 777 /var/lib/ganglia-web/dwoo/compiled
chmod 777 /var/lib/ganglia-web/dwoo/cache
service gmond restart
service gmetad restart
service httpd restart
#集群
#主节点:
vi /etc/ganglia/gmetad.conf
#修改为
data_source "my cluster" localhost hadooptest3 hadooptest4
#从节点
yum -y install epel-release
sudo yum install ganglia-gmond
#修改从节点配置文件
vi /etc/ganglia/gmond.conf
#修改host为location=主机ip
host {
location = 192.168.198.112
}
#启动
#主机
service gmond restart
service gmetad restart
service httpd restart
#从机
service gmond restart
八 企业真实面试题
1、你是如何实现 Flume 数据传输的监控的
- 使用第三方框架 Ganglia 实时监控 Flume。
2、Flume 的 Source,Sink,Channel 的作用?
- Source 组件是专门用来收集数据的,可以处理各种类型、各种格式的日志数据,
包括 avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy - Channel 组件对采集到的数据进行缓存,可以存放在 Memory 或 File 中。
- Sink 组件是用于把数据发送到目的地的组件,目的地包括 Hdfs、Logger、avro、thrift、ipc、file、Hbase、solr、自定义。
3、Flume参数调优
(1)Source
- 增加 Source 个(使用 Tair Dir Source 时可增加 FileGroups 个数)可以增大 Source 的读取数据的能力。例如:当某一个目录产生的文件过多时需要将这个文件目录拆分成多个文件目录,同时配置好多个 Source 以保证 Source 有足够的能力获取到新产生的数据。
- batchSize 参数决定 Source 一次批量运输到 Channel 的 event 条数,适当调大这个参数可以提高 Source 搬运 Event 到 Channel 时的性能。
(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 参数。
(3)Sink - 增加 Sink 的个数可以增加 Sink 消费 event 的能力。Sink 也不是越多越好够用就行,过多的 Sink 会占用系统资源,造成系统资源不必要的浪费。
- batchSize 参数决定 Sink 一次批量从 Channel 读取的 event 条数,适当调大这个参数可以提高 Sink 从 Channel 搬出 event 的性能。
4、Flume 的事务机制
- Flume 的事务机制(类似数据库的事务机制):Flume 使用两个独立的事务分别负责从Soucrce 到 Channel,以及从 Channel 到 Sink 的事件传递。比如 spooling directory source 为文件的每一行创建一个事件,一旦事务中所有的事件全部传递到 Channel 且提交成功,那么Soucrce 就将该文件标记为完成。同理,事务以类似的方式处理从 Channel 到 Sink 的传递过程,如果因为某种原因使得事件无法记录,那么事务将会回滚。且所有的事件都会保持到Channel 中,等待重新传递。
5、 Flume 采集数据会丢失吗?
- 根据Flume的架构原理,Flume是不可能丢失数据的,其内部有完善的事务机制,Source到Channel是事务性的,Channel到Sink是事务性的,因此这两个环节不会出现数据的丢失,唯一可能丢失数据的情况是Channel采用memoryChannel,agent宕机导致数据丢失,或者Channel存储数据已满,导致Source不再写入,未写入的数据丢失。
- Flume不会丢失数据,但是有可能造成数据的重复,例如数据已经成功由Sink发出,但是没有接收到响应,Sink会再次发送数据,此时可能会导致数据的重复。