Flume 配置,安装,使用,案例
分布式日志采集系统Flume学习
1、Flume架构
1).Hadoop业务开发流程
2)Flume概述
flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。
支持在日志系统中定制各类数据发送方,用于收集数据;
同时,Flume提供对数据进行简单处理,并写到各种数据接受方(比如文本、HDFS、Hbase等)的能力 。
flume的数据流由事件(Event)贯穿始终。
事件是Flume的基本数据单位,它携带日志数据(字节数组形式)并且携带有头信息,这些Event由Agent外部的Source生成,当Source捕获事件后会进行特定的格式化,然后Source会把event推入(单个或多个)Channel中。你可以把Channel看作是一个缓冲区,它将保存事件直到Sink处理完该事件。Sink负责持久化日志或者把事件推向另一个Source。
Event的概念:
flume的核心是把数据从数据源(source)收集过来,在将收集到的数据送到指定的目的地(sink)。为了保证输送的过程一定成功,在送到目的地(sink)之前,会先缓存数据(channel),待数据真正到达目的地(sink)后,flume再删除自己缓存的数据。 在整个数据的传输的过程中,流动的是event,即事务保证是在event级别进行的。那么什么是event呢?—–event将传输的数据进行封装,是flume传输数据的基本单位,如果是文本文件,通常是一行记录,event也是事务的基本单位。event从source,流向channel,再到sink,本身为一个字节数组,并可携带headers(头信息)信息。event代表着一个数据的最小完整单元,从外部数据源来,向外部的目的地去。
简单理解:event信息就是flume收集到的数据(日志记录)
它是一个完整的数据收集工具,含有三个核心组件,分别是source、 channel、 sink。
source
Channel
Channel是连接Source和Sink的组件,大家可以将它看做一个数据的缓冲区(数据队列),它可以将事件暂存到内存中也可以持久化到本地磁盘上, 直到Sink处理完该事件。介绍两个较为常用的Channel, MemoryChannel和FileChannel。
Channel支持的类型
Sink
Sink从Channel中取出事件,然后将数据发到别处,可以向文件系统、数据库、 hadoop存数据, 也可以是其他agent的Source。在日志数据较少时,可以将数据存储在文件系统中,并且设定一定的时间间隔保存数据。
3)Flume运行机制
Flume 传输的数据的基本单位是 Event,如果是文本文件,通常是一行记录,这也是事务的基本单位。 Event 从 Source,流向 Channel,再到 Sink,本身为一个 byte 数组,并可携带 headers 信息。 Event 代表着一个数据流的最小完整单元,从外部数据源来,向外部的目的地去。
值得注意的是,Flume提供了大量内置的Source、Channel和Sink类型。不同类型的Source,Channel和Sink可以自由组合。组合方式基于用户设置的配置文件,非常灵活。
比如:Channel可以把事件暂存在内存里,也可以持久化到本地硬盘上。Sink可以把日志写入HDFS, HBase,甚至是另外一个Source等等。Flume支持用户建立多级流,
4)Flume可靠性
Flume 使用事务性的方式保证传送Event整个过程的可靠性。 Sink 必须在Event 已经被传达到下一站agent里,又或者,已经被存入外部数据目的地之后,才能把 Event 从 Channel 中 remove 掉。这样数据流里的 event 无论是在一个 agent 里还是多个 agent 之间流转,都能保证可靠,因为以上的事务保证了 event 会被成功存储起来。比如 Flume支持在本地保存一份channel文件作为备份,而memory channel 将event存在内存 queue 里,速度快,但丢失的话无法恢复。
5)
2、Flume的安装
1.上传压缩包并解压(/usr/local/soft)
tar -zxvf apache-flume-1.9.0-bin.tar.gz
2.重命名目录,并配置环境变量
mv apache-flume-1.9.0-bin/ flume-1.9.0
vim /etc/profile
export FLUME_HOME=/usr/local/soft/flume-1.9.0 $FLUME_HOME/bin
source /etc/profile
3.查看flume版本
flume-ng version
3、使用案例
在使用之前,提供一个大致思想,使用Flume的过程是确定scource类型,channel类型和sink类型,编写conf文件并开启服务,在数据捕获端进行传入数据流入到目的
案例一:从控制台打入数据,在控制台显示
2、编写conf文件
#a代表agent的名称,r1代表source的名称。c1代表channel名称,k1代表的是sink的名称 #声明各个组件 a.sources=r1 a.channels=c1 a.sinks=k1 #定义source类型,这里是试用netcat的类型 a.sources.r1.type=netcat a.sources.r1.bind=192.168.80.100 a.sources.r1.port=8888 #定义source发送的下游channel a.sources.r1.channels=c1 #定义channel a.channels.c1.type=memory #缓存的数据条数 a.channels.c1.capacity=1000 #事务数据量 a.channels.c1.transactionCapacity=1000 #定义sink的类型,确定上游channel a.sinks.k1.channel=c1 a.sinks.k1.type=logger
3、开启服务,我们重新开启复制一个客户端进行开启服务
[root@master flumeconfs]# flume-ng agent -n a -c /usr/local/soft/flume-1.9.0/conf -f ./netcat.conf -Dflume.root.logger=DEBUG,console
4、在另一个客户端输入命令:(需要先启动hadoop)
yum install -y telnet
yum install -y nc
第一种方式打开:telnet master 8888
单独起一个线程,不会占用端口号
第二种方式打开:nc -lk 8888
单独起一个线程,会占用端口号
2、编写conf文件
a1.sources = r1 a1.sinks = k1 a1.channels = c1 #指定spooldir的属性 a1.sources.r1.type = spooldir a1.sources.r1.spoolDir = /usr/local/soft/flumedata #时间拦截器 a1.sources.r1.interceptors = i1 a1.sources.r1.interceptors.i1.type = timestamp #指定sink的类型 a1.sinks.k1.type = hdfs #指定hdfs的集群地址和路径,路径如果没有创建会自动创建 a1.sinks.k1.hdfs.path =hdfs://master:9000/shujia/bigdata19/flumeout/log_s/dt=%Y-%m-%d #指定hdfs路径下生成的文件的前缀 a1.sinks.k1.hdfs.filePrefix = log_%Y-%m-%d #手动指定hdfs最小备份 a1.sinks.k1.hdfs.minBlockReplicas=1 #设置数据传输类型 a1.sinks.k1.hdfs.fileType = DataStream #如果参数为0,不按照条数生成文件。如果参数为n,就是按照n条生成一个文件 a1.sinks.k1.hdfs.rollCount = 10000 #这个参数是hdfs下文件sink的数据size。每sink 32MB的数据,自动生成一个文件 a1.sinks.k1.hdfs.rollSize =0 #每隔n 秒 将临时文件滚动成一个目标文件。如果是0,就不按照时间进行生成目标文件。 a1.sinks.k1.hdfs.rollInterval =0 a1.sinks.k1.hdfs.idleTimeout=0 #指定channel a1.channels.c1.type = memory #暂存条数 a1.channels.c1.capacity = 10000 #每次sink取的条数 a1.channels.c1.transactionCapacity = 1000 #组装 a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1
3、开启服务
[root@master flumedata]# flume-ng agent -n a1 -c /usr/local/soft/flume-1.9.0/conf -f ./dir2hdfs.conf -Dflume.root.logger=DEBUG,console
4、将文件复制到指定的目录下
cp DIANXIN.csv /usr/local/soft/flumedata/
a1.sources = r1 a1.sinks = k1 a1.channels = c1 #定义source类型,这里是试用netcat的类型 a1.sources.r1.type=netcat a1.sources.r1.bind=192.168.80.100 a1.sources.r1.port=8888 #指定sink的类型 a1.sinks.k1.type = hdfs #指定hdfs的集群地址和路径,路径如果没有创建会自动创建 a1.sinks.k1.hdfs.path =hdfs://master:9000/shujia/bigdata19/flumeout2/log_s/test #指定hdfs路径下生成的文件的前缀 a1.sinks.k1.hdfs.filePrefix = log_test #手动指定hdfs最小备份 a1.sinks.k1.hdfs.minBlockReplicas=1 #设置数据传输类型 a1.sinks.k1.hdfs.fileType = DataStream #如果参数为0,不按照条数生成文件。如果参数为n,就是按照n条生成一个文件 a1.sinks.k1.hdfs.rollCount = 100 #这个参数是hdfs下文件sink的数据size。每sink 32MB的数据,自动生成一个文件 a1.sinks.k1.hdfs.rollSize =0 #每隔n 秒 将临时文件滚动成一个目标文件。如果是0,就不按照时间进行生成目标文件。 a1.sinks.k1.hdfs.rollInterval =0 a1.sinks.k1.hdfs.idleTimeout=0 #指定channel a1.channels.c1.type = memory #暂存的条数 a1.channels.c1.capacity = 1000 #每次sink取的条数 a1.channels.c1.transactionCapacity = 10 #组装 a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1
1、先确定scource类型,channel类型和sink类型
确定的三个组件的类型是,avro source, memory channel, hdfs sink
2、打开maven项目,添加依赖
<!-- https://mvnrepository.com/artifact/org.apache.flume/flume-ng-core --> <dependency> <groupId>org.apache.flume</groupId> <artifactId>flume-ng-core</artifactId> <version>1.9.0</version> </dependency> <dependency> <groupId>org.apache.flume.flume-ng-clients</groupId> <artifactId>flume-ng-log4jappender</artifactId> <version>1.9.0</version> </dependency>
3、设置log4J的内容
log4j.rootLogger=INFO,stdout,flume log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n log4j.appender.flume = org.apache.flume.clients.log4jappender.Log4jAppender log4j.appender.flume.Hostname = 192.168.80.100 log4j.appender.flume.Port = 41414 log4j.appender.flume.UnsafeMode = true log4j.appender.flume.layout=org.apache.log4j.PatternLayout log4j.appender.flume.layout.ConversionPattern=%m%n
编写java代码(示例,可以修改logger打印的内容)
package com; import org.apache.log4j.Logger; import java.text.SimpleDateFormat; import java.util.Date; public class LoggerToFlume { public static void main(String[] args) throws InterruptedException { //创建一个logger对象 Logger logger = Logger.getLogger(LoggerToFlume.class.getName()); //写一个死循环 while (true) { Date date = new Date(); //创建一个日期格式化对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time=sdf.format(date); logger.info("当前的时间是:"+time); //让线程休眠一会儿 Thread.sleep(1000); } } }
4、编写conf文件
#定义agent名, source、channel、sink的名称 a.sources = r1 a.channels = c1 a.sinks = k1 #具体定义source a.sources.r1.type = avro a.sources.r1.bind = 192.168.80.100 a.sources.r1.port = 41414 #具体定义channel a.channels.c1.type = memory a.channels.c1.capacity = 10000 a.channels.c1.transactionCapacity = 1000 #具体定义sink a.sinks.k1.type = hdfs a.sinks.k1.hdfs.path =hdfs://master:9000/shujia/bigdata19/flumeout2/flume_hdfs_avro2 a.sinks.k1.hdfs.filePrefix = events- a.sinks.k1.hdfs.minBlockReplicas=1 a.sinks.k1.hdfs.fileType = DataStream #不按照条数生成文件 a.sinks.k1.hdfs.rollCount = 1000 a.sinks.k1.hdfs.rollSize =0 #每隔N s将临时文件滚动成一个目标文件 a.sinks.k1.hdfs.rollInterval =0 a.sinks.k1.hdfs.idleTimeout=0 #组装source、channel、sink a.sources.r1.channels = c1 a.sinks.k1.channel = c1
5、开启服务,命令:
flume-ng agent -n a -c ../conf -f ./avro2hdfs2.conf -Dflume.root.logger=DEBUG,console
案例四、监控HBase日志到Hbase表中(这里可以换成其他组件日志监控)
1、监控日志
提前建好表
create 'log','cf1'
编写conf文件 hbaselog2hdfs.conf
# a表示给agent命名为a # 给source组件命名为r1 a.sources = r1 # 给sink组件命名为k1 a.sinks = k1 # 给channel组件命名为c1 a.channels = c1 #指定spooldir的属性 a.sources.r1.type = exec a.sources.r1.command = cat /usr/local/soft/hbase-1.4.6/logs/hbase-root-master-master.log #指定sink的类型 a.sinks.k1.type = hbase a.sinks.k1.table = log a.sinks.k1.columnFamily = cf1 #指定channel a.channels.c1.type = memory a.channels.c1.capacity = 10000 # 表示sink每次会从channel里取多少数据 a.channels.c1.transactionCapacity = 100 # 组装 a.sources.r1.channels = c1 a.sinks.k1.channel = c1
运行
flume-ng agent -n a -c ../conf -f ./ hbaselog2hdfs.conf -Dflume.root.logger=DEBUG,console
确保test_idoall_org表在hbase中已经存在:
hbase(main):002:0> create 'test_idoall_org','uid','name' 0 row(s) in 0.6730 seconds => Hbase::Table - test_idoall_org hbase(main):003:0> put 'test_idoall_org','10086','name:idoall','idoallvalue' 0 row(s) in 0.0960 seconds
2.创建配置文件:
a1.sources = r1 a1.sinks = k1 a1.channels = c1 # Describe/configure the source a1.sources.r1.type = exec a1.sources.r1.command = tail -F /usr/local/soft/flumedata/data.txt a1.sources.r1.port = 44444 a1.sources.r1.host = 192.168.40.110 # Describe the sink a1.sinks.k1.type = hbase a1.sinks.k1.table = test_idoall_org a1.sinks.k1.columnFamily = name a1.sinks.k1.serializer = org.apache.flume.sink.hbase.RegexHbaseEventSerializer # Use a channel which buffers events in memory a1.channels.c1.type = memory a1.channels.c1.capacity = 1000 a1.channels.c1.transactionCapacity = 100 # Bind the source and sink to the channel a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1
3.启动flume agent:
flume-ng agent -n a1 -c ../../flume/conf -f ./file2hbase.conf -Dflume.root.logger=DEBUG, console
4.产生数据
echo "hello idoall.org from flume" >> data.txt
1、先确定scource类型,channel类型和sink类型
确定的三个组件的类型是,http source, memory channel, logger sink.
2、编写conf文件
a1.sources=r1 a1.sinks=k1 a1.channels=c1 a1.sources.r1.type=http a1.sources.r1.port=50000 a1.sources.r1.channels=c1 a1.sinks.k1.type=logger a1.sinks.k1.channel=c1 a1.channels.c1.type=memory a1.channels.c1.capacity=10000 # 表示sink每次会从channel里取多少数据 a1.channels.c1.transactionCapacity=100
3、启动服务
curl -X POST -d'[{"headers":{"h1":"v1","h2":"v2"},"body":"hello bigdata"}]' http://192.168.40.110:50000
1、将flume复制到node1,node2
[root@master soft]# scp -r flume-1.9.0 node1:`pwd` [root@master soft]# scp -r flume-1.9.0 node2:`pwd`
2、在node1节点的/usr/local/soft/bigdata19/scripts 下新建配置文件:
a3.sources = r3 a3.channels = c3 a3.sources.r3.type = avro a3.sources.r3.channels = c3 a3.sources.r3.bind = node1 a3.sources.r3.port = 4141 a3.channels.c3.type = memory a3.channels.c3.capacity = 1000 a3.channels.c3.transactionCapacity = 100 a3.sinks = k3 a3.sinks.k3.type = logger a3.sinks.k3.channel = c3
3、在node2节点的 /usr/local/soft/bigdata19/scripts 下新建配置文件:
vim netcat-flume-loggers.conf
添加如下内容:
a4.sources = r4 a4.channels = c4 a4.sources.r4.type = avro a4.sources.r4.channels = c4 a4.sources.r4.bind = node2 a4.sources.r4.port = 4141 a4.channels.c4.type = memory a4.channels.c4.capacity = 1000 a4.channels.c4.transactionCapacity = 100 a4.sinks = k4 a4.sinks.k4.type = logger a4.sinks.k4.channel = c4
4、在master节点的 /usr/local/soft/bigdata19/scrips 下新建配置文件:
vim netcat-flume-loggers.conf
添加如下内容
a2.sources = r1 a2.sinks = k1 k2 a2.channels = c1 c2 # Describe/configure the source a2.sources.r1.type = netcat a2.sources.r1.bind = master a2.sources.r1.port = 44444 # Describe the sink a2.sinks.k1.type = avro a2.sinks.k1.hostname = node1 a2.sinks.k1.port = 4141 a2.sinks.k2.type = avro a2.sinks.k2.hostname = node2 a2.sinks.k2.port = 4141 # Use a channel which buffers events in memory a2.channels.c1.type = memory a2.channels.c1.capacity = 1000 a2.channels.c1.transactionCapacity = 100 # Use a channel which buffers events in memory a2.channels.c2.type = memory a2.channels.c2.capacity = 1000 a2.channels.c2.transactionCapacity = 100 # Bind the source and sink to the channel a2.sources.r1.channels = c1 c2 a2.sinks.k1.channel = c1 a2.sinks.k2.channel = c2
flume-ng agent -n a3 -c ../../flume-1.9.0/conf -f ./netcat-flume-loggers.conf -Dflume.root.logger=INFO,console flume-ng agent -n a4 -c ../../flume-1.9.0/conf -f ./netcat-flume-loggers.conf -Dflume.root.logger=INFO,console
启动master节点的netcat:
flume-ng agent -n a2 -c ../../flume-1.9.0/conf -f ./netcat-flume-loggers.conf -Dflume.root.logger=INFO,console
开启netcat后此窗口就不能操作了,再新建一个master窗口启动telnet:
telnet master 44444
master上输入数据:
node1和node2接收数据:
案例七、故障转移
Flume支持使用将多个sink逻辑上分到一个sink组,sink组配合不同的SinkProcessor可以实现负载均衡和错误恢复的功能。这里的故障,指的是Sink故障
1)通过sinkgroups里priority属性配置的权重来决定哪台的优先级高,同一时间只能有一台机器工作
2)当当前的sink挂掉后切换为standby模式(假设优先级10),并立刻切换到另一台(假设优先级9),当sink修复好重新启动后,隔段时间会恢复使用优先级为10的sink
3)遇到故障时,我们要立即修复
master:
vim guzhang.conf
a1.sources = r1 a1.channels = c1 a1.sinks = k1 k2 a1.sources.r1.type = netcat a1.sources.r1.bind = master a1.sources.r1.port = 4444 a1.channels.c1.type = memory a1.channels.c1.capacity = 10000 a1.channels.c1.transactionCapacity = 100 #将数据写到另一台Flume服务器上 a1.sinks.k1.type = avro a1.sinks.k1.hostname = node1 a1.sinks.k1.port = 5555 #将数据写到另一台Flume服务器上 a1.sinks.k2.type = avro a1.sinks.k2.hostname = node2 a1.sinks.k2.port = 6666 #使用sink processor来控制channel的数据流向 a1.sinkgroups = g1 a1.sinkgroups.g1.sinks = k1 k2 a1.sinkgroups.g1.processor.type = failover a1.sinkgroups.g1.processor.priority.k1 = 5 a1.sinkgroups.g1.processor.priority.k2 = 10 a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 a1.sinks.k2.channel = c1
node1
a3.sources = r3 a3.channels = c3 a3.sources.r3.type = avro a3.sources.r3.channels = c3 a3.sources.r3.bind = node1 a3.sources.r3.port = 5555 a3.channels.c3.type = memory a3.channels.c3.capacity = 1000 a3.channels.c3.transactionCapacity = 100 a3.sinks = k3 a3.sinks.k3.type = logger a3.sinks.k3.channel = c3
node2
a4.sources = r4 a4.channels = c4 a4.sources.r4.type = avro a4.sources.r4.channels = c4 a4.sources.r4.bind = node2 a4.sources.r4.port = 6666 a4.channels.c4.type = memory a4.channels.c4.capacity = 1000 a4.channels.c4.transactionCapacity = 100 a4.sinks = k4 a4.sinks.k4.type = logger a4.sinks.k4.channel = c4
先启动node1,node2上的
flume-ng agent -n a3 -c ../../flume-1.9.0/conf -f ./guzhang.conf -Dflume.root.logger=INFO,console flume-ng agent -n a4 -c ../../flume-1.9.0/conf -f ./guzhang.conf -Dflume.root.logger=INFO,console
再启动master的
flume-ng agent -n a1 -c ../../flume-1.9.0/conf -f ./guzhang.conf -Dflume.root.logger=INFO,console
master输入数据
telnet master 4444
启动之后数据会输出到node2(因为node1是5,node2是10),再将node2手动关闭后数据输出到node1,如果把node2继续启动后,数据会继续输出到node2 。
通过将sinkprocessor里的type属性来控制processor模式,分别是(负载均衡load_balance、故障转移failover)
使用负载均衡以后,channel会轮训分配任务,减少机器负荷
master上的配置文件:(随机的)
a1.sources = r1 a1.channels = c1 a1.sinks = k1 k2 a1.sources.r1.type = netcat a1.sources.r1.bind = master a1.sources.r1.port = 4444 a1.channels.c1.type = memory a1.channels.c1.capacity = 10000 a1.channels.c1.transactionCapacity = 100 a1.sinks.k1.type = avro a1.sinks.k1.hostname = node1 a1.sinks.k1.port = 5555 a1.sinks.k2.type = avro a1.sinks.k2.hostname = node2 a1.sinks.k2.port = 6666 a1.sinkgroups = g1 a1.sinkgroups.g1.sinks = k1 k2 a1.sinkgroups.g1.processor.type = load_balance a1.sinkgroups.g1.processor.backoff = true a1.sinkgroups.g1.processor.selector = random a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 a1.sinks.k2.channel = c1
node1、node2两台日志服务机器实时生产日志主要类型为access.log、nginx.log、web.log 现在要求:
把node1、node2机器中的access.log、nginx.log、web.log 采集汇总到master机器上然后统一收集到hdfs中。 但是在hdfs中要求的目录为:
/shujia/bigdata19/flumelogs/access/20220616/** /shujia/bigdata19/flumelogs/nginx/20180616/** /shujia/bigdata19/flumelogs/web/20180616/**
场景分析:
数据流程处理分析:
实现:
node1对应的IP为 192.168.80.20 node2对应的IP为 192.168.80.30 master对应的IP为 192.168.80.100
node1和node2上配置文件
[root@node2 bigdata17]# mkdir -p /usr/local/soft/bigdata17/scrips/taillogs [root@node2 bigdata17]# touch /usr/local/soft/bigdata19/scrips/taillogs/access.log [root@node2 bigdata17]# touch /usr/local/soft/bigdata19/scrips/taillogs/nginx.log [root@node2 bigdata17]# touch /usr/local/soft/bigdata19/scrips/taillogs/web.log
vim exec_source_avro_sink.conf
# Name the components on this agent a1.sources = r1 r2 r3 a1.sinks = k1 a1.channels = c1 # Describe/configure the source a1.sources.r1.type = exec a1.sources.r1.command = tail -F /usr/local/soft/bigdata17/scrips/taillogs/access.log # static拦截器的功能就是往采集到的数据的header中插入自己定义的key-value对 a1.sources.r1.interceptors = i1 a1.sources.r1.interceptors.i1.type = static a1.sources.r1.interceptors.i1.key = type a1.sources.r1.interceptors.i1.value = access a1.sources.r2.type = exec a1.sources.r2.command = tail -F /usr/local/soft/bigdata17/scrips/taillogs/nginx.log a1.sources.r2.interceptors = i2 a1.sources.r2.interceptors.i2.type = static a1.sources.r2.interceptors.i2.key = type a1.sources.r2.interceptors.i2.value = nginx a1.sources.r3.type = exec a1.sources.r3.command = tail -F /usr/local/soft/bigdata17/scrips/taillogs/web.log a1.sources.r3.interceptors = i3 a1.sources.r3.interceptors.i3.type = static a1.sources.r3.interceptors.i3.key = type a1.sources.r3.interceptors.i3.value = web # Describe the sink a1.sinks.k1.type = avro a1.sinks.k1.hostname = master a1.sinks.k1.port = 41414 # Use a channel which buffers events in memory a1.channels.c1.type = memory a1.channels.c1.capacity = 20000 a1.channels.c1.transactionCapacity = 10000 # Bind the source and sink to the channel a1.sources.r1.channels = c1 a1.sources.r2.channels = c1 a1.sources.r3.channels = c1 a1.sinks.k1.channel = c1
在master上面开发flume配置文件
vim avro_source_hdfs_sink.conf
a1.sources = r1 a1.sinks = k1 a1.channels = c1 # 定义source a1.sources.r1.type = avro a1.sources.r1.bind = master a1.sources.r1.port =41414 # 添加时间拦截器 a1.sources.r1.interceptors = i1 a1.sources.r1.interceptors.i1.type = timestamp # 定义channels a1.channels.c1.type = memory a1.channels.c1.capacity = 20000 a1.channels.c1.transactionCapacity = 10000 # 定义sink a1.sinks.k1.type = hdfs a1.sinks.k1.hdfs.path=hdfs://master:9000/shujia/bigdata17/flumelogs/%{type}/%Y%m%d a1.sinks.k1.hdfs.filePrefix = events a1.sinks.k1.hdfs.fileType = DataStream a1.sinks.k1.hdfs.writeFormat = Text # 时间类型 a1.sinks.k1.hdfs.useLocalTimeStamp = true # 生成的文件不按条数生成 a1.sinks.k1.hdfs.rollCount = 0 # 生成的文件按时间生成 a1.sinks.k1.hdfs.rollInterval = 30 # 生成的文件按大小生成 a1.sinks.k1.hdfs.rollSize = 10485760 # 批量写入hdfs的个数 a1.sinks.k1.hdfs.batchSize = 10000 # flume操作hdfs的线程数(包括新建,写入等) a1.sinks.k1.hdfs.threadsPoolSize=10 # 操作hdfs超时时间 a1.sinks.k1.hdfs.callTimeout=30000 # 组装source、channel、sink a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1
# !/bin/bash while true do date >> /usr/local/soft/bigdata19/scrips/taillogs/access.log; date >> /usr/local/soft/bigdata19/scrips/taillogs/web.log; date >> /usr/local/soft/bigdata19/scrips/taillogs/nginx.log; sleep 0.5; done
flume-ng agent -n a1 -c ../../flume-1.9.0/conf -f ./avro_source_hdfs_sink.conf -Dflume.root.logger=INFO,console
node1与node2启动flume实现数据监控
flume-ng agent -n a1 -c ../../flume-1.9.0/conf -f ./exec_source_avro_sink.conf -Dflume.root.logger=INFO,console
node1与node2启动生成文件脚本
sh server.sh
ChannelSelector的作用就是选出Event将要被发往哪个Channel。其共有两种类型,分别是Replicating(复制)和Multiplexing(多路复用)。
ReplicatingSelector会将同一个Event发往所有的Channel,Multiplexing会根据相应的原则,将不同的Event发往不同的Channel。默认是Replicating
Multiplexing类型的ChannelSelector会根据Event中Header中的某个属性决定分发到哪个Channel。
每个event里的header默认是没有值的,所以,multiplexing类型的ChannelSelector一般会配合自定义拦截器使用
replicating类型例子:
a1.sources = r1 a1.channels = c1 c2 # 如果有100个Event,那么c1和c2中都会有这100个事件 a1.channels.c1.type = memory a1.channels.c1.capacity = 1000 a1.channels.c1.transactionCapacity = 100 a1.channels.c2.type = memory a1.channels.c2.capacity = 1000 a1.channels.c2.transactionCapacity = 100
multiplexing类型的ChannelSelector例子:
a1.sources = r1 a1.channels = c1 c2 a1.sources.source1.selector.type = multiplexing a1.sources.source1.selector.header = title # 以header中的title对应的值作为条件 a1.sources.source1.selector.mapping.a = c2 # 如果header中title的值为a,使用c2这个channel a1.sources.source1.selector.mapping.b = c1 # 如果header中title的值为b,使用c1这个channel a1.sources.source1.selector.default = c1 # 默认使用c1这个channel
SinkProcessor
SinkProcessor共有三种类型,分别是DefaultSinkProcessor、LoadBalancingSinkProcessor和FailoverSinkProcessor
DefaultSinkProcessor对应的是单个的Sink,LoadBalancingSinkProcessor和FailoverSinkProcessor对应的是Sink Group,LoadBalancingSinkProcessor可以实现负载均衡的功能,FailoverSinkProcessor可以错误恢复的功能。
自定义Interceptor
使用Flume采集服务器本地日志,需要按照日志类型的不同,将不同种类的日志发往不同的分析系统。
需求:
在该案例中,我们以端口数据模拟日志,模拟不同类型的日志,我们需要自定义interceptor区分内容是否包含shujia,将其分别发往不同的分析系统(Channel)。
实现代码
import org.apache.flume.Context; import org.apache.flume.Event; import org.apache.flume.interceptor.Interceptor; import java.util.List; import java.util.Map; /** * 1. 如何自定义拦截器? * flume的自定义拦截器需要实现Flume提供的Interceptor接口. * * 实现抽象方法: * initialize: 完成一些初始化工作. * close: 完成一些善后的工作 * intercept:拦截器的核心处理方法. 拦截的逻辑. * intercept(Event event) : 单个event的拦截处理 * intercept(List<Event> events): 批次event的拦截处理 * * 2. 拦截器的对象如何实例化? * 在拦截器中定义一个static的内部类,实现Flume提供的Builder接口 * * 实现抽象方法: * build : 用于构建拦截器对象 * configure:用于读取配置信息(xxxx.conf) * * * */ public class LogDataInterceptor implements Interceptor { @Override public void initialize() { } /* 判断变成event的数据中是否包含shujia字符串,event==>header({}) + body(数据) 如果包含,给event中的header中添加一个key-value: name/title/key === sj 如果不包含,给event中的header中添加一个key-value: name/title/key === nsj */ @Override public Event intercept(Event event) { //如何取出event中的header和body呢? // Map<String, String> getHeaders(); // void setHeaders(Map<String, String> var1); // byte[] getBody(); Map<String, String> headers = event.getHeaders(); String body = new String(event.getBody()); //判断body是否包含shujia if(body.contains("shujia")){ headers.put("title","sj"); }else { headers.put("title","nsj"); } return event; } @Override public List<Event> intercept(List<Event> list) { for (Event event : list) { intercept(event); } return list; } @Override public void close() { } public static class MyBuilder implements Builder{ @Override public Interceptor build() { return new LogDataInterceptor(); } @Override public void configure(Context context) { } } }
引入依赖
<dependency> <groupId>org.apache.flume</groupId> <artifactId>flume-ng-core</artifactId> <version>1.9.0</version> </dependency>
将代码打成jar包
将jar包放在flume的lib目录下。简单暴力,但是不方便管理
1.进阶案例 - channel选择器 - 多路 a3 ==> a3.conf a3.sources = r1 a3.channels = c1 a3.sinks = k1 a3.sources.r1.type = avro a3.sources.r1.bind = node2 a3.sources.r1.port = 6666 a3.channels.c1.type = memory a3.channels.c1.capacity = 10000 a3.channels.c1.transactionCapacity = 100 a3.sinks.k1.type = logger a3.sources.r1.channels = c1 a3.sinks.k1.channel = c1 a2 ==> a2.conf a2.sources = r1 a2.channels = c1 a2.sinks = k1 a2.sources.r1.type = avro a2.sources.r1.bind = node1 a2.sources.r1.port = 5555 a2.channels.c1.type = memory a2.channels.c1.capacity = 10000 a2.channels.c1.transactionCapacity = 100 a2.sinks.k1.type =logger a2.sources.r1.channels = c1 a2.sinks.k1.channel = c1 a1 ==> a1.conf a1.sources = r1 a1.channels = c1 c2 a1.sinks = k1 k2 a1.sources.r1.type = netcat a1.sources.r1.bind = master a1.sources.r1.port = 4444 #将选择器类型改为multiplexing分发 a1.sources.r1.selector.type = multiplexing #检测每个event里head的title key a1.sources.r1.selector.header = title #如果title的值为at,吧event发到channel c1里,如果为ot,发到channel c2里,如果都不匹配,默认发到c2里 a1.sources.r1.selector.mapping.sj = c1 a1.sources.r1.selector.mapping.nsj = c2 a1.sources.r1.selector.default=c2 #给拦截器命名i1 a1.sources.r1.interceptors = i1 #这里写自定义类的全类名 a1.sources.r1.interceptors.i1.type = com.shujia.log2flume.LogDataInterceptor$MyBuilder # 组装channel与source a1.sources.r1.channels = c1 c2 a1.channels.c1.type = memory a1.channels.c1.capacity = 10000 a1.channels.c1.transactionCapacity = 100 a1.channels.c2.type = memory a1.channels.c2.capacity = 10000 a1.channels.c2.transactionCapacity = 100 a1.sinks.k1.type = avro a1.sinks.k1.hostname = node1 a1.sinks.k1.port = 5555 a1.sinks.k2.type = avro a1.sinks.k2.hostname = node2 a1.sinks.k2.port = 6666 a1.sinks.k1.channel = c1 a1.sinks.k2.channel = c2
启动
flume-ng agent -n a2 -c ../../flume-1.9.0/conf -f ./a2.conf -Dflume.root.logger=INFO,console flume-ng agent -n a3 -c ../../flume-1.9.0/conf -f ./a3.conf -Dflume.root.logger=INFO,console
最后启动master上面的flume
flume-ng agent -n a1 -c ../../flume-1.9.0/conf -f ./a3.conf -Dflume.root.logger=INFO,console