浅探Flume安装、使用和自定义实现
一、浅谈Flume
flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(比如文本、HDFS、Hbase等)的能力 。
一些概念:
Event:一个数据单元(传输单元),消息头和消息体组成。(Events可以是日志记录、 avro 对象等。)
Agent:一个独立的Flume进程,包含组件Source、Channel、Sink。(Agent使用JVM 运行Flume。每台机器运行一个agent,但是可以在一个agent中包含多个sources和sinks。)
Source: 数据收集组件。(source从Client收集数据,传递给Channel)
Channel: 中转Event的一个临时存储,保存由Source组件传递过来的Event。(Channel连接 sources 和 Sinks ,这个有点像一个队列。MemoryChannel可以实现高速的吞吐,但是无法保证数据的完整性。FileChannel保证数据的完整性与一致性。在具体配置不现的FileChannel时,建议FileChannel设置的目录和程序日志文件保存的目录设成不同的磁盘,以便提高效率。)
Sink: 从Channel中读取并移除Event, 将Event传递到FlowPipeline中的下一个Agent(如果有的话)(Sink从Channel收集数据,运行在一个独立线程。)
Put事务:
doPut:将批数据先写入临时缓冲区putList。
doCommit:检查channel内存队列是否足够合并。
doRollback:channel内存队列空间不足,回滚数据。
Take事务:
doTake:现将数据提到临时缓冲区takeList。
doCommit:如果数据全部发送成功,则清除临时缓冲区TakeList。
二、下载安装Flume
1、 到官网下载资源包(作者用的是1.8.0版本):http://archive.apache.org/dist/flume/1.8.0/
2、 解压并更新配置文件
tar -xvzf apache-flume-1.8.0-bin.tar.gz #解压
进入 /flume/conf 目录拷贝一份模板做 flume-env.sh
写入JAVA_HOME
export JAVA_HOME=/usr/java/jdk-13.0.1
三、使用Flume
需求:使用flume监听44444端口,并将数据大隐刀控制台
(若使用sinks组,可实现负载均衡)
1、/flume目录下创建/job目录用于存放启动用的配置文件
2、/job下创建文件 flume-netcat-logger.conf
#Name the components on this agent
a1.sources = r1 #为source1起名
a1.sinks = k1 #为sink1起名
a1.channels = c1 #为channel1起名
# Describe/configure the source
a1.sources.r1.type = netcat #定义r1类型为netcat,来自网络数据
a1.sources.r1.bind = localhost #来源于本地(ip)
a1.sources.r1.port = 44444
# Describe the sink
a1.sinks.k1.type = logger #定义k1类型
# 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
3、 启动命令
bin/flume-ng agent --conf conf --name a1 --conf-file job/flume-netcat-logger.conf -Dflume.root.logger=INFO,console
新建窗口,用nc向该端口发数据来测试
接收成功
四、自定义Source和Sink
创建Maven工程并添加依赖
工程目录:
依赖:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.flume</groupId>
<artifactId>flume-ng-core</artifactId>
<version>1.8.0</version>
</dependency>
</dependencies>
创建MySource
public class MySource extends AbstractSource implements Configurable, PollableSource {
//定义要从配置中读取的字段
//两条数据之间的间隔
private long delay;
private String field;
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); //把数据放入channel传输
Thread.sleep(delay);
}
}catch (Exception e){
return Status.BACKOFF; //回滚
}
return Status.READY;
}
public long getBackOffSleepIncrement() { //Source往Channel放数据时,失败后重试的时间间隔
return 0;
}
public long getMaxBackOffSleepInterval() { //最大失败重试次数
return 0;
}
public void configure(Context context) { //从配置文件读取数据
delay = context.getLong("delay", 2000l);
field = context.getString("field", "default");
}
}
创建MySink
public class MySink extends AbstractSink implements Configurable {
private String prefix;
private String suffix;
private static final Logger LOG = LoggerFactory.getLogger(AbstractSink.class);
@Override
public Status process() throws EventDeliveryException {
Status status = null;
Channel channel = getChannel(); //拿到channle
Transaction transaction = channel.getTransaction();
transaction.begin();
try{
Event take;
while((take = channel.take()) == null) { //从channel拿数据,不一定有
Thread.sleep(1000);
}
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", "PRE");
suffix = context.getString("suffix");
}
}
最后打成jar包放到/flume/lib内
写启动配置文件
#Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = com.yzh.MySource #完整路径
a1.sources.r1.delay = 5000
a1.sources.r1.field = XXXXX
# Describe the sink
a1.sinks.k1.type = com.yzh.MySink #完整路径
a1.sinks.k1.prefix = aaa:
a1.sinks.k1.suffix = :asdad
# 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
测试:
bin/flume-ng agent --conf conf --name a1 --conf-file job/flume-mysource-logger.conf -Dflume.root.logger=INFO,console
成功: