三十九、Flume自定义Source、Sink

上篇文章咱们基于Flume举了几个例子,包括它的扇入扇出等等。这篇文章我们主要来看一下怎样通过自定义Source和Sink来实现Flume的数据采集。关注专栏《破茧成蝶——大数据篇》,查看更多相关的内容~


目录

一、自定义Source

1.1 需求说明

1.2 编码实现

1.3 编写Flume配置文件

1.4 测试自定义的Source

二、自定义Sink

2.1 需求说明

2.2 代码实现

2.3 编写Flume的配置文件

2.4 测试自定义Sink


一、自定义Source

Source是负责接收数据到Flume Agent的组件,我们不仅可以根据Flume自身提供的API,实现Source的定义,还可以根据项目的实际需求,编写自己的Source,比如Source可以是从网络上下载一个文件,或者是从数据库中查询到的数据。Source组件可以处理各种类型、各种格式的日志数据,包括avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy等等。官方提供的source类型已经很多,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些Source。

自定义的Source有两种类型:PollableSource(轮训拉取)与EventDrivenSource (事件驱动)。两者的区别在于PollableSource是通过线程不断去调用process方法,主动拉取消息,而EventDrivenSource是需要触发一个调用机制,即被动等待。在利用PollableSource实现自定义Source时还需要实现Configurable接口,以便在项目中初始化某些配置。下面我们就以实现PollableSource为例进行自定义Source的说明。官方也提供了自定义source的接口,可以点击这里进行查看~

1.1 需求说明

使用Flume接收数据,自定义Source接收数据,并将数据输出到控制台。

1.2 编码实现

首先需要导入Maven依赖,如下所示:

        <dependency>
            <groupId>org.apache.flume</groupId>
            <artifactId>flume-ng-core</artifactId>
            <version>1.7.0</version>
        </dependency>

实现自定义Source的代码如下所示:

package com.xzw.source;

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;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: xzw
 * @create_date: 2021/1/14 15:24
 * @desc: 自定义source
 * @modifier:
 * @modified_date:
 * @desc:
 */
public class MySource extends AbstractSource implements Configurable, PollableSource {

    //定义需要从配置中读取的字段

    //两条数据之间的间隔
    private long delay;
    //模拟信息
    private String field;

    /**
     * 处理过程
     *
     * @return
     * @throws EventDeliveryException
     */
    public Status process() throws EventDeliveryException {
        try {
            Map<String, String> header = new HashMap<>();
            SimpleEvent event = new SimpleEvent();
            //拿到数据
            for (int i = 0; i < 5; i++) {
                event.setHeaders(header);
                event.setBody((field + i).getBytes());
                getChannelProcessor().processEvent(event);
                Thread.sleep(delay);
            }
        } catch (Exception e) {
            return Status.BACKOFF;
        }

        return Status.READY;
    }

    /**
     * 回滚之后睡眠增加多长时间(每回滚一次增加多长时间)
     *
     * @return
     */
    public long getBackOffSleepIncrement() {
        return 0;
    }

    /**
     * 最大的失败睡眠间隔
     *
     * @return
     */
    public long getMaxBackOffSleepInterval() {
        return 0;
    }

    /**
     * 配置方法
     *
     * @param context
     */
    public void configure(Context context) {
        delay = context.getLong("delay", 2000l);
        field = context.getString("field", "xzw");
    }

    public static void main(String[] args) {

    }
}

1.3 编写Flume配置文件

自定义flume-mysource.conf配置文件并添加如下内容:

a1.sources = r1
a1.sinks = k1
a1.channels = c1

a1.sources.r1.type = com.xzw.source.MySource
a1.sources.r1.delay = 5000
#a1.sources.r1.field = xzw

a1.sinks.k1.type = logger

a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

1.4 测试自定义的Source

将写好的代码打包上传到Flume的lib目录下,我们这里的路径是/opt/modules/flume/lib。使用如下命令启动Flume进行测试:

bin/flume-ng agent -c conf/ -f conf/flume-mysource.conf -n a1 -Dflume.root.logger=INFO,console

可以发现在控制天打印出了我们传输的数据:

二、自定义Sink

Sink组件目的地包括hdfs、logger、avro、thrift、ipc、file、null、HBase、solr等等,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些Sink。官方也提供了自定义source的接口,请点击这里进行查看~

2.1 需求说明

使用Flume接收数据,并在Sink端给每条数据添加前缀和后缀,最后将添加了后缀的数据输出到控制台。

2.2 代码实现

实现自定义Sink的代码如下所示:

package com.xzw.source;

import org.apache.flume.*;
import org.apache.flume.conf.Configurable;
import org.apache.flume.sink.AbstractSink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author: xzw
 * @create_date: 2021/1/15 10:09
 * @desc: 自定义sink
 * @modifier:
 * @modified_date:
 * @desc:
 */
public class MySink extends AbstractSink implements Configurable {

    //创建Logger对象
    private static final Logger LOG = LoggerFactory.getLogger(AbstractSink.class);

    //声明前缀和后缀
    private String prefix = "";
    private String suffix = "";

    @Override
    public Status process() throws EventDeliveryException {
        //声明返回值状态信息
        Status status = null;

        //获取当前sink绑定的channel
        Channel channel = getChannel();

        //获取事务
        Transaction transaction = channel.getTransaction();

        //开启事务
        transaction.begin();

        try {
            //声明事件
            Event take;
            while ((take = channel.take()) == null) {
                Thread.sleep(200);
            }

            //处理事件
            LOG.info(prefix + new String(take.getBody()) + suffix);

            //事务提交
            transaction.commit();
            status = Status.READY;
        } catch (Throwable e) {
            //当遇到异常的时候,回滚事务
            transaction.rollback();
            status = Status.BACKOFF;

            if (e instanceof Error) {
                throw (Error) e;
            }
        } finally {
            //关闭事务
            transaction.close();
        }

        return status;
    }

    @Override
    public void configure(Context context) {
        //读取配置文件内容,有默认值
        prefix = context.getString("prefix", "PREFIX:");
        //读取配置文件内容,没有默认值
        suffix = context.getString("suffix");

    }

    public static void main(String[] args) {

    }
}

2.3 编写Flume的配置文件

编写flume-mysink.conf配置文件,文件内容如下所示:

a1.sources = r1
a1.sinks = k1
a1.channels = c1

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

a1.sinks.k1.type = com.xzw.source.MySink
a1.sinks.k1.suffix = :SUFFIX

a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

2.4 测试自定义Sink

将编写好的代码打包上传到Flume的lib目录下,使用如下命令启动Flume:

bin/flume-ng agent -c conf/ -f conf/flume-mysink.conf -n a1 -Dflume.root.logger=INFO,console

通过测试可以发现,数据通过自定义的Sink输出到控制台:

 

OK,本文就介绍到这里,自定义的Source、Sink这部分比较简单,你们在这个过程中遇到了什么问题,欢迎留言,让我看看你们遇到了什么问题~

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Flume是一个分布式、可靠、可扩展的日志收集、聚合、传输系统。它使用拦截器来处理数据流,可以在数据流经过某个拦截器时对数据进行预处理、过滤、转换等操作。 下面给出一个自定义Flume拦截器,用于将数据转换为JSON格式。该拦截器可以将文本数据转换为JSON格式,并添加时间戳和其他元数据,方便后续处理和分析。 ```java package com.example.flume.interceptor; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.flume.Context; import org.apache.flume.Event; import org.apache.flume.interceptor.Interceptor; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class JSONInterceptor implements Interceptor { private Gson gson; @Override public void initialize() { gson = new GsonBuilder().create(); } @Override public Event intercept(Event event) { // 获取原始数据 String data = new String(event.getBody()); // 将数据转换为JSON格式 Map<String, Object> jsonMap = new HashMap<String, Object>(); jsonMap.put("timestamp", System.currentTimeMillis()); jsonMap.put("data", data); String json = gson.toJson(jsonMap); // 构造新的Event Event newEvent = EventBuilder.withBody(json.getBytes(), event.getHeaders()); return newEvent; } @Override public List<Event> intercept(List<Event> events) { List<Event> interceptedEvents = new ArrayList<Event>(); for (Event event : events) { interceptedEvents.add(intercept(event)); } return interceptedEvents; } @Override public void close() { // do nothing } public static class Builder implements Interceptor.Builder { @Override public void configure(Context context) { // do nothing } @Override public Interceptor build() { return new JSONInterceptor(); } } } ``` 上述代码,我们首先在`initialize()`方法创建了一个Gson对象,用于将数据转换为JSON格式。然后在`intercept()`方法,我们获取原始数据,将其封装成一个Map对象,并添加时间戳等元数据。接着使用Gson将Map对象转换为JSON格式,并构造一个新的Event对象返回。 最后,我们还需要在Flume的配置文件添加相关配置,以启用该拦截器: ```conf agent.sources = source1 agent.sinks = sink1 agent.channels = channel1 agent.sources.source1.type = netcat agent.sources.source1.bind = localhost agent.sources.source1.port = 44444 agent.sinks.sink1.type = logger agent.channels.channel1.type = memory # 添加JSONInterceptor拦截器 agent.sources.source1.interceptors = i1 agent.sources.source1.interceptors.i1.type = com.example.flume.interceptor.JSONInterceptor$Builder agent.sources.source1.channels = channel1 agent.sinks.sink1.channel = channel1 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

象在舞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值