目录
一、Flume内部原理
Flume内部从Source -> Channel -> Sink,中间会先后经历拦截器和选择器;
(1)Event:一个数据单元,也是Flume数据传输的基本单元,事务类型;
包括一个可选的消息头header,容纳key-value对的HashMap类型(name,mapping),一般为空;
name是header的名字,mapping是header的内容;可以加header标志然后通过拦截器和选择器来将不同header对应的数据输入不同Channel;
header对应一个载有数据的byte Array类型的body,即字节数组。
★ header(name,mapping)-> body(byte Array),逻辑是从body挑选特定字段,作为header的mapping进行拦截选择。
ps:Kafka的消息没有header,所以Flume的消息进入Kafka后,header就会丢失。
(2)拦截器Interceptor负责拦截配置好的header;
在配置文件中写明header的名称;
在IDEA中编写拦截器类,打成jar包放入flume安装目录下的lib目录中,可以拦截对应的header的数据。
(3)选择器Selector负责依据Header的Value决定将数据传入哪个Channel;
选择器有两种类型:
Replicating(default),会将source发来的event发往所有的channel,
Multiplexing,可以配置发往指定channel。
二、Interceptor和Selector配置文件案例
#interceptor
agent-hdfs.sources.sc1.interceptors=i1
agent-hdfs.sources.sc1.interceptors.i1.type=fi.MyInterceptor$Builder
#selector
agent-hdfs.sources.sc1.selector.type = multiplexing
agent-hdfs.sources.sc1.selector.header= logType
agent-hdfs.sources.sc1.selector.mapping.startup = ch1
agent-hdfs.sources.sc1.selector.mapping.event = ch2
agent-hdfs.sources.sc1.selector.default = ch2
其中Interceptor的type是指执行jar包中fi包下MyInerceptor.class中内部类Builder.class;
Selector中type为multiplexing,自定义channel;
定义header名为logType,header =(key,mapping);
当mapping为startup时,走channel1;当mapping为event时,走channel2;其余默认走channel2。
三、自定义拦截器案例(IDEA)
需要先实现Interceptor这个接口,并实现其中方法;
其中的内部类Builder.class需要实现Interceptor.Builder这个接口,并实现其中方法;
案例如下,将代码打成jar包放入flume安装目录下的lib目录下即可
package fi;
import com.google.gson.Gson;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//拦截器类
public class MyInterceptor implements Interceptor {
//配置文件中定义event的header名为logType
public static final String FI_HEADER_TYPE = "logType";
public static final String FI_HEADER_TYPE_STARTUP = "startup";
public static final String FI_HEADER_TYPE_EVENT = "event";
@Override
public void initialize() {
}
/*
完整event的body:{"area":"shanghai","uid":"166","os":"andriod","ch":"360",
"appid":"gmall0901","mid":"mid_351","type":"startup","vs":"1.2.0"}
*/
@Override
public Event intercept(Event event) {
//1. 从event获取字节数组类型的Body,再根据body中数据类型,给body加上对应header
String logString = new String(event.getBody());
//2. 将String类型的body变成Json对象
Gson gson = new Gson();
HashMap logMap = gson.fromJson(logString, HashMap.class);
//3. 数据中包含"type":"startup"和"type":"event"
//从Json格式的body中获取type对应的值:startup或者event,封装成对象value
String value = (String) logMap.get("type");
/**
* 4. 创建event的header,
* 如果value对象为startup,则打个header标志(logType,startup)
* 如果vlaue对象为event,则打个header标志(logType,event)
*/
Map<String, String> headers = event.getHeaders();
if (FI_HEADER_TYPE_STARTUP.equals(value)) {
headers.put(FI_HEADER_TYPE, FI_HEADER_TYPE_STARTUP);
} else {
headers.put(FI_HEADER_TYPE, FI_HEADER_TYPE_EVENT);
}
//5. 返回打好header标志的event
return event;
}
//批量操作
@Override
public List<Event> intercept(List<Event> list) {
for (Event event : list) {
intercept(event);
}
return list;
}
@Override
public void close() {
}
/**
* 通过该静态内部类来创建自定义对象供flume使用,实现Interceptor.Builder接口,并实现其抽象方法
*/
public static class Builder implements Interceptor.Builder{
//该方法主要用来返回创建的自定义拦截器类
@Override
public Interceptor build() {
return new MyInterceptor();
}
@Override
public void configure(Context context) {
//可以通过context得到flume.conf中设置的参数,传递给Interceptor
}
}
}