Flume 是 Cloudera 提供的日志收集系统,具有分布式、高可靠、高可用性等特点,对海量日志采集、聚合和传输,Flume 支持在日志系统中定制各类数据发送方,同时,Flume提供对数据进行简单处理,并写到各种数据接受方的能力。
Flume 使用 java 编写,其需要运行在 Java1.6 或更高版本之上。
Flume 的核心是把数据从数据源收集过来,再送到目的地。为了保证输送一定成功,在送到目的地之前,会先缓存数据,待数据真正到达目的地后,删除自己缓存的数据。
Flume 传输的数据的基本单位是 Event,如果是文本文件,通常是一行记录,这也是事务的基本单位。Event 从 Source,流向 Channel,再到 Sink,本身为一个 byte 数组,并可携带 headers 信息。Event 代表着一个数据流的最小完整单元,从外部数据源来,向外部的目的地去。
Flume 运行的核心是 Agent。它是一个完整的数据收集工具,含有三个核心组件,分别是 source、channel、sink。通过这些组件,Event 可以从一个地方流向另一个地方,如下图所示。
flume 允许多个 agent 连在一起,形成前后相连的多级跳。
Client端操作消费数据的来源,Flume 支持 Avro,log4j,syslog 和 http post(body为json格式)。可以让应用程序同已有的Source直接打交道,如AvroSource,SyslogTcpSource。也可以 写一个 Source,以 IPC 或 RPC 的方式接入自己的应用,Avro和 Thrift 都可以(分别有 NettyAvroRpcClient 和 ThriftRpcClient 实现了 RpcClient接口),其中 Avro 是默认的 RPC 协议。具体代码级别的 Client 端数据接入,可以参考官方手册。
对现有程序改动最小的使用方式是使用是直接读取程序原来记录的日志文件,基本可以实现无缝接入,不需要对现有程序进行任何改动。
对于直接读取文件 Source,有两种方式:
tail -F 文件名
指令,在这种方式下,取的文件名必须是指定的。 ExecSource 可以实现对日志的实时收集,但是存在Flume不运行或者指令执行出错时,将无法收集到日志数据,无法保证日志数据的完整性。SpoolSource 虽然无法实现实时的收集数据,但是可以使用以分钟的方式分割文件,趋近于实时。
如果应用无法实现以分钟切割日志文件的话, 可以两种收集方式结合使用。 在实际使用的过程中,可以结合 log4j 使用,使用 log4j的时候,将 log4j 的文件分割机制设为1分钟一次,将文件拷贝到spool的监控目录。
log4j 有一个 TimeRolling 的插件,可以把 log4j 分割文件到 spool 目录。基本实现了实时的监控。Flume 在传完文件之后,将会修改文件的后缀,变为 .COMPLETED(后缀也可以在配置文件中灵活指定)
当前有几个 channel 可供选择,分别是 Memory Channel, JDBC Channel , File Channel,Psuedo Transaction Channel。比较常见的是前三种 channel。
File Channel 是一个持久化的隧道(channel),它持久化所有的事件,并将其存储到磁盘中。因此,即使 Java 虚拟机当掉,或者操作系统崩溃或重启,再或者事件没有在管道中成功地传递到下一个代理(agent),这一切都不会造成数据丢失。Memory Channel 是一个不稳定的隧道,其原因是由于它在内存中存储所有事件。如果 java 进程死掉,任何存储在内存的事件将会丢失。另外,内存的空间收到 RAM大小的限制,而 File Channel 这方面是它的优势,只要磁盘空间足够,它就可以将所有事件数据存储到磁盘上。
Sink在设置存储数据时,可以向文件系统、数据库、hadoop存数据,在日志数据较少时,可以将数据存储在文件系中,并且设定一定的时间间隔保存数据。在日志数据较多时,可以将相应的日志数据存储到Hadoop中,便于日后进行相应的数据分析.
更多sink的内容可以参考官方手册。
Flume 的核心是把数据从数据源收集过来,再送到目的地。为了保证输送一定成功,在送到目的地之前,会先缓存数据,待数据真正到达目的地后,删除自己缓存的数据。
Flume 使用事务性的方式保证传送Event整个过程的可靠性。Sink 必须在 Event 被存入 Channel 后,或者,已经被传达到下一站agent里,又或者,已经被存入外部数据目的地之后,才能把 Event 从 Channel 中 remove 掉。这样数据流里的 event 无论是在一个 agent 里还是多个 agent 之间流转,都能保证可靠,因为以上的事务保证了 event 会被成功存储起来。而 Channel 的多种实现在可恢复性上有不同的保证。也保证了 event 不同程度的可靠性。比如 Flume 支持在本地保存一份文件 channel 作为备份,而memory channel 将 event 存在内存 queue 里,速度快,但丢失的话无法恢复。
Flume 的 rpm 安装方式很简单,这里不做说明。
安装成功之后,在 /etc/flume/conf 目录创建f1.conf 文件,内容如下:
agent-1.channels.ch-1.type = memory
agent-1.sources.avro-source1.channels = ch-1
agent-1.sources.avro-source1.type = avro
agent-1.sources.avro-source1.bind = 0.0.0.0
agent-1.sources.avro-source1.port = 41414
agent-1.sources.avro-source1.threads = 5
agent-1.sinks.log-sink1.channel = ch-1
agent-1.sinks.log-sink1.type = logger
agent-1.channels = ch-1
agent-1.sources = avro-source1
agent-1.sinks = log-sink1
关于 avro-source 配置说明,请参考 avro-source
接下来启动 agent:
$ flume-ng agent -c /etc/flume-ng/conf -f /etc/flume-ng/conf/f1.conf -Dflume.root.logger=DEBUG,console -n agent-1
参数说明:
-n
指定agent名称-c
指定配置文件目录-f
指定配置文件-Dflume.root.logger=DEBUG,console
设置日志等级下面可以启动一个 avro-client 客户端生产数据:
$ flume-ng avro-client -c /etc/flume-ng/conf -H localhost -p 41414 -F /etc/passwd -Dflume.root.logger=DEBUG,console
在 /etc/flume/conf 目录创建 f2.conf 文件,内容如下:
agent-1.channels = ch-1
agent-1.sources = src-1
agent-1.channels.ch-1.type = memory
agent-1.sources.src-1.type = spooldir
agent-1.sources.src-1.channels = ch-1
agent-1.sources.src-1.spoolDir = /root/log
agent-1.sources.src-1.fileHeader = true
agent-1.sinks.log-sink1.channel = ch-1
agent-1.sinks.log-sink1.type = logger
agent-1.sinks = log-sink1
关于 Spooling Directory Source 配置说明,请参考 Spooling Directory Source
接下来启动 agent:
$ flume-ng agent -c /etc/flume-ng/conf -f /etc/flume-ng/conf/f2.conf -Dflume.root.logger=DEBUG,console -n agent-1
然后,手动拷贝一个文件到 /root/log 目录,观察日志输出以及/root/log 目录下的变化。
在 /etc/flume/conf 目录创建 f3.conf 文件,内容如下:
agent-1.channels.ch-1.type = file
agent-1.channels.ch-1.checkpointDir= /root/checkpoint
agent-1.channels.ch-1.dataDirs= /root/data
agent-1.sources.src-1.type = spooldir
agent-1.sources.src-1.channels = ch-1
agent-1.sources.src-1.spoolDir = /root/log
agent-1.sources.src-1.deletePolicy= never
agent-1.sources.src-1.fileHeader = true
agent-1.sources.src-1.interceptors =i1
agent-1.sources.src-1.interceptors.i1.type = timestamp
agent-1.sinks.sink_hdfs.channel = ch-1
agent-1.sinks.sink_hdfs.type = hdfs
agent-1.sinks.sink_hdfs.hdfs.path = hdfs://cdh1:8020/user/root/events/%Y-%m-%d
agent-1.sinks.sink_hdfs.hdfs.filePrefix = logs
agent-1.sinks.sink_hdfs.hdfs.inUsePrefix = .
agent-1.sinks.sink_hdfs.hdfs.rollInterval = 30
agent-1.sinks.sink_hdfs.hdfs.rollSize = 0
agent-1.sinks.sink_hdfs.hdfs.rollCount = 0
agent-1.sinks.sink_hdfs.hdfs.batchSize = 1000
agent-1.sinks.sink_hdfs.hdfs.writeFormat = text
agent-1.sinks.sink_hdfs.hdfs.fileType = DataStream
#agent-1.sinks.sink_hdfs.hdfs.fileType = CompressedStream
#agent-1.sinks.sink_hdfs.hdfs.codeC = lzop
agent-1.channels = ch-1
agent-1.sources = src-1
agent-1.sinks = sink_hdfs
关于 HDFS Sink配置说明,请参考 HDFS Sink
说明:
hdfs.inUsePrefix
,例如设置为 .
时,hdfs 会把该文件当做隐藏文件,以避免在 mr 过程中读到这些临时文件,引起一些错误关于 HBase Sink 配置说明,请参考 HBase Sink
从 github 下载源代码并编译:
$ git clone [email protected]:cloudera/flume-ng.git -b cdh4-1.4.0_4.7.0
$ cd flume-ng
$ mvn install -DskipTests -Phadoop-2
如果提示找不到 hadoop-test 的 jar 包,则修改 pom.xml 中的版本,如改为 2.0.0-mr1-cdh4.7.0
,具体版本视你使用的分支版本而定,我这里是 cdh4.7.0。
如果提示找不到 uanodeset-parser 的 jarb,则在 pom.xml 中添加下面仓库:
<repository>
<id>tempo-dbid>
<url>http://maven.tempo-db.com/artifactory/list/twitter/
url>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
参考基于Flume的美团日志收集系统(一)架构和设计,列出一些最佳实践:
美团对 flume 的改进代码见 github:https://github.com/dashengju/mt-flume