简介
Flume 是 Cloudera 提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力
一、概述
1.1、工作方式
Flume-og 采用了多 Master 的方式。为了保证配置数据的一致性,Flume 引入了 ZooKeeper,用于保存配置数据,ZooKeeper 本身可保证配置数据的一致性和高可用,另外,在配置数据发生变化时,ZooKeeper 可以通知 Flume Master 节点。Flume Master 间使用 gossip 协议同步数据。
Flume-ng 最明显的改动就是取消了集中管理配置的 Master 和 Zookeeper,变为一个纯粹的传输工具。Flume-ng 另一个主要的不同点是读入数据和写出数据由不同的工作线程处理(称为 Runner)。 在 Flume-og 中,读入线程同样做写出工作(除了故障重试)。如果写出慢的话(不是完全失败),它将阻塞 Flume 接收数据的能力。这种异步的设计使读入线程可以顺畅的工作而无需关注下游的任何问题。
1.2、优势
- Flume 可以将应用产生的数据存储到任何集中存储器中,比如 HDFS,HBase
- 当收集数据的速度超过将写入数据的时候,也就是当收集信息遇到峰值时,这时候收集的信息非常大,甚至超过了系统的写入数据能力,这时候,Flume 会在数据生产者和数据收容器间做出调整,保证其能够在两者之间提供平稳的数据
- 提供上下文路由特征
- Flume 的管道是基于事务,保证了数据在传送和接收时的一致性
- Flume 是可靠的,容错性高的,可升级的,易管理的,并且可定制的
1.3、特征
- Flume 可以高效率的将多个网站服务器中收集的日志信息存入 HDFS/HBase 中
- 使用 Flume,我们可以将从多个服务器中获取的数据迅速的移交给 Hadoop 中
- 除了日志信息,Flume 同时也可以用来接入收集规模宏大的社交网络节点事件数据,比如facebook,twitter,电商网站如亚马逊,flipkart 等
- 支持各种接入资源数据的类型以及接出数据类型
- 支持多路径流量,多管道接入流量,多管道接出流量,上下文路由等
- 可以被水平扩展
1.4、核心组件概述
- Client:客户端,数据产生的地方,如Web服务器
- Event:事件,指通过 Agent 传输的单个数据包,如日志数据通常对应一行数据
- Flow:Event 从源点到达目的点的迁移的抽象
- Agent:一个独立的 JVM 进程,Agent 使用JVM 运行 Flume
Agent 主要由:source,channel,sink 三个组件组成
1.4.1、Source
从数据发生器接收数据,并将接收的数据以 Flume 的 event 格式传递给一个或者多个通道channel,Flume 提供多种数据接收的方式,比如 Avro,Thrift,twitter1% 等
1.4.2、Channel
channel 是一种短暂的存储容器,它将从 source 处接收到的 event 格式的数据缓存起来,直到它们被 sinks 消费掉,它在 source 和 sink 间起着桥梁的作用,channel 是一个完整的事务,这一点保证了数据在收发的时候的一致性;并且它可以和任意数量的 source 和 sink 链接,支持的类型有:JDBC channel,File System channel,Memory channel 等
1.4.3、sink
sink 将数据存储到集中存储器比如 Hbase 和 HDFS,它从 channels 消费数据(events)并将其传递给目标地,目标地可能是另一个 sink,也可能 HDFS,HBase
二、Flume 的体系结构
Flume 运行的核心是 Agent,Flume 以 agent 为最小的独立运行单位;一个 agent 就是一个JVM;它是一个完整的数据收集工具,含有三个核心组件,分别是 source,channel,sink;通过这些组件,Event 可以从一个地方流向另一个地方,如下图所示
2.1、Source
Source 是数据的收集端,负责将数据捕获后进行特殊的格式化,将数据封装到事件(event)里,然后将事件推入 Channel 中
Flume 提供了各种 source 的实现,如果内置的 Source 无法满足需要,Flume 还支持自定义 Source
Flume 常用 Source 如下
- exec source:执行 Linux 指令,并消费指令返回的结果,如
tail -f
- spooling directory source:从磁盘文件夹中获取文件数据,可避免重启或者发送失败后数据丢失,还可用于监控文件夹新文件
- http source:用于接收HTTP的Get和Post请求
- avro source:监听Avro端口,并从外部Avro客户端接收events
- kafka source:从 Kafka 接收数据
- netcat source:从 NetCat 服务器接收数据
exec source
执行 Linux 指令,并消费指令返回的结果
属性 | 缺省值 | 描述 |
---|---|---|
type | - | exec |
command | - | 如tail -f xxx.log |
shell | - | 选择系统Shell程序,如/bin/sh |
batchSize | 20 | 发送给channel的最大行数 |
command 可执行脚本
for i in /path/*.txt; do echo $i; done
遍历目录
spooling directory source
从磁盘文件夹中获取文件数据,可避免重启或者发送失败后数据丢失,还可用于监控文件夹新文件
属性 | 缺省值 | 描述 |
---|---|---|
type | - | spooldir |
spoolDir | - | 需读取的文件夹 |
fileSuffix | .COMPLETED | 文件读取完成后添加的后缀 |
deletePolicy | never | 文件完成后删除策略:never和immediate |
http source
用于接收HTTP的Get和Post请求
属性 | 缺省值 | 描述 |
---|---|---|
type | - | http |
port | - | 监听端口 |
bind | 0.0.0.0 | 绑定IP |
handler | org.apache.flume.source.http.JSONHandler | 数据处理程序类全名 |
avro source
监听 Avro 端口,并从外部 Avro 客户端接收 events
属性 | 缺省值 | 描述 |
---|---|---|
type | - | avro |
port | - | 监听端口 |
bind | - | 绑定IP |
threads | - | 最大工作线程数量 |
2.2、Channel
Channel是连接Source和Sink的组件,大家可以将它看做一个数据的缓冲区(数据队列),它可以将事件暂存到内存中也可以持久化到本地磁盘上, 直到Sink处理完该事件
Flume 对于 Channel,则提供了 Memory Channel、JDBC Chanel、File Channel,etc
MemoryChannel:event保存在本地文件中,可靠性高,但吞吐量低于Memory Channel
FileChannel:保证数据的完整性与一致性。在具体配置不现的 FileChannel 时,建议 FileChannel 设置的目录和程序日志文件保存的目录设成不同的磁盘,以便提高效率
JDBC Channel:event保存在关系数据中,一般不推荐使用
2.3、Sink
Flume Sink 取出 Channel 中的数据,进行相应的存储文件系统,数据库,或者提交到远程服务器
Flume 也提供了各种 sink 的实现,包括 HDFS sink、Logger sink、Avro sink、File Roll sink、Null sink、HBase sink,Kafka sink,Hive sink
Flume Sink 在设置存储数据时,可以向文件系统中,数据库中,hadoop 中储数据,在日志数据较少时,可以将数据存储在文件系中,并且设定一定的时间间隔保存数据。在日志数据较多时,可以将相应的日志数据存储到 Hadoop 中,便于日后进行相应的数据分析
avro sink
作为 avro 客户端向 avro 服务端发送 avro 事件
属性 | 缺省值 | 描述 |
---|---|---|
type | - | avro |
port | - | 监听端口 |
hostname | - | 服务端IP地址 |
batch-size | 100 | 批量发送事件数量 |
HDFS sink
将事件写入Hadoop分布式文件系统(HDFS)
属性 | 缺省值 | 描述 |
---|---|---|
type | - | hdfs |
hdfs.path | - | hdfs 目录 |
hfds.filePrefix | FlumeData | 文件前缀 |
hdfs.fileSuffix | - | 文件后缀 |
HBase sink
属性 | 缺省值 | 描述 |
---|---|---|
type | - | hbase |
table | - | 要写入的 Hbase 表名 |
columnFamily | - | 要写入的 Hbase 列族 |
zookeeperQuorum | - | 对应hbase.zookeeper.quorum |
znodeParent | /hbase | zookeeper.znode.parent |
serializer | org.apache.flume.sink.hbase.SimpleHbaseEventSerializer | 一次事件插入一列 |
serializer.payloadColumn | - | 列名col1 |
三、Flume的部署类型
3.1、单一流程
指一个 Agent JVM 进程,如下图
3.2、多代理流程(多个agent顺序连接)
多个 Agent 顺序连接起来,将最初的数据源经过收集,存储到最终的存储系统中。这是最简单的情况,一般情况下,应该控制这种顺序连接的 Agent 的数量,因为数据流经的路径变长了,如果不考虑 failover 的话,出现故障将影响整个Flow上的Agent收集服务。
3.3、流的合并(多个Agent的数据汇聚到同一个Agent)
这种情况应用的场景比较多,比如要收集 Web 网站的用户行为日志,Web 网站为了可用性使用的负载集群模式,每个节点都产生用户行为日志,可以为每 个节点都配置一个 Agent 来单独收集日志数据,然后多个 Agent 将数据最终汇聚到一个用来存储数据存储系统,如HDFS上
3.4、多路复用流(多级流)
Flume 还支持多级流,举个例子,当syslog, java, nginx、 tomcat 等混合在一起的日志流开始流入一个 agent 后,可以 agent 中将混杂的日志流分开,然后给每种日志建立一个自己的传输通道
3.5、load balance功能
下图 Agent1 是一个路由节点,负责将 Channel 暂存的 Event 均衡到对应的多个 Sink 组件上,而每个 Sink 组件分别连接到一个独立的 Agent 上
四、Flume的日志收集输出(精华所在)
4.1、netcat source,logger sink
创建 flume 文件netcat-flume-logger.conf
a1.sources=r1
a1.channels=c1
a1.sinks=k1
a1.sources.r1.type=netcat
a1.sources.r1.bind=localhost
a1.sources.r1.port=7777
a1.channels.c1.type=memory
a1.channels.c1.capacity=1000
a1.channels.c1.transactionCapacity=1000
a1.sinks.k1.type=logger
a1.sources.r1.channels=c1
a1.sinks.k1.channel=c1
参数解析:
-
source.xxx.type:数据来源类型
-
source.xxx.bind:来源地址
-
source.xxx.port:自定义端口号
-
channels.xxx.type:通道数据中的 event 类型
-
channels.xxx.capacity:通道容量
-
channels.xxx.transactionCapacity:通道的吞吐量
-
sink.xxx.type:sink 存储数据方式
-
source.xxx.channels:连接数据收集端(source)和通道(channels)
-
sink.xxx.channels:连接通道(channels)和数据消费端(sink)
启动 flume 文件命令
flume-ng agent \
--name a1 \
--conf /opt/flume/conf/ \
--conf-file /opt/data/flumedir/confs/netcat-flume-logger.conf \
-Dflume.root.logger=INFO,console
// 可简写成以下格式
flume-ng agent \
-n a1 \
-c /opt/flume/conf/ \
-f /opt/data/flumedir/confs/netcat-flume-logger.conf \
-Dflume.root.logger=INFO,console
参数说明:
-
--name
或者-n
:进程名字,即上面的 a1 -
--conf-file
或者-f
:创建的 flume 文件路径,建议使用绝对路径 -
--conf
或者-c
:Flume 安装目录下配置文件 conf 目录的路径,建议使用绝对路径,可省略 -
Dflume.root.logger=INFO,console
:设置日志级别,可省略
启动 netcat 客户端查看结果:
telnet localhost 7777
777为自定义端口号,不固定,也可定义为其他的,例如:5555等
在控制台输入,客户端会同步显示出控制台输入的内容
同样也可以在客户端输入回车后,控制台也可以看到结果
运行结果如下:
4.2、exec source,logger sink
创建 flume 文件file-flume-logger.conf
a2.sources=r1
a2.channels=c1
a2.sinks=k1
a2.sources.r1.type=exec
a2.sources.r1.command=tail -f /opt/data/flumedir/tmp/a.txt
a2.channels.c1.type=memory
a2.channels.c1.capacity=1000
a2.channels.c1.transactionCapacity=1000
a2.sinks.k1.type=logger
a2.sources.r1.channels=c1
a2.sinks.k1.channel=c1
参数说明:
-
exec:表示单个文件作为数据源
-
source.xxx.command=tail -f path:文件路径
启动 flume 文件命令
flume-ng agent \
-n a2 \
-c /opt/flume/conf/ \
-f /opt/data/flumedir/confs/file-flume-logger.conf \
-Dflume.root.logger=INFO,console
4.3、spooldir source,logger sink
spooldir source 是最常用的数据源
获取指定件夹下所有指定名称的文件;以下示例均使用文件夹作为数据源,仅修改输出方式
创建events-flume-logger.conf
events.sources=eventsSource
events.channels=eventsChannel
events.sinks=eventsSink
events.sources.eventsSource.type=spooldir
events.sources.eventsSource.spoolDir=/opt/data/flumedir/dataSourceFile/events
events.sources.eventsSource.deserializer=LINE
events.sources.eventsSource.deserializer.maxLineLength=10000
events.sources.eventsSource.includePattern=events_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
events.channels.eventsChannel.type=file
events.channels.eventsChannel.checkpointDir=/opt/data/flumedir/checkPointFile/events
events.channels.eventsChannel.dataDirs=/opt/data/flumedir/dataChannelFile/events
events.sinks.eventsSink.type=logger
events.sources.eventsSource.channels=eventsChannel
events.sinks.eventsSink.channel=eventsChannel
参数说明:
-
spooldir:指定数据源为文件夹下所有指定内容
-
sources.xxx.spoolDir:指定数据来源文件夹路径(启动 agent 前必须存在)
-
source.xxx.deserializer:指定序列化方式(LINE 表示为逐行读取)
-
source.xxx.maxLineLength:指定每行的最大字符数
-
source.xxx.includePattern:指定数据来源文件夹下文件名的类型,正则匹配
-
channels.xxx.type=file:指定通道类型为文件,即通道中的 event 落盘,保证数据安全
-
channels.xxx.checkpointDir:指定通道检查点文件夹目录(绝对路径)
-
channels.xxx.dataDirs:指定通道中数据落盘的文件夹路径(绝对路径)
启动 flume 文件命令
flume-ng agent \
-n events \
-c /opt/flume/conf/ \
-f /opt/data/flumedir/confs/events-flume-logger.conf \
-Dflume.root.logger=INFO,console
注意来源文件夹必须存在,检查点文件夹和通道落盘文件夹可以不存在,启动 flume 时会自动创建
将需要读取的文件拷贝到指定路径下即可输出到 flume 客户端;
flume 获取后的文件夹会改名,在原来名字后面加上后缀.COMPLETED
结果如下:
4.4、spooldir source,hdfs sink
从文件夹获取数据,输出方式为上传到 HDFS
创建文件userFriend-flume-hdfs.conf
user_friend.sources=userFriendSource
user_friend.channels=userFriendChannel
user_friend.sinks=userFriendSink
user_friend.sources.userFriendSource.type=spooldir
user_friend.sources.userFriendSource.spoolDir=/opt/data/flumedir/dataSourceFile/test
user_friend.sources.userFriendSource.deserializer=LINE
user_friend.sources.userFriendSource.deserializer.maxLineLength=320000
user_friend.sources.userFriendSource.includePattern=userFriend_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
user_friend.channels.userFriendChannel.type=file
user_friend.channels.userFriendChannel.checkpointDir=/opt/data/flumedir/checkPointFile/test
user_friend.channels.userFriendChannel.dataDirs=/opt/data/flumedir/dataChannelFile/test
user_friend.sinks.userFriendSink.type=hdfs
user_friend.sinks.userFriendSink.hdfs.fileType=DataStream
user_friend.sinks.userFriendSink.hdfs.filePrefix=userFriend
user_friend.sinks.userFriendSink.hdfs.fileSuffix=.csv
user_friend.sinks.userFriendSink.hdfs.path=hdfs://192.168.8.99:9000/flume/test/%Y-%m-%d
user_friend.sinks.userFriendSink.hdfs.useLocalTimeStamp=true
user_friend.sinks.userFriendSink.hdfs.batchSize=640
user_friend.sinks.userFriendSink.hdfs.rollInterval=20
user_friend.sinks.userFriendSink.hdfs.rollCount=0
user_friend.sinks.userFriendSink.hdfs.rollSize=120000000
user_friend.sources.userFriendSource.channels=userFriendChannel
user_friend.sinks.userFriendSink.channel=userFriendChannel
参数说明:
-
sink.xxx.type=hdfs:指定 sink 存储方式为 HDFS
-
sink.xxx.hdfs.fileType:指定保存到 HDFS 文件系统上的文件类型
-
sink.xxx.hdfs.filePrefix:指定保存到 HDFS 文件系统上的文件名前缀
-
sink.xxx.hdfs.fileSuffix:指定保存到 HDFS 文件系统上的文件名后缀
-
sink.xxx.hdfs.path:指定保存在 HDFS 上的路径
-
sink.xxx.hdfs.useLocalTimeStamp:是否使用本地时间戳,默认为 false 不使用
-
sink.xxx.hdfs.batchSize:批量发送事件数量(发送给 channel 的最大行数)
-
sink.xxx.hdfs.rollInterval:按时间生成 HDFS 文件
-
sink.xxx.hdfs.rollCount:按写入的 event 的个数触发 roll,生成新的 HDFS 文件
-
sink.xxx.hdfs.rollSize:按文件大小触发 roll,生成新的 HDFS 文件
启动 flume 文件命令
flume-ng agent \
-n user_friend \
-c /opt/flume/conf/ \
-f /opt/data/flumedir/confs/userFriend-flume-hdfs.conf \
-Dflume.root.logger=INFO,console
运行结果如下:
4.5、获取数据时添加拦截器过滤数据
在获取数据的同时简单过滤一些不需要的数据
创建user-flume-hdfs.conf
users.sources=userSource
users.channels=userChannel
users.sinks=userSink
users.sources.userSource.type=spooldir
users.sources.userSource.spoolDir=/opt/data/flumedir/dataSourceFile/user
users.sources.userSource.includePattern=user_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
users.sources.userSource.deserializer=LINE
users.sources.userSource.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/data/flumedir/checkPointFile/user
users.channels.userChannel.dataDirs=/opt/data/flumedir/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://hadoop:9000/flume/test/users/%Y-%m-%d
users.sinks.userSink.hdfs.useLocalTimeStamp=true
users.sinks.userSink.hdfs.batchSize=640
users.sinks.userSink.hdfs.rollCount=0
users.sinks.userSink.hdfs.rollSize=120000000
users.sinks.userSink.hdfs.rollInterval=20
users.sources.userSource.channels=userChannel
users.sinks.userSink.channel=userChannel
参数说明:
- sources.xxx.interceptors=head_filter:指定拦截器名称
- sources.xxx.interceptors.head_filter.type=regex_filter:指定拦截器类型
- sources.xxx.interceptors.head_filter.regex=^user_id*:过滤掉以 user_id 开头的行(常用于过滤第一行)
- sources.xxx.interceptors.head_filter.excludeEvents=true:正则过滤拦截(false表示过滤掉不是以 user_id 开头的行)
启动 flume 文件命令
flume-ng agent \
-n users \
-c /opt/flume/conf/ \
-f /opt/data/flumedir/confs/user-flume-hdfs.conf \
-Dflume.root.logger=INFO,console
4.6、spooldir source,KafkaSink
创建events-flume-kafka.conf
events.sources=eventsSource
events.channels=eventsChannel
events.sinks=eventsSink
events.sources.eventsSource.type=spooldir
events.sources.eventsSource.spoolDir=/opt/data/flumedir/dataSourceFile/events
events.sources.eventsSource.deserializer=LINE
events.sources.eventsSource.deserializer.maxLineLength=320000
events.sources.eventsSource.includePattern=events_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
events.sources.eventsSource.interceptors=head_filter
events.sources.eventsSource.interceptors.head_filter.type=regex_filter
events.sources.eventsSource.interceptors.head_filter.regex=^event_id*
events.sources.eventsSource.interceptors.head_filter.excludeEvents=true
events.channels.eventsChannel.type=file
events.channels.eventsChannel.checkpointDir=/opt/data/flumedir/checkPointFile/events
events.channels.eventsChannel.dataDirs=/opt/data/flumedir/dataChannelFile/events
events.sinks.eventsSink.type=org.apache.flume.sink.kafka.KafkaSink
events.sinks.eventsSink.batchSize=640
events.sinks.eventsSink.brokerList=192.168.8.99:9092
events.sinks.eventsSink.topic=events
events.sources.eventsSource.channels=eventsChannel
events.sinks.eventsSink.channel=eventsChannel
创建 Kafka Topic
kafka-topics.sh --create \
--zookeeper 192.168.8.99:2181 \
--partitions 1 \
--replication-factor 1 \
--topic events
启动 flume 文件命令
flume-ng agent \
-n events \
-c /opt/flume/conf/ \
-f /opt/data/flumedir/confs/events-flume-kafka.conf \
-Dflume.root.logger=INFO,console