flume日志收集系统
概述
Flume是一个分布式的、可靠的、高可用的海量日志采集系统。它能够将不同数据源的海量日志数据进行高效收集、聚合、移动,最后存储到一个中心化数据存储系统中。能够做到实时推送事件,并且可以满足数据量是持续且量级很大的情况。
基本组件
Flume传输的数据的基本单位是event,如果是文本文件,通常是一行记录,这也是事务的基本单位,代表着一个数据流的最小完整单元。flume运行的核心是agent。它是一个完整的数据收集工具,含有三个核心组件,分别是source、channel、sink。Event从Source,流向Channel,再到Sink,本身为一个byte数组,并可携带headers信息。基本流程如下:
-
1.Source
Source主要负责接收数据到Flume Agent组件,可以从其他系统或者应用程序中接收数据,比如web server、log4j等。也可以是从其他Agent的Sink通过RPC发送的数据 -
2.Channel
Channel充当了Source与Sink之间的缓冲区,使得source与sink之间的藕合度降低,source只管向Channel发数据,sink只需从Channel取数据,有点类似于队列的功能。Agent缓冲已经接收,但尚未写出到另一个Agent或者存储系统的数据。多个Source可以同时写入到一个Channel,多个Sink也可以从相同的Channel读取,但是一个Sink只能从一个Channel中读取。它允许Source和Sink可以工作在不同的速率,使得flume可以处理Source 高峰时的负载,即使此时Sink无法读取Channel。
Channel有多种方式:有MemoryChannel、KafkaChannel、JDBCChannel、FileChannel等。
Memory Channel 实现是一个内存缓冲区,性能比较好,若JVM或者机器重启,Channel冲的任何数据都将丢失。如果允许数据小量丢失,推荐使用;
KafkaChannel 是用Kafka作为Channel,即就是将数据保存在kafka中。
File Channel,event 保存在本地磁盘中,可靠性高,只要磁盘上存储的数据仍然是起作用的和可访问的,就不会丢失数据,但吞吐量低于Memory Channel;
JDBC Channel,event保存在关系数据中,一般不推荐使用;
- 3.Sink
Sink主要是移除Channel中的数据并写入到另一个Agent或者数据存储或者一些其他系统的组件中。Sink会连续的轮询Channel中的事件,将事件传送到下一个目的地,一旦成功传递后,Sink就会通知Channel将该事件删除,这些都是依据于flume中的事务机制实现的。
flume event
flume中event是数据传输的基本单元,由消息头header和消息体body组成,其定义接口如下:
//所在文件:flume-ng-sdk\src\main\java\org\apache\flume\Event.java
public interface Event {
/**
* Returns a map of name-value pairs describing the data stored in the body.
*/
public Map<String, String> getHeaders();
/**
* Set the event headers
* @param headers Map of headers to replace the current headers.
*/
public void setHeaders(Map<String, String> headers);
/**
* Returns the raw byte array of the data contained in this event.
*/
public byte[] getBody();
/**
* Sets the raw byte array of the data contained in this event.
* @param body The data.
*/
public void setBody(byte[] body);
}
可以看出header类型为key-value的Map集合,body为byte字节数组类型。消息头header并不是用来传输数据的,只是为了路由和跟踪发送事件的优先级和严重性,还可以给事件添加事件ID等,接下来看下event的基本实现,主要就是实现了header、body两部分的设置,以及toString方法的重写:
public class SimpleEvent implements Event {
private Map<String, String> headers;
private byte[] body;
public SimpleEvent() {
headers = new HashMap<String, String>();
body = new byte[0];
}
@Override
public Map<String, String> getHeaders() {
return headers;
}
@Override</