在『Flume之HelloWorld的基础上』,本例完成采集目录中的文件,并将文件上传到HDFS中。
需求
采集目录中已有的文件,并存储到HDFS中。
分析
- 根据需求,采集目录中已有的文件,可使用
Spooling Directory Source
; - 由于需要存储到HDFS,需使用
HDFS Sink
; - Channel可使用基于内存的或者基于文件的,本例使用基于文件的,保证数据不丢失。
故最终组件选择如下图所示:
环境
本例各组件版本如下:
- JDK:1.8.0_202
- Hadoop:3.2.2
- Flume:1.9.0
配置
下面针对每一个组件进行说明和配置:
Spooling Directory Source
该source监控指定文件夹中的新文件,并在新文件出现时,从新文件中解析数据出来。当新文件被完全读入channel后,默认情况下会重命名文件,以表示文件读取已经完成。也可以配置读取完成后立刻删除;或者配置trackerDir
参数,通过tracker_dir
目录,来跟踪已经处理完成的文件。
本例中,source部分的配置如下:
# Describe/configure the source
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /root/jtest/flume/biz/input-file
File Channel
该Channel有两个较为重要的配置项:checkpointDir
和dataDirs
:
checkpointDir
用于存储检查点(checkpoint)文件,默认为*~/.flume/file-channel/checkpoint*dataDirs
用于指定采集的数据目录,默认为*~/.flume/file-channel/data*,在不同磁盘中使用多个目录可以提高file channel的性能
默认情况下,上面两个参数的路径均在用户home目录中。那么如果在agent中有多个file channel实例,只有一个file channel可以将目录lock,另一个file channel初始化将会失败。所以最好显示指定每一个channel的检查点目录和数据目录。
本例中,channel部分的配置如下:
# Use a channel which buffers events in memory
a1.channels.c1.type = file
a1.channels.c1.checkpointDir = /root/jtest/flume/biz/file-checkpoint
a1.channels.c1.dataDirs = /root/jtest/flume/biz/file-data
HDFS Sink
这个Sink将events写入到分布式文件系统HDFS中,目前支持创建文本文件(text files)以及Sequence files,这两种文件类型均支持压缩。写入HDFS中的文件,可根据时间、文件大小、event数量进行分割(关闭当前文件,同时新建文件)。使用HDFS Sink需要安装hadoop,flume使用hadoop中的jar包与HDFS集群进行通信。
本例中,sink部分的配置如下:
# Describe the sink
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://bukp1:9000/flume/biz
a1.sinks.k1.hdfs.filePrefix = biz-
# 此处使用DataStream便于查看数据
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.writeFormat = Text
# 以下指定文件分割策略,一小时或者文件大小达到128M
a1.sinks.k1.hdfs.rollInterval = 3600
a1.sinks.k1.hdfs.rollSize = 134217728
a1.sinks.k1.hdfs.rollCount = 0
其中:
hdfs.path
:文件件在HDFS中的存储路径;hdfs.filePrefix
:指定文件存储在HDFS中,添加的文件前缀;hdfs.fileType
和hdfs.writeFormat
指定文件类型和写入格式,本例中为了方便数据查看,分别设置为DataStream
和Text
则将以文本文件形式存储数据;hdfs.rollInterval
、hdfs.rollSize
、hdfs.rollCount
用于指定文件分割策略,当参数都有配置的情况下,最先符合的策略则先执行。在本例中,每一小时(rollInterval=3600)或文件大小达到128M(rollSize=134217728)时,将会进行文件分割。
完整配置
本例的完整配置如下:
# file-to-hdfs.conf:
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /root/jtest/flume/biz/input-file
# Use a channel which buffers events in memory
a1.channels.c1.type = file
a1.channels.c1.checkpointDir = /root/jtest/flume/biz/file-checkpoint
a1.channels.c1.dataDirs = /root/jtest/flume/biz/file-data
# Describe the sink
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://bukp1:9000/flume/bizDir
a1.sinks.k1.hdfs.filePrefix = biz-
# 此处使用DataStream便于查看数据
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.writeFormat = Text
# 以下指定文件分割策略,一小时或者文件大小达到128M
a1.sinks.k1.hdfs.rollInterval = 3600
a1.sinks.k1.hdfs.rollSize = 134217728
a1.sinks.k1.hdfs.rollCount = 0
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
启动
分别启动HDFS集群和Flume进程。
注意:由于需操作HDFS集群,所以Flume进程节点亦需要成为hadoop的客户端节点。成为客户端节点很简单,只需要把集群中hadoop整个目录拷贝到Flume节点即可。
启动Flume:
# bin/flume-ng agent --conf conf --conf-file conf/file-to-hdfs.conf --name a1 -Dflume.root.logger=INFO,console
部分控制台输出如下:
--- 此处省略若干行 ---
2022-01-20 17:17:59,236 (conf-file-poller-0) [INFO - org.apache.flume.node.Application.startAllComponents(Application.java:207)] Starting Source r1
2022-01-20 17:17:59,237 (lifecycleSupervisor-1-0) [INFO - org.apache.flume.source.SpoolDirectorySource.start(SpoolDirectorySource.java:85)] SpoolDirectorySource source starting with directory: /root/jtest/flume/biz/input-file
2022-01-20 17:17:59,245 (lifecycleSupervisor-1-0) [INFO - org.apache.flume.instrumentation.MonitoredCounterGroup.register(MonitoredCounterGroup.java:119)] Monitored counter group for type: SOURCE, name: r1: Successfully registered new MBean.
2022-01-20 17:17:59,245 (lifecycleSupervisor-1-0) [INFO - org.apache.flume.instrumentation.MonitoredCounterGroup.start(MonitoredCounterGroup.java:95)] Component type: SOURCE, name: r1 started
由此可以看到,Source已经开始对目录*/root/jtest/flume/biz/input-file*进行监控。
have a try
接下来,我们将做若干尝试,并且修改一些配置项,观察不同的效果:
在被监控目录中,放入新文件
在/root/jtest/flume/biz/input-file目录中,放入如下图所示的文本文件:
出错!guava包冲突
但是,出现了如下错误:
2022-01-20 17:48:14,565 (SinkRunner-PollingRunner-DefaultSinkProcessor) [ERROR - org.apache.flume.sink.hdfs.HDFSEventSink.process(HDFSEventSink.java:459)] process failed
java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;Ljava/lang/Object;)V
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1357)
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1338)
at org.apache.hadoop.conf.Configuration.setBoolean(Configuration.java:1679)
at org.apache.flume.sink.hdfs.BucketWriter.open(BucketWriter.java:221)
at org.apache.flume.sink.hdfs.BucketWriter.append(BucketWriter.java:572)
at org.apache.flume.sink.hdfs.HDFSEventSink.process(HDFSEventSink.java:412)
at org.apache.flume.sink.DefaultSinkProcessor.process(DefaultSinkProcessor.java:67)
at org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:145)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "SinkRunner-PollingRunner-DefaultSinkProcessor" java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;Ljava/lang/Object;)V
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1357)
at org.apache.hadoop.conf.Configuration.set(Configuration.java:1338)
at org.apache.hadoop.conf.Configuration.setBoolean(Configuration.java:1679)
at org.apache.flume.sink.hdfs.BucketWriter.open(BucketWriter.java:221)
at org.apache.flume.sink.hdfs.BucketWriter.append(BucketWriter.java:572)
at org.apache.flume.sink.hdfs.HDFSEventSink.process(HDFSEventSink.java:412)
at org.apache.flume.sink.DefaultSinkProcessor.process(DefaultSinkProcessor.java:67)
at org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:145)
at java.lang.Thread.run(Thread.java:748)
该错误原因,是因为guava版本冲突导致,在hadoop中使用的版本为guava-27.0:
hadoop-3.2.2/share/hadoop/common/lib/guava-27.0-jre.jar
而Flume中,使用的版本为guava-11.0.2:
flume-1.9.0/lib/guava-11.0.2.jar
解决办法为:删除掉flume中的guava包,并重启Flume,重启后观察控制台输出:
2022-01-20 17:58:49,275 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.hdfs.HDFSDataStream.configure(HDFSDataStream.java:57)] Serializer = TEXT, UseRawLocalFileSystem = false
2022-01-20 17:58:49,362 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.hdfs.BucketWriter.open(BucketWriter.java:246)] Creating hdfs://bukp1:9000/flume/bizDir/biz-.1642672729275.tmp
2022-01-20 17:59:18,798 (Log-BackgroundWorker-c1) [INFO - org.apache.flume.channel.file.EventQueueBackingStoreFile.beginCheckpoint(EventQueueBackingStoreFile.java:230)] Start checkpoint for /root/jtest/flume/biz/file-checkpoint/checkpoint, elements to sync = 30
2022-01-20 17:59:18,802 (Log-BackgroundWorker-c1) [INFO - org.apache.flume.channel.file.EventQueueBackingStoreFile.checkpoint(EventQueueBackingStoreFile.java:255)] Updating checkpoint metadata: logWriteOrderID: 1642672728850, queueSize: 0, queueHead: 28
2022-01-20 17:59:18,805 (Log-BackgroundWorker-c1) [INFO - org.apache.flume.channel.file.Log.writeCheckpoint(Log.java:1065)] Updated checkpoint for file: /root/jtest/flume/biz/file-data/log-2 position: 1266 logWriteOrderID: 1642672728850
查看运行效果
可以看到,Flume已经读取了文件内容,并写入到HDFS。查看HDFS中文件:
[root@bukp4 input-file]# hdfs dfs -ls /flume/bizDir
Found 1 items
-rw-r--r-- 2 root supergroup 3870 2022-01-20 17:58 /flume/bizDir/biz-.1642672729275.tmp
可以看到,HDFS相应目录中已存在文件biz-.1642672729275.tmp,并且前缀即为先前的配置项hdfs.filePrefix=biz
。继续查看这个tmp文件:
[root@bukp4 input-file]# hdfs dfs -cat /flume/bizDir/biz-.1642672729275.tmp
Introduction
Overview
Apache Flume is a distributed, reliable, and available system for efficiently collecting, aggregating and moving large amounts of log data from many different sources to a centralized data store.
The use of Apache Flume is not only restricted to log data aggregation. Since data sources are customizable, Flume can be used to transport massive quantities of event data including but not limited to network traffic data, social-media-generated data, email messages and pretty much any data source possible.
--- 此处省略若干
可以看到,文件内容已经写入到HDFS文件中。
再一次拷贝一个新文件到Flume的监控目录,最终可以看到在HDFS路径中,仍然只有biz-.1642672729275.tmp这个文件,但监控目录中新文件的内容,已经被追加到HDFS中biz-.1642672729275.tmp文件尾部。
修改source
配置,再看看现象
可以注意到,在被监控的目录中已经被处理完毕的文件会被加上了*.COMPLETED*后缀:
[root@bukp4 input-file]# ll
total 8
-rw-r--r--. 1 root root 3870 Jan 20 17:48 test-text-1.dat.COMPLETED
-rw-r--r--. 1 root root 747 Jan 20 18:23 test-text-2.dat.COMPLETED
这跟Spooling Directory Source
的跟踪策略和删除策略有关,相应的配置项为:
- deletePolicy
删除策略,用于配置在什么时候删除已经处理完毕的文件。可选配置包括:never
、immediate
;默认值为never
,即永不删除; - fileSuffix
给已处理完毕的文件,添加的文件后缀。默认值即为.COMPLETED
; - trackingPolicy
跟踪策略,用于配置如何跟踪文件的处理过程,与deletePolicy
配合使用,并且仅当deletePolicy
设置为never
时才会生效。该参数可选配置包括rename
和tracker_dir
:- rename:文件处理完毕后文件被重命名,在文件名末尾添加一个后缀,这个后缀通过
fileSuffix
参数指定。 - tracker_dir:文件处理完毕后不会被重命名,但会在参数
trackerDir
指定的目录中生成一个空文件,文件名为原始文件名+fileSuffix
- rename:文件处理完毕后文件被重命名,在文件名末尾添加一个后缀,这个后缀通过
- trackerDir
当跟踪策略为tracker_dir
时,该参数指定用于存储相关处理过程元数据的目录。默认为*.flumespool*。该参数可配置为相对路径或者绝对路径,当配置为相对路径时,则为相对于spoolDir
参数所指定的目录。
接下来,将调整上面几个参数,验证不同参数组合下的实际效果。
一、文件处理完毕后立即删除
将deletePolicy
设置为immediate
,配置文件source部分修改如下:
# Describe/configure the source
a1.sources.r1.type = spooldir
a1.sources.r1.deletePolicy = immediate
a1.sources.r1.spoolDir = /root/jtest/flume/biz/input-file
启动后,拷贝新的文件到spoolDir中,文件自动消失了!查看HDFS,可以看到刚才的文件内容已经被写入了HDFS相应文件中。
二、trackingPolicy策略使用tracker_dir
将deletePolicy
设置为never
,配置文件source部分修改如下:
# Describe/configure the source
a1.sources.r1.type = spooldir
a1.sources.r1.deletePolicy = never
a1.sources.r1.spoolDir = /root/jtest/flume/biz/input-file
a1.sources.r1.trackerDir = flumespool
a1.sources.r1.trackingPolicy = tracker_dir
此处,trackerDir
使用了相对路径,则会在*/root/jtest/flume/biz/input-file*中新建该目录,重新启动后可以观察到,该目录被建立:
[root@bukp4 input-file]# ll
total 12
drwxr-xr-x. 2 root root 4096 Jan 21 14:43 flumespool
-rw-r--r--. 1 root root 3870 Jan 20 17:48 test-text-1.dat.COMPLETED
-rw-r--r--. 1 root root 747 Jan 20 18:23 test-text-2.dat.COMPLETED
拷贝新文件到spoolDir
中,当文件处理完后可以观察到,在flumespool目录中出现了如下文件:
[root@bukp4 flumespool]# ll
total 0
-rw-r--r--. 1 root root 0 Jan 21 15:09 test-text-3.dat.COMPLETED
而spoolDir
中,文件名称不会改变:
[root@bukp4 input-file]# ll
total 16
drwxr-xr-x. 2 root root 4096 Jan 21 15:09 flumespool
-rw-r--r--. 1 root root 3870 Jan 20 17:48 test-text-1.dat.COMPLETED
-rw-r--r--. 1 root root 747 Jan 20 18:23 test-text-2.dat.COMPLETED
-rw-r--r--. 1 root root 3870 Jan 21 15:07 test-text-3.dat
以上,该案例实验完毕。