什么是Flume
Flume是一个日志采集工具,特点是不需要写代码,就可以进行日志采集。
如下图,这个属于Flume的典型应用场景,使用Flume采集数据,最终存储到HDFS上。
左边的web server表示是一个web项目,web项目会产生日志数据,通过中间的Agent把日志数据采集到HDFS中。其中这个Agent就是我们使用Flume启动的一个代理,它是一个持续传输数据的服务,数据在Agent内部的这些组件之间传输的基本单位是Event。
从图中可以看到,Agent是由Source,Channel,Sink这三大组件组成的,这就是Flume中的三大核心组件:其中source是数据源,负责读取数据;channel是临时存储数据的,source会把读取到的数据临时存储到channel中;sink是负责从channel中读取数据的,最终将数据写出去,写到指定的目的地中。
Flume高级应用场景
如下图,主要演示了Flume的多路输出,就是可以将采集到的一份数据输出到多个目的地中,不同的目的地的数据对应不同的业务场景。
图中一个有两个Agent,表示启动了2个Flume的代理,或者可以理解为了启动2个Flume的进程。
首先看左边这个agent,给他起名叫foo,这里面有一个source,source后面接了3个channel,表示source读取到的数据会重复发送给每个channel,每个channel中的数据都是一样的;针对每个channel都接了一个sink,这三个sink负责读取对应channel中的数据,并且把数据输出到不同的目的地,sink1负责把数据写到hdfs中,sink2负责把数据写到一个java消息服务数据队列中,sink3负责把数据写给另一个Agent。
Flume中多个Agent之间是可以连通的,只需要让前面Agent的sink组件把数据写到下一个Agent的source组件中即可
所以sink3就把数据输出到了Agent bar中,在Agent bar中同样有三个组件,source组件其实就获取到了sink3发送过来的数据,然后把数据临时存储到自己的channel4中,最终再通过sink组件把数据写到其他地方。这就是这个场景的应用,把采集到的一份数据重复输出到不同目的地中。
接下来再看下面这张图,这张图主要表示了flume的汇聚功能,就是多个Agent采集到的数据统一汇聚到一个Agent。
这个图里面一共启动了四个agent,左边的三个agent都是负责采集对应web服务器中的日志数据,数据采集过来之后统一发送给agent4,最后agent4进行统一汇总,最终写入hdfs。
这种架构的好处是后期如果要修改最终数据的输出目的地,只要修改agent4中的sink即可,不需要修改agent1,2,3。但是也有弊端:
- 如果有很多个agent同时想agent4写数据,那么agent4会出现性能瓶颈,导致数据处理过慢;
- 这种架构还存在单点故障问题,如果agent4挂了,那么所有的数据都断了。
不过这些问题可以通过flume中的负载均衡和故障转移机制解决。
Flume的三大核心组件
Flume的三大核心组件定义
- Source:通过source组件可以指定让Flume读取哪里的数据,然后将数据传递给后面的channel。Flume内置支持读取很多数据源,基于文件,基于目录,基于TCP\UDP端口,基于HTTP,Kafka的等等,也支持自定义
- Channel:接受Source发出的数据,可以把channel理解为一个临时存储数据的管道,channel的类型有很多:内存,文件,内存+文件,JDBC等
- Sink:从Channel中读取数据并存储到指定目的地;Sink的表现形式有很多:打印到控制台,HDFS,Kafka等。Channel中的数据直接进入目的地才会被删除,当sink写入目的地失败后,可以自动重写,不会造成数据丢失,这块是有一个事务保证的。
常用的source
- exec 实现文件监控,可以实时监控文件中的新增内容,类似于linux的tail -f。需要注意tail -F和tail -f的区别:tail -F等同于-follow=name --retry ,根据文件名进行追踪,并保持重试,即该文件被删除或改名后,如果再次创建相同的文件名,会继续追踪;tail -f 等同于-follow=descriptor,根据文件描述符进行追踪,当文件改名或被删除,追踪停止。在实际工作中我们的日志数据一般都会通过log4j记录,log4j产生的日志文件名称是固定的,每天定时给文件重命名,假设默认log4j会向access.log 文件中写日志,每当凌晨0点的时候,log4j都会对文件进行重命名,在access后面添加昨天的日期,然后再创建新的access.log 记录当天的新增日志数据。这个时候如果想要一直监控access.log 文件中的新增日志数据的话,就需要使用tail -F。
- netcat 采集指定端口(tcp,udp)的数据,可以读取流经端口的每一行数据。
- spooldir 采集文件夹里新增的文件
- Kafka Source:从Kafka消息队列中采集数据
exec 和 kafka 在实际工作中是最常见的,可以满足大部分的数据采集需求
常用的channel
- memory:使用内存作为数据的存储,因为就不涉及磁盘IO,所以优点是效率高,缺点有两个:1. 可能会丢数据,如果Flume的agent挂了,那么channel中的数据就丢失了;2.内存是有限的,会存在内存不够用的情况。
- file:使用文件来作为数据的存储,优点是数据不会丢失,缺点是效率相对内存来说会有点慢,但是这个慢并没有我们想象的那么慢,所以这个也是比较常用的一种channel。
- SPILLABLEMEMORY:使用内存和文件作为数据存储,即先把数据存到内存中,如果内存中数据达到阈值再flush到文件中,优点:解决了内存不够用的问题;缺点:还是存在数据丢失的风险。
常用的sink
- logger:将数据作为日志处理,可以选择打印到控制台或者写到文件中,这个主要在测试的时候使用
- hdfs:将数据传输到HDFS中,这个比较常见的,主要针对离线计算的场景
- kafka:将数据发送到kafka消息队列中,这个也是比较常见的,主要针对实时计算场景,数据不落盘,实时传输,最后使用实时计算框架直接处理。
Flume使用案例
单节点flume配置
# example.conf
# 给各个 source channel sink命名
a1.sources = r1
a1.channels = c1
a1.sinks = k1
# 配置source 属性
a1.sources.r1.type = netcat
a1.sources.r1.bind = 0.0.0.0
a1.sources.r1.port = 44444
# 配置channel属性
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# 配置sink属性
a1.sinks.k1.type = logger
# 将source channel sink 串联起来
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
a1.sources.r1.bind = 0.0.0.0 绑定的是当前机器的通用ip,因为一台机器可以有多个ip,例如:内网ip,外网ip,如果通过bind参数指定某一个ip的话,表示就监听通过这个ip发送过来的数据了,这样会有局限性,所以可以指定0.0.0.0
启动flume
bin/flume-ng agent --name a1 --conf conf --conf-file conf/example.conf -Dflume.root.logger=INFO,console
后面指定agent,表示启动一个flume的agent代理
–name: 指定agent的名字
–conf: 指定flume配置文件的根目录
–conf-file: 指定agent对应的配置文件,包含source,channel,sink配置的文件
-D:动态添加一些参数,在这里是指定了flume的日志输出级别和输出位置,INFO表示日志级别,console表示是控制台的意思,也就是说默认会把日志数据打印到控制台上,方便查看,一般在学习测试阶段会指定这个参数
bin/flume-ng agent -n $agent_name -c conf -f conf/flume-conf.properties.template
-n是简写,完整的写法就是-name
-c完整的写法是-conf
-f完整写法是-conf-file
采集文件内容上传至HDFS
需求:采集目录中已有的文件内容,存储到HDFS
分析:source是要给予目录的,channel建议使用file,可以保证不丢数据,sink使用hdfs
# file-to-hdfs.conf
# 给各个 source channel sink命名
a1.sources = r1
a1.channels = c1
a1.sinks = k1
# 配置source 属性
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /data/log/studentDir # 指定监控目录
# 配置channel属性
a1.channels.c1.type = file
a1.channels.c1.checkpointDir = /data/soft/apache-flume-1.9.0-bin/data/studentDir/checkpoint # 存放检查点目录
a1.channels.c1.dataDirs = /data/soft/apache-flume-1.9.0-bin/data/studentDir/data # 存放数据的目录
# 配置source属性
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://XXX.XXX.XXX.XXX:9000/flume/studentDir
a1.sinks.k1.hdfs.filePrefix = stu-
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.writeFormat = Text
a1.sinks.k1.hdfs.rollInterval = 3600
a1.sinks.k1.hdfs.rollSize = 134217728
a1.sinks.k1.hdfs.rollCount = 0
# 将source channel sink 串联起来
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
hdfs.path是必填项,指定hdfs上的存储目录
filePrefix参数是一个文件前缀,会在hdfs上生成的文件前面加上这个前缀,这个属于可选项,有需求的可以加上。
一般需要设置writeFormat和fileType,默认情况下writeFormat是Writable,建议改为Text,表示普通文本数据,这样hive可以直接用;fileType默认是SequenceFile,还支持DataStream和CompressedStream,DataStream不会对输出数据进行压缩,CompressedStream会对数据进行压缩。
hdfs.rollInterval默认值是30,单位是秒,表示hdfs多长时间切分一个文件,因为这个采集程序是一直运行的,只要有新数据,就会被采集到hdfs上面,hdfs默认30秒切分出来一个文件,如果设置为0表示不按时间切文件;
hdfs.rollSize默认是1024,单位是字节,最终hdfs上切出来的文件大小都是1024字节,如果设置为0表示不按大小切文件;
hdfs.rollCount默认设置为10,表示每隔10条数据切出来一个文件,如果设置为0表示不按数据条数切文件;
这三个参数,如果都设置的有值,哪个条件先满足就按照哪个条件执行。
工作中较常用的是时间设置一小时,文件大小设置为128M,哪个先满足执行哪个。