flume笔记(四)之 自定义Interceptor、Source、Sink

一.自定义-Interceptor

1.案例概述

  首先flume在实际开发中的日志处理的要去各不相同,然而官方所给的案例不能满足我实际开发者的要求,所以就有了自定义Interceptor这个概念。它需要按照日志类型的不同,将不同种类的日志发往不同的分析系统。
  而下面的一个小案例我采用的的拓扑结构是Multiplexing 结构。这个前面的文章中也提到过。其原理是根据event 中 Header 的某个 key 的值,将不同的 event 发送到不同的 Channel中,所以我们需要自定义一个 Interceptor,为不同类型的 event 的 Header 中的 key 赋予不同的值。
  我门闲话少说直接上案例,该案例使用自定义拦截器将是否包含hello信息发送给不同分析系统。

2.实现步骤

2.1.创建一个maven 项目,并引入以下依赖。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>
<dependencies>
    <dependency>
        <groupId>org.apache.flume</groupId>
        <artifactId>flume-ng-core</artifactId>
        <version>1.7.0</version>
    </dependency>
</dependencies>

2.2.定义 TestInterceptor类并实现 Interceptor 接口。然后将其打包将jar放入虚拟机中flume安装目录的lib文件夹。代码如下:

import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class TestInterceptor implements Interceptor{
    //声明一个存放事件的集合
    private List<Event> addHeaderEvents;

    //初始化
    @Override
    public void initialize() {
        //初始化
        addHeaderEvents = new ArrayList<>();
    }

    //单个事件拦截
    @Override
    public Event intercept(Event event) {
        //1.获取事件中的头信息
        Map<String, String> headers = event.getHeaders();
        //2.获取事件中的body信息
        String body = new String(event.getBody());   //因为getBody为字节流byte[]
        //3.根据body中是否有“hello”来决定添加怎样的信息
        if (body.contains("hello")){
            //添加头部信息
            headers.put("type","Hello");
        }else {
            //添加头部信息
            headers.put("type","NoHello");
        }
        return event;
    }

    //批量事件拦截
    @Override
    public List<Event> intercept(List<Event> list) {
        //1.清空集合
        addHeaderEvents.clear();
        //2.遍历events
        for (Event event:list) {
            addHeaderEvents.add(intercept(event));
        }
        //3.返回结果
        return addHeaderEvents;
    }

    @Override
    public void close() {
    }

    public static class Builder implements Interceptor.Builder{
        @Override
        public Interceptor build() {
            return new TestInterceptor();
        }

        @Override
        public void configure(Context context) {
        }
    }
}

2.3.在hadoop-1上编辑flume-netcat-flume.conf 配置文件。配置1个netcat source,2个avro sink和相应的ChannelSelector 和 interceptor。代码如下:

# name
a1.sources = r1
a1.channels = c1 c2 
a1.sinks = k1 k2 

# source 
a1.sources.r1.type = netcat 
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444

# interceptors
a1.sources.r1.interceptors = i1
# TestInterceptor自定义拦截器的全类名 和  Builder静态内部类的名称
a1.sources.r1.interceptors.i1.type = TestInterceptor$Builder

# channel  selector
a1.sources.r1.selector.type = multiplexing
# 注意 该值要和自定义拦截器中设置的 header 一致,我设置的是type
a1.sources.r1.selector.header = type
# 这里也是同理  官方给的是a1.sources.r1.selector.mapping.CZ 而我设置的为 Hello
a1.sources.r1.selector.mapping.Hello = c1
# 官方给的是a1.sources.r1.selector.mapping.US 而我设置的为 NoHello
a1.sources.r1.selector.mapping.NoHello = c2

# channel 
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

# Sink
a1.sink.k1.type = avro 
a1.sink.k1.hostname = hadoop-2
a1.sink.k1.port = 4142

a1.sink.k2.type = avro 
a1.sink.k2.hostname = hadoop-3
a1.sink.k2.port = 4142

# bind 
a1.sources.r1.channels = c1 c2 
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2

2.4.在hadoop-2上编辑flume-flume-console1.conf,配置一个 avro source 和一个 logger sink。代码如下:

#name
a2.sources = r1
a2.channels = c1
a2.sinks = k1 

#Source
a2.sources.r1.type = avro
a2.sources.r1.bind = hadoop-2
a2.sources.r1.port = 4142

#Channel
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100

#Sink
# 输出到控制台
a2.sinks.k1.type = logger

#Bind
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1

2.5.在hadoop-3上编辑flume-flume-console2.conf,配置一个 avro source 和一个 logger sink。代码如下:

#name
a3.sources = r1
a3.channels = c1
a3.sinks = k1 

#Source
a3.sources.r1.type = avro
a3.sources.r1.bind = hadoop-3
a3.sources.r1.port = 4142

#Channel
a3.channels.c1.type = memory
a3.channels.c1.capacity = 1000
a3.channels.c1.transactionCapacity = 100

#Sink
# 输出到控制台
a3.sinks.k1.type = logger

#Bind
a3.sources.r1.channels = c1
a3.sinks.k1.channel = c1

2.6.先启动hadoop-2 和 hadoop-3的flume配置文件,最后启动hadoop-1的flume配置文件。
2.7.在hadoop-1上测试 使用netcat端口 向localhost:44444 发送信息。
2.8.打印结果:如果发送的信息包含hello则在打印在hadoop-2上,否则打印在hadoop-3上。
总结:自定义拦截器在实际开发中用处还是非常大的,它可以完成各种数据处理的逻辑。

二.自定义-Source

1.案例概述

  官方提供的 source 类型已经很多,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些 source。因此官方提供了自定义 source 的接口。然而自定义Source 类中需要继AbstractSource 类并实现 Configurable 和 PollableSource 接口。
  使用 flume 接收数据,并给每条数据添加前缀和后缀,输出到控制台。前缀和后缀可从 flume 配置文件中配置。

2.实现步骤

2.1.定义一个TestSource 类继承继AbstractSource 类并实现 Configurable 和 PollableSource 接口。然后将其打包将jar放入虚拟机中flume安装目录的lib文件夹。代码如下:

import org.apache.flume.Context;
import org.apache.flume.EventDeliveryException;
import org.apache.flume.PollableSource;
import org.apache.flume.conf.Configurable;
import org.apache.flume.event.SimpleEvent;
import org.apache.flume.source.AbstractSource;

public class TestSource extends AbstractSource implements Configurable, PollableSource {

    //定义全局的前缀和后缀
    private String prefix;
    private String subifx;
    @Override
    public void configure(Context context) {

        //读取配置信息,给前后在赋值
        prefix = context.getString("prefix");

        subifx = context.getString("subifx","defaultValue");   //defaultValue 为默认值

    }

    /**
     * 1.接收数据(可以是数据库中的数据、或者自己造数据)
     * 2.将数据封装为事件
     * 3.将事件传给channel
     * @return
     * @throws EventDeliveryException
     */
    @Override
    public Status process() throws EventDeliveryException {
        //定义状态
        Status status = null;

        try {
            //1.接收数据
            for (int i = 0;i<5;i++){
                //2。构建事件对象
                SimpleEvent event = new SimpleEvent();

                //3.设置事件设置格式和值
                event.setBody((prefix+"---"+i+"---"+subifx).getBytes());

                //4.将事件传给channel
                getChannelProcessor().processEvent(event);

                status = Status.READY;
            }

        } catch (Exception e) {
            e.printStackTrace();
            status = Status.BACKOFF;
        }
        
        //休眠两秒
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return status;
    }

    @Override
    public long getBackOffSleepIncrement() {
        return 0;
    }

    @Override
    public long getMaxBackOffSleepInterval() {
        return 0;
    }
}

2.2.在hadoop-1上配置source.conf的flume配置文件,代码如下:

#name
a2.sources = r1
a2.channels = c1
a2.sinks = k1 

#Source
#上面代码的全类名
a2.sources.r1.type = TestSource
#自定义类中 configure 方法定义的变量名
a2.sources.r1.prefix = header   # 随便起名
a2.sources.r1.subfix = end	 # 随便起名

#Channel
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100

#Sink
# 输出到控制台
a2.sinks.k1.type = logger

#Bind
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1

2.3.在hadoop-1上启动source.conf配置文件,观察控制台的输出。

三.自定义-Sink

1.案例概述

  官方提供的 Sink 类型已经很多,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些 Sink。然而自定义Sink类中需要继AbstractSink 类并实现 Configurable 接口。
  使用 flume 接收数据,并在 Sink 端给每条数据添加前缀和后缀,输出到控制台。前后缀可在 flume 任务配置文件中配置。

2.实现步骤

2.1定义一个TestSink 类继承继AbstractSink 类并实现Configurable 接口。然后将其打包将jar放入虚拟机中flume安装目录的lib文件夹。代码如下:


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王博1999

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值