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**

flume采集日志文件配置 flume数据采集_HDFS

flume采集日志文件配置 flume数据采集_hdfs_02

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:采集一个文件数据

flume采集日志文件配置 flume数据采集_hdfs_03

Exec Source:通过执行一条Linux命令来实现文件的动态采集

channel:Flume提供了各种channel用于缓存数据

flume采集日志文件配置 flume数据采集_flume采集日志文件配置_04

mem channel:将数据缓存在内存中

sink:Flume提供了很多种sink

flume采集日志文件配置 flume数据采集_flume采集日志文件配置_05

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

运行结果

flume采集日志文件配置 flume数据采集_flume采集日志文件配置_06

常用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