Flume学习笔记
概述
官网。Cloudera开源的Flume通过简单的配置收集不同数据源的海量数据并将数据准确高效地传输到不同的中心存储。
一种提供高可用、高可靠、分布式海量日志采集、聚合和传输的系统,支持在日志系统中定制各类数据发送方,用于采集数据;同时提供对数据进行简单处理,并写到各种数据接收方的能力,即Flume是实时采集日志的数据采集引擎。
Flume-OG升级到Flume-NG。
概念
- Client:Client生产数据,运行在一个独立的线程
- Event:一条消息或一条数据,具有可选头信息,在头信息中可以设置时间戳、主机名称等信息。可以是日志记录、 avro 对象等
- Source:数据源,接收或者收集不同形式的数据源
- Channel:event的临时缓冲区,source先将event发送到channel缓存等待sink消费
- Sink:从channel获取event并发送到中心存储或者下一级agent
- Agent:包含source、channel、sink等组件的flume进程
- Interceptor:event拦截器,根据配置文件在event的header中添加时间戳、主机名称等信息
- Selector:event选择器,event选择流入channel的方式,flume提供复制(replicating)和复用(multiplexing)选择器
- Sink Processor:event sink处理器,flume提供故障转移处理器和负载均衡处理器
架构
Flume主要分为Source、Channel、Sink三个组件,包含在一个Agent中,一个Agent相当于一个独立的application,数据从源头经过Agent的这几个组件最后到达目的地。一个Flume服务可同时运行多个Agent。一个event在一个agent中的传输流程:
特性
1、可靠性
当节点出现故障时,日志能够被传送到其他节点上而不会丢失。Flume提供三种级别的可靠性保障,从强到弱依次分别为:end-to-end(收到数据agent首先将event写到磁盘上,当数据传送成功后,再删除;如果数据发送失败,可以重新发送),Store on failure(这也是scribe采用的策略,当数据接收方crash时,将数据写到本地,待恢复后,继续发送),Best effort(数据发送到接收方后,不会进行确认)。
2、可扩展性
Flume采用三层架构,分别为agent,collector和storage,每一层均可以水平扩展。所有agent和collector由master统一管理,这使得系统容易监控和维护,且master允许有多个(使用ZooKeeper进行管理和负载均衡),避免单点故障问题。
适用场景
日志—>Flume—>实时计算(如kafka/MQ+Storm/Spark Streaming)
日志—>Flume—>离线计算(如ODPS、HDFS、HBase)
日志—>Flume—>ES等
Source
Spooling Directory Source
- 采集文件夹数据到HDFS,写到HDFS上的文件大小最好是100M左右,比blocksize的默认值(128M)略低
- 一般使用rolllnterval、rollSize来控制文件的生成,哪个先触发就会生成HDFS文件,将根据条数的roll关闭
- rollSize控制的大小是指的压缩前的,所以若HDFS文件开启压缩配置,则需调大rollsize的大小
- 当文件夹下的某个文件被采集到HDFS上,会有个
.complete
的标志 - 采集文件数据时若该文件数据已经被采集,再对该文件做修改是会报错并停止,其次若放进去一个已经完成采集的同名数据文件也是会报错停止的
- 写HDFS数据可按照时间分区,注意该时间刻度内无数据则不会生成该时间文件夹
- 生成的文件名称默认是前缀+时间戳,这个是可以更改的
Taildir Source
- 采集文件夹数据到HDFS,Flume1.7新推出,CDH Flume1.6有集成进来
- 高可靠(reliable)的source,会实时的将文件偏移量写到json文件中并保存到磁盘。重启Flume时会读取Json文件获取文件IO偏移量,然后从之前的位置读取数据,保证数据零丢失
- 可同时监控多个文件夹以及文件,即使文件在实时写入数据
- 也无法采集递归文件下的数据,这需要改造源码
- 监控一个文件夹下的所有文件一定要用
.*
正则
其他
- HTTP Source
- Kafka Source
配置文件示例:
Channel
Channel被设计为Event中转临时缓冲区,存储Source收集并且没有被Sink读取的Event,为平衡Source收集和Sink读取数据的速度,可视为Flume内部的消息队列。Channel线程安全并且具有事务性,支持source写失败重复写和sink读失败重复读等操作。
常用的Channel:
- Memory channel:缓存到内存中
- JDBC channel:通过JDBC缓存到关系型数据库中
- Kafka channel:缓存到Kafka中
- File Channel:缓存到本地文件中
Sink
缓存的数据最终需要进行保存,Sink组件用来保存数据。部分Sink:
- HDFS sink:保存到HDFS中
- HBase Sink:保存到HBase中
- Hive Sink:保存到Hive中
- Kafka Sink:保存到Kafka中
配置文件示例:
a1.sinks.r1.type = hdfs
a1.sinks.r1.hdfs.path = hdfs://cdh5/tmp
a1.sinks.r1.hdfs.filePrefix = johnny_%{static_key}
a1.sinks.r1.hdfs.fileSuffix = .log
a1.sinks.r1.hdfs.fileType = DataStream
a1.sinks.r1.hdfs.useLocalTimeStamp = true
a1.sinks.r1.hdfs.writeFormat = Text
a1.sinks.r1.hdfs.rollCount = 0
a1.sinks.r1.hdfs.rollSize = 0
a1.sinks.r1.hdfs.rollInterval = 600
a1.sinks.r1.hdfs.batchSize = 500
a1.sinks.r1.hdfs.threadsPoolSize = 10
a1.sinks.r1.hdfs.idleTimeout = 0
a1.sinks.r1.hdfs.minBlockReplicas = 1
a1.sinks.r1.channel = fileChannel
Interceptor
拦截器,用户Source读取events发送到Sink时,在events header中加入一些有用的信息,或对events的内容进行过滤,或将读取的数据按照业务类型分开存储,完成初步的数据清洗。
org.apache.flume.interceptor.Interceptor
接口源码:
public interface Interceptor {
void initialize();
Event intercept(Event event);
List intercept(List events);
void close();
interface Builder extends Configurable {
Interceptor build();
}
}
通过实现Interceptor来自定义拦截器,用户可以通过该节点定义规则来修改或者丢弃事件。Flume支持链式拦截,通过在配置中指定构建的拦截器类的名称,在source的配置中,拦截器被指定为一个以空格为间隔的列表,它按照指定的顺序调用,一个拦截器返回的事件列表被传递到链中的下一个拦截器,当一个拦截器要丢弃某些事件时,拦截器只需要在返回事件列表时不返回该事件即可,若拦截器要丢弃所有事件,则其返回一个空的事件列表。
Flume-ng 1.6中目前提供以下拦截器:
- Timestamp Interceptor,将时间戳插入到Flume的事件报头中。Source连接到时间戳拦截器的配置:
a1.sources.r1.interceptors=timestamp
a1.sources.r1.interceptors.timestamp.type=timestamp
a1.sources.r1.interceptors.timestamp.preserveExisting=false
- Host Interceptor,插入服务器的ip地址或者主机名,agent将这些内容插入到事件的报头中。Source连接到主机拦截器的配置:
a1.sources.r1.interceptors=host
a1.sources.r1.interceptors.host.type=host
a1.sources.r1.interceptors.host.useIP=false
a1.sources.r1.interceptors.timestamp.preserveExisting=true
- Static Interceptor,将k/v插入到事件的报头中。Source连接到静态拦截器的配置:
a1.sources.r1.interceptors = static
a1.sources.r1.interceptors.static.type=static
a1.sources.r1.interceptors.static.key=logs
a1.sources.r1.interceptors.static.value=logFlume
a1.sources.r1.interceptors.static.preserveExisting=false
- UUID Interceptor:用于在每个events header中生成一个UUID字符串
- Morphline Interceptor:使用Morphline对每个events数据做相应的转换
- Search and Replace Interceptor:用于将events中的正则匹配到的内容做相应的替换;
- Regex Filtering Interceptor:过滤掉不需要的日志,也可以根据需要收集满足正则条件的日志;
Source连接到正则过滤拦截器的配置:
a1.sources.r1.interceptors=regex
a1.sources.r1.interceptors.regex.type=REGEX_FILTE
# 匹配除“\n”之外的任何字符
a1.sources.r1.interceptors.regex.regex=.*
# false默认收集匹配到的事件;若为true,则会删除匹配到的event,收集未匹配到的
a1.sources.r1.interceptors.regex.excludeEvents=false
- Regex Extractor Interceptor:使用正则表达式抽取原始events中的内容,并将该内容加入events header中。
安装
事务
Flume事务可用于保证数据的可靠性。下图的数据流是spooling directory source-> memory channel-> kafka sink,memory channel维护两个事务:PUT事务和Take事务。
- PUT事务
- 批量数据循环PUT到putList中;
- Commit,把putList队列中的数据offer到queue队列中,然后释放信号量,清空putList队列;
- Rollback,清空putList队列。
- Take事务
- 检查takeList队列大小是否够用,从queue队列中poll;
- Event到takeList队列中;
- Commit,表明被Sink正确消费掉,清空takeList队列;
- Rollback,异常出现,则把takeList队列中的Event返还到queue队列顶部。
监控
作为一个采集数据和日志的应用,只有自身不间断健康运行,才能保证其他系统可用性。故而,对Flume的监控就显得很重要。
使用Flume实时收集日志的过程中,尽管有事务机制保证数据不丢失,但仍然需要时刻关注Source、Channel、Sink之间的消息传输是否正常,比如,Source到Channel传输多少消息,Channel到Sink又传输多少,两处的消息量是否偏差过大等等。
Flume提供Monitor机制,通过Reporting的方式,把过程中的Counter都打印出来。有4种Reporting方式,JMX Reporting、Ganglia Reporting、JSON Reporting、Custom Reporting。
这里以最简单的JSON Reporting为例,在启动Flume Agent时,增加两个参数:
flume-ng agent -n agent_centos113 –conf . -f agent_centos113_file_2_kafka.properties -Dflume.monitoring.type=http -Dflume.monitoring.port=34545
flume.monitoring.type=http
指定Reporting的方式为http,flume.monitoring.port
指定http服务的端口号
启动后,会在Flume Agent所在的机器上启动http服务,http://<hostname>:34545/metrics
打开该地址后,返回一段JSON:
{
"SINK.sink_centos113":{
"ConnectionCreatedCount":"0",
"BatchCompleteCount":"0",
"BatchEmptyCount":"72",
"EventDrainAttemptCount":"0",
"StartTime":"1518400034824",
"BatchUnderflowCount":"43",
"ConnectionFailedCount":"0",
"ConnectionClosedCount":"0",
"Type":"SINK",
"RollbackCount":"0",
"EventDrainSuccessCount":"244",
"KafkaEventSendTimer":"531",
"StopTime":"0"
},
"CHANNEL.file_channel_centos113":{
"Unhealthy":"0",
"ChannelSize":"0",
"EventTakeAttemptCount":"359",
"StartTime":"1518400034141",
"Open":"true",
"CheckpointWriteErrorCount":"0",
"ChannelCapacity":"10000",
"ChannelFillPercentage":"0.0",
"EventTakeErrorCount":"0",
"Type":"CHANNEL",
"EventTakeSuccessCount":"244",
"Closed":"0",
"CheckpointBackupWriteErrorCount":"0",
"EventPutAttemptCount":"244",
"EventPutSuccessCount":"244",
"EventPutErrorCount":"0",
"StopTime":"0"
},
"SOURCE.source_centos113":{
"EventReceivedCount":"244",
"AppendBatchAcceptedCount":"45",
"Type":"SOURCE",
"AppendReceivedCount":"0",
"EventAcceptedCount":"244",
"StartTime":"1518400034767",
"AppendAcceptedCount":"0",
"OpenConnectionCount":"0",
"AppendBatchReceivedCount":"45",
"StopTime":"0"
}
}
三个JSON对象分别打印出三个组件的Counter信息:
SOURCE中"EventReceivedCount":"244"
表示SOURCE从文件中读取到244条消息;
CHANNEL中"EventPutSuccessCount":"244"
表示成功存放244条消息;
SINK中"EventDrainSuccessCount":"244"
表示成功向Kafka发送244条消息。
性能优化
一个Flume进程就是一个Agent,性能调优主要是Flume的参数配置,Flume agent配置分为三个部分:Source、Channel、Sink。
-
Source
- 增加Source个数(使用tairDirSource时可增加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参数;byteCapacity是Channel的内存大小,单位是byte。
-
Sink
- 增加Sink的个数可以增加Sink消费event的能力。Sink也不是越多越好,够用就行,Sink过多会占用系统资源,造成不必要的浪费。
- batchSize参数决定Sink一次批量从Channel读取的event条数,适当调大这个参数可以提高Sink从Channel搬出event的性能。
问题
- Flume的停止
使用kill停止Flume进程,不可使用kill -9
,Flume内部注册有很多钩子函数执行善后工作,kill -9
会导致钩子函数不执行,使用kill时,Flume内部进程会监控到用户的操作,然后调用钩子函数,执行一些善后操作,正常退出。 - Flume数据丢失
Flume可能丢失数据的情况是Channel采用memoryChannel,agent宕机导致数据丢失,或Channel存储数据已满,导致Source不再写入,未写入的数据丢失。另外,Flume有可能造成数据的重复,例如数据已经成功由Sink发出,但是没有接收到响应,Sink会再次发送数据,此时可能会导致数据的重复。 - Sink从Channel中读取数据的方式
默认情况下,Sink获取数据的方式是:当Source向Channel发送一条数据的时候,Sink会通过循环的方式获取一条数据,然后再发送给客户端。
Sink可以分为KafkaSink和AvroSink, 它们都是通过循环的方式获取数据,但是 KafkaSink可以通过配置topic进行批量从客户端读取。但原理还是一条一条的从Channel读取数据,只是在Sink中存在缓存机制,当数据量达到某一数量的时候,会将数据批量发送到客户端。 - CPU占用过高
若程序运行出现CPU占用过高的现象,则可在代码中加入休眠sleep,这样的话,就可以释放CPU资源;内存资源不会释放,因为线程还未结束,是可用状态。