「大数据」win环境下的Flume日志采集初级实验

3,265 阅读14分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

2022最后一天🐾, 预祝大家元旦快乐,有多少小伙伴在b站跨年鸭~🎉


Flume日志采集

1.前言

相关技术介绍

Apache Flume 是一个分布式、高可靠、高可用的用来收集、聚合、转移不同来源的大量日志数据到中央数据仓库的工具

Apache Flume是Apache软件基金会(ASF)的顶级项目

目前有两个发行版本,0.9.x和1.x。

相关文档:

系统要求

  • Java运行环境 - Java 1.8或更高版本
  • 内存 - 足够的内存 用来配置Souuces、Channels和Sinks
  • 硬盘空间 - 足够的硬盘用来配置Channels 和 Sinks
  • 目录权限 - Agent用来读写目录的权限
Flume版本依赖的JRE版本
Flume 1.8.0+Java1.8 或更高版本
Flume 1.7.0Java1.7 或更高版本
Flume 1.4.0、1.5.0、1.5.2、1.6.0Java1.6 或更高版本(建议使用1.7)

简介

Event是Flume定义的一个数据流传输的最小单元。Flume以Agent为最小的独立运行单位,Agent就是一个Flume的实例,本质是一个JVM ( Java Virtual Machine),该JVM进程控制Event数据流从外部日志生产者那里传输到目的地(或者是下一个Agent)。

它是一个完整的数据采集工具,包含三个核心组件,分别是数据源(Source-数据的来源和方式) 、数据通道(Channel-数据的缓冲池)和数据槽(Sink-定义了数据输出的方式和目的地) 。

通过这些组件,“事件” 可以从一个地方流向另一个地方。

Source消耗由外部(如Web服务器)传递给它的Event。外部以Flume Source识别的格式向Flume发送Event。例如,Avro Flume Source可接收从Avro客户端(或其他FlumeSink)接收Avro Event。用Thrift Flume Source也可以实现类似的流程,接收的Event数据可以是任何语言编写的只要符合Thrift协议即可。

当Source接收Event时,它将其存储到一个或多个channel。该channel是一个被动存储器,可以保持Event直到它被Sink消耗。『文件channel』就是一个例子 - 它由本地文件系统支持。sink从channel中移除Event并将其放入外部存储库(如HDFS,通过 Flume的 HDFS Sink 实现)或将其转发到流中下一个Flume Agent(下一跳)的Flume Source。

Agent中的source和sink与channel存取Event是异步的。

Flume的Source负责消费外部传递给它的数据(比如web服务器的日志)。外部的数据生产方以Flume Source识别的格式向Flume发送Event。

Source、Channel、Sink组件

三个重要组件的具体功能如下 :

(1)数据源(Source) 是数据的收集端,负责将数据捕获后进行特殊的格式化,将数

据封装到事件(Event) 里,然后将事件推入数据通道中。

常用的数据源的类型包括Avro、Thrift、 Exec、 JMS、Spooling Directory、 Taildir、 Kafka、NetCat、Syslog、 HTTP等。

(2)数据通道(Channel) 是连接数据源和数据槽的组件,可以将它看作一个数据的缓冲区(数据队列),它可以将事件暂存到内存中,也可以持久化到本地磁盘上,直到数据槽处理完该事件。

常用的数据通道类型包括Memory、JDBC、Kafka、File、 Custom等。

(3)数据槽取(Sink) 出数据通道中的数据,存储到文件系统和数据库,或者提交到远程服务器。

常用的数据槽包括HDFS、Hive、Logger、 Avro、Thrift、IRC、File Roll、HBase、ElasticSearch、 Kafka、 HTTP等。

复杂流

Flume可以设置多级Agent连接的方式传输Event数据。也支持扇入(多对一)和扇出(一对多)的部署方式。也就是说Agent可以将数据流发到多个下级Agent,也可以从多个Agent发到一个Agent中。

下图为前三个Agent的数据都汇总到一个Agent4上,最后由Agent4统一存储到HDFS的例子:

image.png

Flume提供了大量内置的数据源、数据通道和数据槽类型。不同类型的数据源、数据通道和数据槽可以自由组合。

组合方式基于用户设置的配置文件,非常灵活。比如,数据通道可以把事件暂存在内存里,也可以持久化到本地硬盘上;数据槽可以把日志写入HDFS、HBase甚至是另外一个数据源等等。


2.环境准备

以下实验的操作系统为Win10 / Win11.

hadoop集群的启动

1.Java环境

确保cmd模式下输入java -version有反应。(JDK1.8.0+即可)

建议装1.8的即可,版本太高容易出奇怪的问题...(别问,问就是卸载重装很多次了

2.Hadoop安装

下载hadoop-3.1.3压缩包并解压至任意目录下,并将winutils中的bin目录替换掉hadoop下的bin目录。

然后在"E:\SoftWare\hadoop-3.1.3"(自己的解压目录)下新建tmp目录,并在tmp目录下新建两个子目录datanodenamenode。安装完成之后不要忘记编辑环境变量。

环境变量配置: 我的电脑->属性->高级系统变量->环境变量->系统变量

新建一个"HADOOP_HOME"变量,设置值为"E:\SoftWare\hadoop-3.1.3"。然后在用户变量Path中添加%HADOOP_HOME%\bin

打开cmd输入hadoop version,返回版本信息即配置无误。

3.修改配置文件

\hadopop-3.1.3\etc\hadoop下的core-site.xml文件配置改为

<configuration>
  <property>
    <name>fs.default.name</name>
    <value>hdfs://localhost:9000</value>
  </property>
</configuration>

不用多说了,上述配置的就是hdfs网页端的路径。

hdfs-site.xml配置改为

<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
  <property>
    <name>dfs.permissions</name>
    <value>false</value>
  </property>
  <property>
    <name>dfs.namenode.name.dir</name>
    <value>/E:\SoftWare\hadoop-3.1.3\tmp\namenode</value>
  </property>
  <property>
    <name>dfs.datanode.data.dir</name>
    <value>/E:\SoftWare\hadoop-3.1.3\tmp\datanode</value>
  </property>
</configuration>

dfs.replication配置的为从结点的个数,这里设置为1,即表示搭建的是伪分布式集群环境。即在一台机器上启动所有的结点。

在Win系统中配置DataNode和Namenode的路径需要在最前面加上/

修改hadoop-env.cmd

右键,点击编辑hadoop-env.cmd文件即可。

找到JAVA_HOME将java的路径修改为JDK的绝对路径,如我的E:\SoftWare\Java

需要注意的是,如果路径之中包含了空格,需要将有空格部分分以""包括起来,或者使用PROGRA~1代替。

C:\Program Files\Java需要改为"C:\Program Files"\Java或者C:\PROGRA~1\Java

4.启动hadoop集群

新建一个cmd窗口,在hadoop\bin目录下输入hdfs namenode -format完成namenode的初始化配置。

看到namenode has been successfully formatted,就代表成功。

再在hadoop\sbin目录下执行start-dfs.cmd,执行完该命令之后就会出现两个cmd窗口(分别是namenode和datanode),然后在原来的窗口中输入jps查看java进程,如果看到了DataNode和NameNode就说明hadoop启动成功

sbin目录下执行stop-dfs.cmd可关闭hadoop。

Flume的安装

解压apache-flume-1.9.0-bin.tar.gz之后直接到flume\bin目录下使用flume-ng version测试flume是否能成功启动。如果出现报错,只需要将报错对应行的注释掉即可。

bin目录下的flume-ng是Flume的启动脚本,启动时需要指定Agent的名字、配置文件的目录和配置文件的名称。

比如图中框起来的部分:

虽然注释掉之后启动的时候会显示 not found,但是并不影响。(好像暂时用不到hbase和hive)

然后需要在 控制面板->程序 -> 程序和功能->打开或关闭windows功能。把Telnet客户端打开。

新建一个cmd窗口,输入telnet --help测试telnet命令是否可以使用。


3.实验

Hello World

Flume Agent的配置是在一个本地的配置文件中。这是一个遵循Java properties文件格式的文本文件。一个或多个Agent配置可放在同一个配置文件里。配置文件包含Agent的source,sink和channel的各个属性以及他们的数据流连接。

Agent需要知道加载什么组件,以及这些组件在流中的连接顺序。通过列出在Agent中的source,sink和channel名称,定义每个sink和source的channel来完成。

flume\conf目录新建一个example.conf配置文件。

下面的配置文件中,source使用的是 NetCat TCP Source, 简单说就是监听本机上某个端口上接收到的TCP协议的消息,收到的每行内容都会解析封装成一个Event,然后发送到channel;sink使用的是 Logger Sink,这个sink可以把Event输出到控制台;channel使用的是Memory Channel,是一个用内存作为Event缓冲的channel。

文件内容如下:

# example.conf: 一个单节点的 Flume 实例配置
 
# 配置Agent a1各个组件的名称
a1.sources = r1 #Agent a1 的source有一个,叫做r1
a1.sinks = k1 #Agent a1 的sink也有一个,叫做k1
a1.channels = c1 #Agent a1 的channel有一个,叫做c1
 
# 配置Agent a1的source r1的属性
a1.sources.r1.type = netcat #使用的是NetCat TCP Source,这个的是别名,Flume内置的一些组件都是有别名的,没有别名填全限定类名
a1.sources.r1.bind = localhost #NetCat TCP Source监听的hostname,这个是本机
a1.sources.r1.port = 44444 #监听的端口
 
# 配置Agent a1的sink k1的属性
a1.sinks.k1.type = logger # sink使用的是Logger Sink,这个配的也是别名
 
# 配置Agent a1的channel c1的属性,channel是用来缓冲Event数据的
a1.channels.c1.type = memory #channel的类型是内存channel,顾名思义这个channel是使用内存来缓冲数据
a1.channels.c1.capacity = 1000  # 通道中最大可存储的数量 1000个event
a1.channels.c1.transactionCapacity = 100 # 每次最大可以从source中拿到或送到sink的event数量
 
# 把source和sink绑定到channel上
a1.sources.r1.channels = c1 #与source r1绑定的channel有一个,叫做c1
a1.sinks.k1.channel = c1 #与sink k1绑定的channel有一个,叫做c1

上述配置文件定义了一个Agent叫做a1,a1有一个source监听本机44444端口上接收到的数据、一个缓冲数据的channel还有一个把Event数据输出到控制台的sink。这个配置文件给各个组件命名,并且设置了它们的类型和其他属性。通常一个配置文件里面可能有多个Agent,当启动Flume时候通常会传一个Agent名字来做为程序运行的标记。

新建一个cmd窗口,在\flume\bin目录下执行:

flume-ng agent -conf ../conf -conf-file ../conf/example.conf -name a1 -property "flume.root.logger=INFO,console"

-name a1就是配置文件中的a1, 这个例子里面,我们强制Flume把日志输出到了控制台,运行的时候没有任何自定义的环境脚本。

测试一下我们的这个例子吧,

再新建一个cmd并执行telnet localhost 44444,这时候在可以在窗口中输入一些单词,比如hello等,在切换到flume启动窗口,就可以看到屏幕上显示了hello,说明flume成功接收到了信息。

恭喜你!到此你已经是个成熟的Flume Agent了(bushi

监控文件

可以随意新建一个mylogs,在flume的conf子目录下,新建example1.conf,文件内容如下:

# 设置agent上的各个组件名称
a1.sources = r1
a1.sinks = k1
a1.channels = c1

# 配置source -- 数据入口
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = E:/mylogs/

# 配置sink -- 数据出口
a1.sinks.k1.type = logger

#配置channels -- 内存管道
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

# 把source和sink绑定到channel上
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

新建一个cmd窗口,在\flume\bin目录下执行:

flume-ng agent -conf ../conf -conf-file ../conf/example1.conf -name a1 -property "flume.root.logger=INFO,console"

然后新建一个hello.txt文件里面输入一些内容,并把该文件复制到mylogs目录下,可以看到hello.txt很快就会变成hellp.txt.COMPLETED,这时,可以在flume窗口中可以看到txt文件中的内容。

采集目录到HDFS

采集需求是某服务器的某特定条件下,会不断产生新的文件,每当有新文件出现,就需要要把 文件采集到hdfs里面去。

Source:因为需要监控文件目录,所以其类型为spooldir.

Sink:因为要把文件采集到hdfs中, 所以其类型为hdfs

Channel:channel的类型可设置为memory。

在flume的conf子目录下,新建spooldir_hdfs.conf,文件内容如下:

# 设置agent上的各个组件名称
a1.sources = source1
a1.sinks = sink1
a1.channels = channel1

# 配置source -- 数据入口
a1.sources.source1.type = spooldir
a1.sources.source1.spoolDir = E:/mylogs/
a1.sources.source1.fileHeader = false

# 配置sink -- 数据出口
a1.sinks.sink1.type = hdfs
a1.sinks.sink1.hdfs.path = hdfs://localhost:9000/weblog/%y-%m-%d%H-%M
a1.sinks.sink1.hdfs.filePrefix = access_log
a1.sinks.sink1.hdfs.maxOpenFiles = 5000
a1.sinks.sink1.hdfs.batchSize = 100
a1.sinks.sink1.hdfs.fileType = DataStream
a1.sinks.sink1.hdfs.writeFormat = Text
a1.sinks.sink1.hdfs.rollSize = 102400
a1.sinks.sink1.hdfs.rollCount = 1000000
a1.sinks.sink1.hdfs.rollInterval = 60
#a1.sinks.sink1.hdfs.round = true
#a1.sinks.sink1.hdfs.roundValue = 10
#a1.sinks.sink1.hdfs.roundUnit = minute
a1.sinks.sink1.hdfs.useLocalTimeStamp = true

#配置channels -- 内存管道
a1.channels.channel1.type = memory
a1.channels.channel1.keep-alive = 120
a1.channels.channel1.capacity = 500000
a1.channels.channel1.transactionCapacity = 600

# 把source和sink绑定到channel上
a1.sources.source1.channels = channel1
a1.sinks.sink1.channel = channel1

新建一个cmd窗口,先启动hadoop的hdfs。

\hadoop\sbin下执行start-dfs.cmd,使用jps查看datanode和namenode是否启动成功。

再新建cmd窗口,在\flume\bin目录下执行:

flume-ng agent -conf ../conf -conf-file ../conf/spooldir_hdfs.conf -name a1 -property "flume.root.logger=INFO,console"

执行上述命令之后,flume就开始实时监控mylogs目录下的文件,只要这个目录下游新的文件生成,就会被flume捕捉到,并把文件内容保存到HDFS。

随便拖一个txt到mylogs目录,过一会儿,打开http://localhost:9870就可以看到生成的文件以及内容。

然后新建一个hello.txt文件里面输入一些内容,并把该文件复制到mylogs目录下,可以看到hello.txt很快就会变成hellp.txt.COMPLETED,这时,可以在flume窗口中可以看到txt文件中的内容。

image.png

实时采集 - exec

如果采集需求时服务器的某特定目录下的文件,比如WorkSpace\hello.txt文件,该文件会不断发生更新,每当文件被更新时,就需要把更新的数据采集到hdfs中去。

根据需求首先定义三大要素:

Source:因为需要监控文件目录,所以其类型为exec.

Sink:因为要把文件采集到hdfs中, 所以其类型为hdfs

Channel:channel的类型可设置为memory。

在flume的conf子目录下,新建exec_hdfs.conf,文件内容如下:

# 设置agent上的各个组件名称
a1.sources = source1
a1.sinks = sink1
a1.channels = channel1

# 配置source -- 数据入口
a1.sources.source1.type = exec
a1.sources.source1.command = tail -F E:/WorkSpace/hello.txt
a1.sources.source1.channels = channel1

# 配置sink -- 数据出口
a1.sinks.sink1.type = hdfs
a1.sinks.sink1.hdfs.path = hdfs://localhost:9000/weblog/%y-%m-%d%H-%M
a1.sinks.sink1.hdfs.filePrefix = access_log
a1.sinks.sink1.hdfs.maxOpenFiles = 5000
a1.sinks.sink1.hdfs.batchSize = 100
a1.sinks.sink1.hdfs.fileType = DataStream
a1.sinks.sink1.hdfs.writeFormat = Text
a1.sinks.sink1.hdfs.rollSize = 102400
a1.sinks.sink1.hdfs.rollCount = 1000000
a1.sinks.sink1.hdfs.rollInterval = 60
#a1.sinks.sink1.hdfs.round = true
#a1.sinks.sink1.hdfs.roundValue = 10
#a1.sinks.sink1.hdfs.roundUnit = minute
a1.sinks.sink1.hdfs.useLocalTimeStamp = true

#配置channels -- 内存管道
a1.channels.channel1.type = memory
a1.channels.channel1.keep-alive = 120
a1.channels.channel1.capacity = 500000
a1.channels.channel1.transactionCapacity = 600

# 把source和sink绑定到channel上
a1.sources.source1.channels = channel1
a1.sinks.sink1.channel = channel1

Exec:基于命令行标准输出来产生数据的数据源接收器

上述文件中的a1.sources.source1.command = tail -F E:/WorkSpace/hello.txt使用了tail命令。该工具需要下载。

tail

tail[必要参数][选择参数][文件]

2.命令功能:
用于显示指定文件末尾内容,不指定文件时,作为输入信息进行处理。常用查看日志文件。
3.命令参数:

-f 循环读取  
-q 不显示处理信息  
-v 显示详细的处理信息  
-c<数目> 显示的字节数  
-n<行数> 显示行数  
--pid=PID 与-f合用,表示在进程ID,PID死掉之后结束.  
-q, --quiet, --silent 从不输出给出文件名的首部  
-s, --sleep-interval=S 与-f合用,表示在每次反复的间隔休眠S秒

启动flume:

flume-ng agent -conf ../conf -conf-file ../conf/exec_hdfs.conf -name a1 -property "flume.root.logger=INFO,console"

之后可以向hello.txt文件中不断更新内容,echo hello >> E:/mylogs/hello.txt

同样可以在http://localhost:9870看到更新的内容。


4.实验总结

关于异常

解决方案:\hadoop-3.1.3\share\hadoop\common\lib所有的jar包,都复制到\flume\lib下,

以及hadoop-hdfs-3.1.3.jarhadoop-hdfs-client-3.1.3.jarhadoop-common-3.1.3.jar

guava-27.0-jre,jar只保留较高版本的jar包,低版本的删除。

免得报错...报错一般情况下就是缺少相应的jar包。

报错汇总

可能遇到的报错信息如下:把上面的包都导进来也许就不会看到这些信息了。但是不妨碍会出现新的报错信息。

1.Failed to start agent because dependencies were not found in classpath. Error follows

hadoop-common-3.1.3.jar包复制过来

2.[ERROR - org.apache.flume.sink.hdfs.HDFSEventSink.process(HDFSEventSink.java:459)

java.lang.NoClassDefFoundError: com/ctc/wstx/io/InputBootstrapper

缺少woodstox-core-5.0.3.jar

3.java.lang.NoClassDefFoundError: org/codehaus/stax2/XMLInputFactory2

stax2-api-3.1.4.jar

4.java.lang.NoClassDefFoundError: org/apache/hadoop/util/PlatformName

hadoop-auth-2.4.0.jar

5.java.lang.NoClassDefFoundError: org/apache/commons/configuration2/Configuration

commons-configuration2-2.1.1.jar

2. [ERROR - org.apache.flume.sink.hdfs.AbstractHDFSWriter.hflushOrSync(AbstractHDFSWriter.java:269)] Error while trying to hflushOrSync。

Closing file: hdfs://localhost:9000/weblog/22-10-2508-48/access_log.1666658934768.tmp failed. Will retry again in 180 seconds.

解决方案: 使用Flume的Host拦截器为各个agent处理的文件打上主机信息。


番外篇:拦截器

flume的host拦截器使用官方连接:

flume.apache.org/FlumeUserGu…

a1.sources = r1
a1.channels = c1
#配置拦截器
a1.sources.r1.interceptors = i1
#给定拦截器类型
a1.sources.r1.interceptors.i1.type = host
#配置ip还是host
a1.sources.r1.interceptors.i1.useIp = false

a1.sinks.sink1.hdfs.filePrefix = %{host}

参考链接

flume的安装与使用

tail命令工具

Flume的三要素(Source/Channel/Sink)、拦截器、选择器、Sink组

Flume - Error while trying to hflushOrSync异常处理

安装包

📎tail.zip

📎apache-hadoop-3.1.3-winutils-master.zip