基于尚硅谷flume公开课做的总结。
收集 聚合 传输 的分布式 日志数据
基础架构
Agent
Event
案例一:监控网络端口
# 声明agent内名字
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# 配置sources
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
# 配置sick
a1.sinks.k1.type = logger
# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000#容量
a1.channels.c1.transactionCapacity = 100#一次传输的数量
#将source与sick分别和channel绑定
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
说明:一个source可以绑定多个channel
一个sink只能绑定一个channel,一个channel可以绑定多个sink
启动命令
bin/flume-ng agent --name a1
--conf conf/
--conf-file job/flume-netcat-logger.conf
-Dflume.root.logger=INFO,console
bin/flume-ng agent -n a1
-c conf/
-f job/flume-netcat-logger.conf
-Dflume.root.logger=INFO,console
参数说明:
--conf/-c:表示配置文件存储在 conf/目录
--name/-n:表示给 agent 起名为 a1
--conf-file/-f:flume 本次启动读取的配置文件是在 job 文件夹下的 flume-telnet.conf 文件。
-Dflume.root.logger=INFO,console :-D 表示 flume 运行时动态修改 flume.root.logger 参数属性值,并将控制台日志打印级别设置为 INFO 级别。日志级别包括:log、info、warn、 error。
注意:先起靠后的agent,再起前面的agent。
案例2:监控单个文件追加
注意:1.两中source:exec和taildir都可以实现。
Spooldir Source 能够保证数据不丢失,且能够实现断点续传,但延迟较高,不能实时监控;
而 Taildir Source 既能够实现断点续传,又可以保证数据不丢失,还能够进行实时监控。
2.sink导入HDFS要导入hadoop相关jar包到flume/lib/下。
tail -f :根据文件描述符进行追踪,当文件改名或被删除,追踪停止
-F:根据文件名进行追踪,并保持重试,即该文件被删除或改名后,如果再次创建相同的文件名,会继续追踪
# name
# source
a2.sources.r2.type = exec
a2.sources.r2.command = tail -F /opt/module/hive/logs/hive.log
a2.sources.r2.shell = /bin/bash -c
# sink
a2.sinks.k2.type = hdfs
a2.sinks.k2.hdfs.path = hdfs://hadoop102:9000/flume/%Y%m%d/%H
#上传文件的前缀
a2.sinks.k2.hdfs.filePrefix = logs-
#是否按照时间滚动文件夹
a2.sinks.k2.hdfs.round = true
#多少时间单位创建一个新的文件夹
a2.sinks.k2.hdfs.roundValue = 1
#重新定义时间单位
a2.sinks.k2.hdfs.roundUnit = hour
#是否使用本地时间戳
a2.sinks.k2.hdfs.useLocalTimeStamp = true
#积攒多少个 Event 才 flush 到 HDFS 一次
a2.sinks.k2.hdfs.batchSize = 1000
#设置文件类型,可支持压缩
a2.sinks.k2.hdfs.fileType = DataStream
#多久生成一个新的文件
a2.sinks.k2.hdfs.rollInterval = 30
#设置每个文件的滚动大小
a2.sinks.k2.hdfs.rollSize = 134217700
#文件的滚动与 Event 数量无关
# channel
# Bind
案例三:监控目录下多个新文件
使用Spooldir Source、HDFS Sink
# source
a3.sources.r3.type = spooldir
a3.sources.r3.spoolDir = /opt/module/flume/upload
a3.sources.r3.fileSuffix = .COMPLETED #上传完成之后,文件后缀变为.COMPLETED
a3.sources.r3.fileHeader = true
#忽略所有以.tmp 结尾的文件,不上传
a3.sources.r3.ignorePattern = ([^ ]*\.tmp)
# sink
a3.sinks.k3.type = hdfs
a3.sinks.k3.hdfs.path = hdfs://centos02:9000/flume/upload/%Y%m%d/%H
#上传文件的前缀
a3.sinks.k3.hdfs.filePrefix = upload-
#文件夹滚动。
#是否按照时间滚动文件夹
a3.sinks.k3.hdfs.round = true
#多少时间单位创建一个新的文件夹
a3.sinks.k3.hdfs.roundValue = 1
#重新定义时间单位
a3.sinks.k3.hdfs.roundUnit = hour
#是否使用本地时间戳
a3.sinks.k3.hdfs.useLocalTimeStamp = true
#积攒多少个 Event 才 flush 到 HDFS 一次
a3.sinks.k3.hdfs.batchSize = 100
#设置文件类型,可支持压缩
a3.sinks.k3.hdfs.fileType = DataStream
#文件滚动。下面一组配置,满足一个条件就创建一个新文件
#多久生成一个新的文件:秒
a3.sinks.k3.hdfs.rollInterval = 60
#设置每个文件的滚动大小大概是 128M:字节
a3.sinks.k3.hdfs.rollSize = 134217700
#文件的滚动与 Event 数量无关
a3.sinks.k3.hdfs.rollCount = 0
# channel
# Bind
注意:在使用 Spooling Directory Source 时,不要在监控目录中创建并持续修改文件,上传完成的文件会以.COMPLETED 结尾,被监控文件夹每 500 毫秒扫描一次文件变动
案例三:监控多个追加文件。
使用Taildir source、HDFS Sink
# Describe/configure the source
a3.sources.r3.type = TAILDIR
a3.sources.r3.positionFile = /opt/module/flume/tail_dir.json #为了实现断电续传,这个保存的是文件读取进度
a3.sources.r3.filegroups = f1
a3.sources.r3.filegroups.f1 = /opt/module/flume/files/file.*
# 其余配置同案例二
Taildir 说明:
Taildir Source 维护了一个 json 格式的 position File,其会定期的往 position File 中更新每个文件读取到的最新的位置,因此能够实现断点续传。
flume的souce和sink都是完全事务的
source-put事务:确保数据写入channel
sink-take事务,确保数据写出
总体执行流程:
source -> channel processor ->Intecreptor -> channel selector -> channels -> sink processor ->sinks
1)ChannelSelector :两种:Replicating(复制)、Multiplexing(多路复用)。
选出event发往那个channel。
2)SinkProcessor:三种:DefaultSinkProcessor(单Sink)、 LoadBalancingSinkProcessor(Sink Group、负载均衡)、 FailoverSinkProcessor(Sink Group、故障转移)。
关键点:Source:Channel= n : n ;Channel:Sink = 1 : n
1)串联
3)负载均衡和故障转移
4)聚合
flume-1:
# name
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1 c2
# sources
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/hive/logs/hive.log
a1.sources.r1.shell = /bin/bash -c
# 将数据流复制给所有 channel
a1.sources.r1.selector.type = replicating
# sink;目标端口
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = centos02
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = centos02
a1.sinks.k2.port = 4142
# channel
#bind
flume-2:
# name
# source
# source 端的 avro 是一个数据接收服务
a2.sources.r1.type = avro
a2.sources.r1.bind = centos02
a2.sources.r1.port = 4141
# hdfs sink
# memory channel
# bind
flume-3:
# name
# avro source
a3.sources.r1.type = avro
a3.sources.r1.bind = hcentos02
a3.sources.r1.port = 4142
# file_roll sink
a3.sinks.k1.type = file_roll
a3.sinks.k1.sink.directory = /opt/module/data/flume3
# memory channel
# bind
注意:输出的本地目录必须是已经存在的目录,如果该目录不存在,并不会创建新的目录。
启动顺序:flume 3-2-1,在串联系统中,靠后的flume充当服务器的角色。
flume-1:一个channel发送到两个sink,所以配置sink组。
# name
a1.sources = r1
a1.channels = c1
a1.sinkgroups = g1
a1.sinks = k1 k2
# netcat source
# sink group #配置sink处理器=failover:故障转移,loadblancing,负载均衡。
a1.sinkgroups.g1.processor.type = failover
a1.sinkgroups.g1.processor.priority.k1 = 5
a1.sinkgroups.g1.processor.priority.k2 = 10
a1.sinkgroups.g1.processor.maxpenalty = 10000 #10s
# avro sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = centos02
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = centos02
a1.sinks.k2.port = 4142
# memory channel
# bind
a1.sources.r1.channels = c1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c1
flume-2:
# name
# avro source
# sink
a2.sinks.k1.type = logger
# memory channel
# bind
flume-3:
# name
# avro source
# sink
a2.sinks.k1.type = logger
# memory channel
# bind
注:使用**jps -ml**查看 Flume 进程。
flume-1:
# name
# exec source 使用taildir也可以
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/group.log
a1.sources.r1.shell = /bin/bash -c
# avro sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = centos04
a1.sinks.k1.port = 4141
# memory channel
# bind
flume-2:
# name
# netcat source
# avro sink
a2.sinks.k1.type = avro
a2.sinks.k1.hostname = centos04
a2.sinks.k1.port = 4141
# memory channel
# bind
flume-3:
# name
# avro source
a3.sources.r1.type = avro
a3.sources.r1.bind = centos04
a3.sources.r1.port = 4141
# log sink
a3.sinks.k1.type = logger
# memory channel
# bind
1.自定义拦截器类实现Interceptor接口
2.重写initialize、intercept(event)、intercept(events),close方法。
3.自定义静态内部类Builder实现 Interceptor.Builder接口。
4.重写build(调用自定义Interceptor)、configure方法。
5.打包,放到/flume/lib/文件夹下
6.编写conf文件,执行
注意:conf中配置channel sellector要和自定义拦截器中header属性对应。而配置自定义拦截器要和类中静态内部类名字对应。
实现步骤:
1.导包
<dependency>
<groupId>org.apache.flumegroupId>
<artifactId>flume-ng-coreartifactId>
<version>1.7.0version>
dependency>
2.自定义拦截器类
public class MyInterceptor implements Interceptor {
@Override
public void initialize() {
}
@Override
public Event intercept(Event event) {
byte[] body = event.getBody();
if (body[0] < 'z' && body[0] > 'a') {
event.getHeaders().put("type", "letter");
} else if (body[0] > '0' && body[0] < '9') {
event.getHeaders().put("type", "number");
}
return event;
}
@Override
public List<Event> intercept(List<Event> events) {
for (Event event : events) {
intercept(event);
}
return events;
}
@Override
public void close() {}
public static class Builder implements Interceptor.Builder {
@Override
public Interceptor build() {
return new CustomInterceptor();
}
@Override
public void configure(Context context) {}
}
}
3.编写flume配置文件
# name
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1 c2
# source
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
# 配置自定义拦截器
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type=com.flume.interceptor.MyInterceptor$Builder
a1.sources.r1.selector.type = multiplexing
a1.sources.r1.selector.header = type
a1.sources.r1.selector.mapping.letter = c1
a1.sources.r1.selector.mapping.number = c2
#avro sink k1 k2
# memory channel c1 c2
# bind
a1.sources.r1.channels = c1 c2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2
flume 2 3 都是一个 avro source 和一个 logger sink,配置略。
MySource 需要继承 AbstractSource 类并实现 Configurable 和 PollableSource 接口。
实现相应方法:
getBackOffSleepIncrement()//暂不用
getMaxBackOffSleepInterval()//暂不用
configure(Context context)//初始化
context(读取配置文件内容)
process()//获取数据封装成 event 并写入 channel,这个方法将被循环调用。
使用场景:读取 MySQL 数据或者其他文件系统。
configure(Context context){
prefix = context.getString("prefix");
subfix = context.getString("","");
//第一个参数是属性key,第二个参数是默认值
}
//作用:1.接收数据2.封装事件3.将event传给channel
process(){
try{
for(int i=0;i<5;i++){
SimpleEvent event = new SimpleEvent();
event.setBody((prefix+"--"+i+"--"+subfix).getBytes());
getChannelProcessor().processEvent(event);
status = Status.READY;
}
}catch(e...){
e...
status = Status.BACKOFF;
}
}
# name
# mysource
a1.sources.r1.type = 自定义source的全限定类名
a1.sources.r1.(自定义中声明的属性)
# sink
# channel
# bind
Sink是完全事务的。事务一旦提交,就要删除channel中的数据。
MySink 需要继承 AbstractSink 类并实现 Configurable 接口。
实现相应方法:
configure(Context context)//初始化
context(读取配置文件内容)
process()//从 Channel 读取获取数据(event),这个方法将被循环调用。
使用场景:读取 Channel 数据写入 MySQL 或者其他文件系统。
class MySink extends AbstractSink implements Configuration{
//log4j对象输出日志
private static final Logger LOG =
LoggerFactory.getLogger(AbstractSink.class);
method confugure(){
}
//1.读取Channel2.从ch获取事务以及数据3.发送数据
method process(){
//获取当前 Sink 绑定的 Channel
Channel ch = getChannel();
//获取事务
Transaction txn = ch.getTransaction();
//开启事务
txn.begin();
try{
//从channel获取数据
Event event = ch.take();
//处理事件
String body = new String(event.getBody());
logger.info(body);
txn.commit();
//提交成功,修改状态信息
status = Status.BACKOFF;
}catch(ChannelException e){
e...
txn.roolback();
}finally {
//关闭事务
txn.close();
}
return status;
}
}
# name
# netcat source
# mysink
a1.sicks.k1.type = 全限定类名
自定义sick中的conf配置
#举例:a1.sinks.k1.suffix = :atguigu(本例子中没用到)
# channel
# bind
使用第三方插件Ganglia。
使用第三方框架 Ganglia 实时监控 Flume。
Flume 的 Source,Sink,Channel 的作用?你们 Source 是什么类 型?
1、作用:
(1)Source 组件是专门用来收集数据的,可以处理各种类型、各种格式的日志数据, 包括 avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、 http、legacy (2)Channel 组件对采集到的数据进行缓存,可以存放在 Memory 或 File 中。
(3)Sink 组件是用于把数据发送到目的地的组件,目的地包括 HDFS、Logger、avro、 thrift、ipc、file、Hbase、solr、自定义。
2、我公司采用的 Source 类型为 :
(1)监控后台日志:exec taildir
(2)监控后台产生日志的端口:netcat Exec spooldir
Flume 的 Channel Selectors相关。
Channel Selectors,可以让不同的项目日志通过不同的Channel到不同的Sink中去。 官方文档上Channel Selectors 有两种类型:**Replicating Channel Selector (default)**和 Multiplexing Channel Selector 。
这两种Selector的区别是:Replicating 会 将source过来的events发往所有channel,而 Multiplexing可以选择该发往哪些Channel。
Flume 参数调优
Source
增加 Source 个(使用 Tair Dir Source 时可增加 FileGroups 个数)可以增大 Source 的读 取数据的能力。例如:当某一个目录产生的文件过多时需要将这个文件目录拆分成多个文件 目录,同时配置好多个 Source 以保证 Source 有足够的能力获取到新产生的数据。
**batchSize** 参数决定 Source 一次批量运输到 Channel 的 event 条数,适当调大这个参数 可以提高 Source 搬运 Event 到 Channel 时的性能。
Channel
type 选择 memory 时 Channel 的性能最好,但是如果 Flume 进程意外挂掉可能会丢失 数据。type 选择 file 时 Channel 的容错性更好,但是性能上会比 memory channel 差。
使用 file Channel 时 dataDirs 配置多个不同盘下的目录可以提高性能。
Capacity 参数决定 Channel 可容纳最大的 event 条数。transactionCapacity 参数决定每 次 Source 往 channel 里面写的最大 event 条数和每次 Sink 从 channel 里面读的最大 event 条数。transactionCapacity 需要大于 Source 和 Sink 的 batchSize 参数。
Sink
增加 Sink 的个数可以增加 Sink 消费 event 的能力。Sink 也不是越多越好够用就行,过 多的 Sink 会占用系统资源,造成系统资源不必要的浪费。
batchSize 参数决定 Sink 一次批量从 Channel 读取的 event 条数,适当调大这个参数可 以提高 Sink 从 Channel 搬出 event 的性能。
Flume 的事务机制
Flume 的事务机制(类似数据库的事务机制):Flume 使用两个独立的事务分别负责从 Soucrce 到 Channel,以及从 Channel 到 Sink 的事件传递。比如 spooling directory source 为文件的每一行创建一个事件,一旦事务中所有的事件全部传递到 Channel 且提交成功,那 么 Soucrce 就将该文件标记为完成。同理,事务以类似的方式处理从 Channel 到 Sink 的传 递过程,如果因为某种原因使得事件无法记录,那么事务将会回滚。且所有的事件都会保持 到 Channel 中,等待重新传递。
Flume 采集数据会丢失吗?
根据 Flume 的架构原理,Flume 是不可能丢失数据的,其内部有完善的事务机制, Source 到 Channel 是事务性的,Channel 到 Sink 是事务性的,因此这两个环节不会出现数据的丢失,唯一可能丢失数据的情况是 Channel 采用 memoryChannel,agent 宕机导致数据 丢失,或者 Channel 存储数据已满,导致 Source 不再写入,未写入的数据丢失。
Flume 不会丢失数据,但是有可能造成数据的重复,例如数据已经成功由 Sink 发出, 但是没有接收到响应,Sink 会再次发送数据,此时可能会导致数据的重复。
数,适当调大这个参数可 以提高 Sink 从 Channel 搬出 event 的性能。
Flume 的事务机制
Flume 的事务机制(类似数据库的事务机制):Flume 使用两个独立的事务分别负责从 Soucrce 到 Channel,以及从 Channel 到 Sink 的事件传递。比如 spooling directory source 为文件的每一行创建一个事件,一旦事务中所有的事件全部传递到 Channel 且提交成功,那 么 Soucrce 就将该文件标记为完成。同理,事务以类似的方式处理从 Channel 到 Sink 的传 递过程,如果因为某种原因使得事件无法记录,那么事务将会回滚。且所有的事件都会保持 到 Channel 中,等待重新传递。
Flume 采集数据会丢失吗?
根据 Flume 的架构原理,Flume 是不可能丢失数据的,其内部有完善的事务机制, Source 到 Channel 是事务性的,Channel 到 Sink 是事务性的,因此这两个环节不会出现数据的丢失,唯一可能丢失数据的情况是 Channel 采用 memoryChannel,agent 宕机导致数据 丢失,或者 Channel 存储数据已满,导致 Source 不再写入,未写入的数据丢失。
Flume 不会丢失数据,但是有可能造成数据的重复,例如数据已经成功由 Sink 发出, 但是没有接收到响应,Sink 会再次发送数据,此时可能会导致数据的重复。