Flume实时数据采集工具的使用
Flume的开发已经接近极致,可以看到最近两年也没有什么更新,是一款非常实用的实时数据采集工具,可以满足大数据采集的大多数要求(全量采集还是建议用sqoop,别问为什么,问就是你的全量采集你也可以用Flume,前提是你不怕被打,前前提是你的内存还能腾出地儿给别的任务跑)。
具体的使用请往后看,这款工具真的是不用脑子,有手就行,基本上你要考虑的人家都给你考虑到了,要用什么直接去官网cp过来改改就完事了,有人非要杠,开发到极致了还要改,洗洗睡吧你。
1.功能
1.可以将各种不同的数据源的数据实时采集到各种目标中。
2.特点
1.1实时采集,也可以做离线采集
1.2.采集:文件、端口
发送:HDFS、Hive、Hbase、Kafka
1.3.允许自定义开发
1.4.开发相对简单,所有功能基本已经封装好了,只需要开发一个配置文件。
1.5.虽然不是分布式工具,但可以将Flume部署在多台机器上,一起采集,实现分布式采集。
3.应用
应用于实时文件、网络数据流采集场景。
参考:美团的Flume设计架构
Flume的基本组成
step1:Agent
step2:Source
step3:Channel
step4:Sink
step5:Event
**官网:flume.apache.org**
Agent:
一个Agent表示一个Flume程序,实现采集数据源的数据,将 数据采集发送到目标地
将WebServer的日志采集以后写入HDFS
任何一个Agent实现数据采集,都必须由三个基本组件构成
Source、Channel、Sink
Source:
负责监听数据源的数据变化,如果数据源产生新的数据,就立即进行采集
负责实现数据采集
将数据源的每一行数据变成一个Event对象,发送给Channel
Channel:
负责接收Source采集到的数据,供Sink来读取数据
采集数据的临时缓存的
Sink:
负责从Channel中读取采集的数据,将数据写入目标地
最终实现数据发送的组件
Event:
数据流传输的最小的封装的单元,将每一行封装为一个Event
结构
header:类似于一个Map集合存储,默认为空的,可以选择性在header放KV对,一些属性的配置等
body:类似于一个字节数组,存放真正的这条数据的内容
作用:实现每一条数据的封装
Flume的开发规则
step1:开发一个Flume的参数配置文件
需要在配置文件中定义Agent
定义Agent的名称
定义Source:从哪读取数据
定义Channel:将数据缓存在哪
定义Sink:将数据发送到哪
**一个文件可以有多个Agent,具体区分每个Agent通过Agent名称来区分**
**step2:运行flume的agent程序**,运行这个程序所在的文件,指定agent的名称即可
--用法
flume-ng <command> [options]...
--使用
flume-ng agent -c/--conf 指定Flume配置文件目录 --name/-n 指定Agent的名称 --conf-file/-f 指定要运行的文件
Flume开发测试
需求:采集Hive的日志、临时缓存在内存中、将日志写入Flume的日志中并打印在命令行
source:采集一个文件数据
Exec Source:通过执行一条Linux命令来实现文件的动态采集
channel:Flume提供了各种channel用于缓存数据
mem channel:将数据缓存在内存中
sink:Flume提供了很多种sink
Logger Sink:将数据写入日志中
**
开发实例
**
创建测试目录 cd /export/server/flume-1.6.0-cdh5.14.0-bin
mkdir usercase
复制官方示例 cp conf/flume-conf.properties.template usercase/hive-mem-log.properties
开发配置文件
# The configuration file needs to define the sources,
# the channels and the sinks.
# Sources, channels and sinks are defined per a1,
# in this case called 'a1'
#define the agent
a1.sources = s1
a1.channels = c1
a1.sinks = k1
#define the source
a1.sources.s1.type = exec
a1.sources.s1.command = tail -f /export/server/hive-1.1.0-cdh5.14.0/logs/hiveserver2.log
#define the channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 10000
#define the sink
a1.sinks.k1.type = logger
#bond
a1.sources.s1.channels = c1
a1.sinks.k1.channel = c1
**运行**
flume-ng agent -c conf/ -f usercase/hive-mem-log.properties -n a1 -Dflume.root.logger=INFO,console
运行结果
常用Source:Exec
**功能与应用场景**
- 功能:**通过执行一条Linux命令来实现数据==动态采集==**
- 固定搭配tail -f命令来使用
- 增量采集
- **==应用场景:实现动态监听采集单个文件的数据==**
- 缺点:如果日志是多个文件的动态变化
常用Source:Taildir
**功能与应用场景**
- 应用场景
- 需求:当前日志文件是一天一个,需要每天将数据实时采集到HDFS上
- 数据:Linux
```
/tomcat/logs/2020-01-01.log
2020-01-02.log
……
2020-11-10.log
```
- 问题:能不能exec source进行采集?
- 不能,exec只能监听采集单个文件
- 解决:Taildir Source
- 功能:从Apache Flume1.7版本开始支持,动态监听采集多个文件
- 如果用的是1.5或者1.6,遇到这个问题,需要自己手动编译这个功能
测试实现
- 需求:让Flume动态监听一个文件和一个目录下的所有文件
- 准备
cd /export/server/flume-1.6.0-cdh5.14.0-bin
mkdir position
mkdir -p /export/data/flume
echo " " >> /export/data/flume/bigdata01.txt
mkdir -p /export/data/flume/bigdata
开发
# define sourceName/channelName/sinkName for the agent
a1.sources = s1
a1.channels = c1
a1.sinks = k1
# define the s1
a1.sources.s1.type = TAILDIR
#指定一个元数据记录文件
a1.sources.s1.positionFile = /export/server/flume-1.6.0-cdh5.14.0-bin/position/taildir_position.json
#将所有需要监控的数据源变成一个组,这个组内有两个数据源
a1.sources.s1.filegroups = f1 f2
#指定了f1是谁:监控一个文件
a1.sources.s1.filegroups.f1 = /export/data/flume/bigdata01.txt
#指定f1采集到的数据的header中包含一个KV对
a1.sources.s1.headers.f1.headerKey1 = value1
#指定f2是谁:监控一个目录下的所有文件
a1.sources.s1.filegroups.f2 = /export/data/flume/bigdata/.*
#指定f2采集到的数据的header中包含一个KV对
a1.sources.s1.headers.f2.headerKey1 = value2
a1.sources.s1.fileHeader = true
# define the c1
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# def the k1
a1.sinks.k1.type = logger
#source、channel、sink bond
a1.sources.s1.channels = c1
a1.sinks.k1.channel = c1
元数据文件的功能:/export/server/flume-1.6.0-cdh5.14.0-bin/position/taildir_position.json
- 问题:如果Flume程序故障,重启Flume程序,已经被采集过的数据还要不要采集?
- 需求:不需要,不能导致数据重复
- 功能:记录Flume所监听的每个文件已经被采集的位置
- 补充:其他的source**
- - **Kafka Source**:监听读取Kafka数据
- - **Spooldir Source**:监控一个目录,只要这个目录中产生一个文件,就会全量采集一个文件
- 缺点:不能动态监控文件,被采集的文件是不能发生变化的
常用Channel:file和mem
- mem Channel:将数据缓存在内存中
- 特点:读写快、容量小、安全性较差
- 应用:小数据量的高性能的传输
- file Channel:将数据缓存在文件中
- 特点:读写相对慢、容量大、安全性较高
- 应用:数据量大,读写性能要求不高的场景下
常用Sink:HDFS
HDFS sink的功能
- 常用的SINk
- Kafka SInk:实时
- HDFS SInk:离线
- 问题:为什么离线采集不直接写入Hive,使用Hive sink
- 原因一:数据可能不是结构化的数据文件
- 原因二:Hive表必须为分桶结构表,数据文件类型必须为ORC类型
- 功能:将Flume采集的数据写入HDFS
- 问题:Flume作为HDFS客户端,写入HDFS数据
- Flume必须知道HDFS地址
- Flume必须拥有HDFS的jar包
- 解决
- 方式一:Flume写地址的时候,指定HDFS的绝对地址
hdfs://node1:8020/nginx/log
- 手动将需要的jar包放入Flume的lib目录下
- 方式二:在Flume中配置Hadoop的环境变量,将core-site和hdfs-site放入Flume的配置文件目录
- 演示
需求:将Hive的日志动态采集写入HDFS
# The configuration file needs to define the sources,
# the channels and the sinks.
# Sources, channels and sinks are defined per a1,
# in this case called 'a1'
#定义当前的agent的名称,以及对应source、channel、sink的名字
a1.sources = s1
a1.channels = c1
a1.sinks = k1
#定义s1:从哪读数据,读谁
a1.sources.s1.type = exec
a1.sources.s1.command = tail -f /export/server/hive-1.1.0-cdh5.14.0/logs/hiveserver2.log
#定义c1:缓存在什么地方
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
#定义k1:将数据发送给谁
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://node1:8020/flume/test1
#s1将数据给哪个channel
a1.sources.s1.channels = c1
#k1从哪个channel中取数据
a1.sinks.k1.channel = c1
指定文件大小
- 问题:Flume默认写入HDFS上会产生很多小文件,都在1KB左右,不利用HDFS存储
- 解决:指定文件大小
hdfs.rollInterval:按照时间间隔生成文件
hdfs.rollSize:指定HDFS生成的文件大小
hdfs.rollCount:按照event个数生成文件
# The configuration file needs to define the sources,
# the channels and the sinks.
# Sources, channels and sinks are defined per a1,
# in this case called 'a1'
#定义当前的agent的名称,以及对应source、channel、sink的名字
a1.sources = s1
a1.channels = c1
a1.sinks = k1
#定义s1:从哪读数据,读谁
a1.sources.s1.type = exec
a1.sources.s1.command = tail -f /export/server/hive-1.1.0-cdh5.14.0/logs/hiveserver2.log
#定义c1:缓存在什么地方
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
#定义k1:将数据发送给谁
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://node1:8020/flume/test1
#指定按照时间生成文件,一般关闭
a1.sinks.k1.hdfs.rollInterval = 0
#指定文件大小生成文件,一般120 ~ 125M对应的字节数
a1.sinks.k1.hdfs.rollSize = 10240
#指定event个数生成文件,一般关闭
a1.sinks.k1.hdfs.rollCount = 0
#s1将数据给哪个channel
a1.sources.s1.channels = c1
#k1从哪个channel中取数据
a1.sinks.k1.channel = c1
指定分区
- 问题:如何实现分区存储,每天一个或者每小时一个目录?
- 解决:添加时间标记目录
# The configuration file needs to define the sources,
# the channels and the sinks.
# Sources, channels and sinks are defined per a1,
# in this case called 'a1'
#定义当前的agent的名称,以及对应source、channel、sink的名字
a1.sources = s1
a1.channels = c1
a1.sinks = k1
#定义s1:从哪读数据,读谁
a1.sources.s1.type = exec
a1.sources.s1.command = tail -f /export/server/hive-1.1.0-cdh5.14.0/logs/hiveserver2.log
#定义c1:缓存在什么地方
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
#定义k1:将数据发送给谁
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://node1:8020/flume/log/daystr=%Y%m%d
#指定按照时间生成文件,一般关闭
a1.sinks.k1.hdfs.rollInterval = 0
#指定文件大小生成文件,一般120 ~ 125M对应的字节数
a1.sinks.k1.hdfs.rollSize = 10240
#指定event个数生成文件,一般关闭
a1.sinks.k1.hdfs.rollCount = 0
a1.sinks.k1.hdfs.useLocalTimeStamp = true
#s1将数据给哪个channel
a1.sources.s1.channels = c1
#k1从哪个channel中取数据
a1.sinks.k1.channel = c1
其他参数
#指定生成的文件的前缀
a1.sinks.k1.hdfs.filePrefix = nginx
#指定生成的文件的后缀
a1.sinks.k1.hdfs.fileSuffix = .log
#指定写入HDFS的文件的类型:普通的文件
a1.sinks.k1.hdfs.fileType = DataStream