背景
在了解了flume的工作原理之后,在一定程度上可能会有自定义输入源和输出目的地的需求,因此本文做了一个简单的demo,以备后查
自定义Source
Source是负责接收数据到Flume Agent的组件。Source组件可以处理各种类型、各种格式的日志数据,包括avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy。官方提供的source类型已经很多,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些source
概述
Flume 1.10.0 Developer Guide — Apache Flume根据官方说明自定义MySource需要继承AbstractSource类并实现Configurable和PollableSource接口。
实现相应方法:
getBackOffSleepIncrement()//暂不用
getMaxBackOffSleepInterval()//暂不用
configure(Context context)//初始化context(读取配置文件内容)
process()//获取数据封装成event并写入channel,这个方法将被循环调用。
使用场景:读取MySQL数据或者其他文件系统
案例需求
自定义source,模拟数据源,并给每条数据添加前缀,输出到控制台。前缀可从flume配置文件中配置
编码
1.创建一个快速maven工程
2.增加pom依赖
PS: 版本最好和客户端版本一直,否则可能出现不兼容的情况
org.apache.flume
flume-ng-core
1.9.0
package com.flume;
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;
/**
*
* 功能描述:自定义的source需要继承以下类,并实现其中的方法
*
*
* @author MILLA
* @version 1.0
* @since 2022/06/15 10:50
*/
public class MyFlumeSource extends AbstractSource implements Configurable, PollableSource {
//定义配置文件将来要读取的字段
private Long delay;
private String field;
/**
* @return 接收数据将数据封装成event,写入channel
* @throws EventDeliveryException
*/
@Override
public Status process() throws EventDeliveryException {
try {
//创建事件头信息
HashMap headerMap = new HashMap<>(16);
//创建事件
SimpleEvent event = new SimpleEvent();
//循环封装事件
for (int i = 0; i < 5; i++) {
//给事件设置头信息
event.setHeaders(headerMap);
//给事件设置内容
event.setBody((field + "-" + i).getBytes());
//将事件写入channel
getChannelProcessor().processEvent(event);
Thread.sleep(delay);
}
} catch (Exception e) {
return Status.BACKOFF;
}
return Status.READY;
}
@Override
public long getBackOffSleepIncrement() {
return 0;
}
@Override
public long getMaxBackOffSleepInterval() {
return 0;
}
/**
* 从配置文件中获取一些固定的配置
*
* @param context
*/
@Override
public void configure(Context context) {
delay = context.getLong("delay");
field = context.getString("field", "I am a default value");
}
}
3.打包之后,将生生成的jar拷贝到flume/lib文件下
mvn clean package -DskipTests
创建flume配置
vi mysource.conf
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = com.flume.MyFlumeSource
a1.sources.r1.delay = 1000
a1.sources.r1.field = customerSource
# Describe the sink
a1.sinks.k1.type = logger
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
启动任务查看效果
../../apache-flume-1.9.0-bin/bin/flume-ng agent \
-c ../../apache-flume-1.9.0-bin/conf/ \
-n a1 \
-f mysource.conf -Dflume.root.logger=INFO,console
注释掉mysource.conf中的a1.sources.r1.field = customerSource配置,重新启动效果如下
自定义Sink
Sink不断地轮询Channel中的事件且批量地移除它们,并将这些事件批量写入到存储或索引系统、或者被发送到另一个Flume Agent。
Sink是完全事务性的。在从Channel批量删除数据之前,每个Sink用Channel启动一个事务。批量事件一旦成功写出到存储系统或下一个Flume Agent,Sink就利用Channel提交事务。事务一旦被提交,该Channel从自己的内部缓冲区删除事件。
Sink组件目的地包括hdfs、logger、avro、thrift、ipc、file、null、HBase、solr、自定义。官方提供的Sink类型已经很多,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些Sink
概述
官方也提供了自定义source的接口:
Flume 1.10.0 Developer Guide — Apache Flume根据官方说明自定义MySink需要继承AbstractSink类并实现Configurable接口。
实现相应方法:
configure(Context context)//初始化context(读取配置文件内容)
process()//从Channel读取获取数据(event),这个方法将被循环调用。
使用场景:读取Channel数据写入MySQL或者其他文件系统
案例需求
使用flume接收数据,并在Sink端给每条数据添加前缀和后缀,输出到控制台。前后缀可在flume任务配置文件中配置
编码
在上一个工程上增加自定义Sink代码
package com.flume;
import org.apache.flume.Channel;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.EventDeliveryException;
import org.apache.flume.Transaction;
import org.apache.flume.conf.Configurable;
import org.apache.flume.sink.AbstractSink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* 功能描述:自定义的sink
*
*
* @author MILLA
* @version 1.0
* @since 2022/06/15 11:33
*/
public class MyFlumeSink extends AbstractSink implements Configurable {
private static final Logger LOG = LoggerFactory.getLogger(AbstractSink.class);
private String prefix;
private String suffix;
@Override
public Status process() throws EventDeliveryException {
//声明返回值状态信息
Status status;
//获取当前Sink绑定的Channel
Channel ch = getChannel();
//获取事务
Transaction txn = ch.getTransaction();
//声明事件
Event event;
//开启事务
txn.begin();
//读取Channel中的事件,直到读取到事件结束循环
while (true) {
event = ch.take();
if (event != null) {
break;
}
}
try {
//处理事件(打印)
LOG.info("Sink输出: " + prefix + new String(event.getBody()) + suffix);
//事务提交
txn.commit();
status = Status.READY;
} catch (Exception e) {
//遇到异常,事务回滚
txn.rollback();
status = Status.BACKOFF;
} finally {
//关闭事务
txn.close();
}
return status;
}
@Override
public void configure(Context context) {
//读取配置文件内容,有默认值
prefix = context.getString("prefix", "hello:");
//读取配置文件内容,无默认值
suffix = context.getString("suffix");
}
}
创建flume配置
vi mysink.conf
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
# 指定自定义的source
a1.sources.r1.type = com.flume.MyFlumeSource
a1.sources.r1.delay = 1000
a1.sources.r1.field = o(∩_∩)o
# Describe the sink
# 指定自定义的sink
a1.sinks.k1.type =com.flume.MyFlumeSink
a1.sinks.k1.prefix = pre-
a1.sinks.k1.suffix = -suf
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
启动任务
../../apache-flume-1.9.0-bin/bin/flume-ng agent \
-c ../../apache-flume-1.9.0-bin/conf/ \
-n a1 \
-f mysink.conf -Dflume.root.logger=INFO,console
执行效果
总结
自定义的数据源可以换成从数据库、文件系统、爬虫等等
自定义的输出可以是写入数据库,文件系统等等
同时也将自定义的数据源和自定义的输出整合了起来