3、自定义组件及源码轻度分析

自定义组件

Flume可以对部分组件实现自定义,自定义时根据Flume版本导入flume-ng-core

自定义Source

getChannelProcessor().processEvent(event);自定义source主要是调用channelProcessor将event写入channel之中。

package cn.lpc.myflume;
/**
 * 项目名:MyFlume
 * 描述:自定义Source
 * @author : Lpc
 * @date : 2019-12-05 13:52
 **/
public class MySource extends AbstractSource implements Configurable, PollableSource {
    String field;
    public void configure(Context context) {
        field=context.getString("field","default");
    }

    public Status process() throws EventDeliveryException {
        // 创建事件头部信息
        try {
            HashMap<String, String> headMap = new HashMap<String, String>();

            SimpleEvent event = new SimpleEvent();
            for (int i = 0; i < 10; i++) {

                event.setBody((field+i).getBytes());
                event.setHeaders(headMap);
                getChannelProcessor().processEvent(event);
                Thread.sleep(10000);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Status.BACKOFF;
        }
        return Status.READY;
    }

    public long getBackOffSleepIncrement() {
        return 0;
    }

    public long getMaxBackOffSleepInterval() {
        return 0;
    }
}

在写Source时观察了一下source的put流程

  1. agent在启动时,调用了PollableSourceRunner.start()。因此source要PollableSource接口。
  2. 启动一个线程,这个线程为PollingRunner,PollingRunner负责启动和停止Source,由 PollingRunner初始化Source。
  3. 一旦有新的数据,调用source封装event,一个source必须实现 process(),这个方法是最核心的方法,它负责发现新的数据,存储到event!
  4. 调用getChannelProcessor().processEventBatch(events);
  5. 在processEventBatch()中,先调用拦截器,处理Events
  6. 使用channelselector获取当前source对应的必须的channel,向channel的dataQuene中,放入处理好的event
  7. 循环每一个event!,调用channel.put(event); 调用Channel中的transaction对象的doPut(event);将event移动到putList中!
  8. 一批event放完之后,执行事务的commit();清空putlist(缓存)!
  9. 如果发生异常,调用rollback(),将之前放入到channel中的一批事务中的event回滚。

自定义Sink

package cn.lpc.myflume;

import org.apache.flume.*;

import org.apache.flume.conf.Configurable;
import org.apache.flume.sink.AbstractSink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 项目名:MyFlume
 * 描述:自定义sink
 *
 * @author : Lpc
 * @date : 2019-12-05 14:36
 **/
public class MySink  extends AbstractSink implements Configurable {

    private Logger logger = LoggerFactory.getLogger(MySink.class);

    public Status process() throws EventDeliveryException {
        Status status = Status.READY;
        //获取管道
        Channel ch=getChannel();
        //获取事务
        Transaction tr = ch.getTransaction();
        try {
            //开启事务
            tr.begin();
            Event take = ch.take();

            if (take==null){
                tr.rollback();
                return Status.BACKOFF;
            }else {

                logger.info(take.getBody().toString()+"sink");
                tr.commit();
            }
        } catch (ChannelException e) {
            e.printStackTrace();
            tr.rollback();
            status= Status.BACKOFF;
        }finally {
            if (tr!=null){

                tr.close();
            }
        }

        return status;

    }

    public void configure(Context context) {

    }
}

sink的事务最为致命

自定义拦截器

package cn.lpc.myflume;

/**
 * 项目名:MyFlume
 * 描述:自定义拦截器,配合自定义的source使用,作用是在每条语句后加一
 *
 * @author : Lpc
 * @date : 2019-12-05 14:14
 **/
public class MyInterceptor implements Interceptor {
    public void initialize() {

    }
    public Event intercept(Event event) {
        byte[] body = event.getBody();
        String sBody = new String(body);

        event.setBody( (sBody+"intercept").getBytes());
        return event;

    }

    public List<Event> intercept(List<Event> events) {
        for (Event event : events) {
            intercept(event);
        }
        return events;
    }

    public void close() {

    }
    public static class Builder implements Interceptor.Builder {

        private boolean preserveExisting;
        private String key;
        private String value;
        public void configure(Context context) {
        }
        public Interceptor build() {
          return new MyInterceptor();
        }

    }
}

实现Interceptor接口。initialize和close分别再拦截器初始和关闭时调用。初始化时可以实现configorable接口。调用配置的参数。主要的方法是intercept(),处理一个event。在最后还需要实现Builder。flume通过调用builder获取拦截器对象。配置时为a1.sources.s1.interceptors.i1.type="全类名$Builder"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值