[大数据]Flume(2)

3.Flume进阶

3.1 Flume事务

在这里插入图片描述

3.2 Flume Agent内部原理

在这里插入图片描述

3.2.1 ChannelSelector

ChannelSelector的作用就是选出Event将要被发往哪个Channel。其共有两种类型,分别是Replicating(复制)和Multiplexing(多路复用)。
ReplicatingSelector会将同一个Event发往所有的Channel,Multiplexing会根据相应的原则,将不同的Event发往不同的Channel。

3.2.2 SinkSelector

SinkProcessor共有三种类型,分别是DefaultSinkProcessor、LoadBalancingSinkProcessor和FailoverSinkProcessor
DefaultSinkProcessor对应的是单个的Sink,LoadBalancingSinkProcessor和FailoverSinkProcessor对应的是Sink Group,LoadBalancingSinkProcessor可以实现负载均衡的功能,FailoverSinkProcessor可以错误恢复的功能。

3.2.3 Interceptors

Flume中的拦截器(interceptor),用户Source读取events发送到Sink的时候,在events header中加入一些有用的信息,或者对events的内容进行过滤,完成初步的数据清洗。这在实际业务场景中非常有用,Flume-ng 1.6中目前提供了以下拦截器:
Timestamp Interceptor;
Host Interceptor;
Static Interceptor;
UUID Interceptor;
Morphline Interceptor;
Search and Replace Interceptor;
Regex Filtering Interceptor;
Regex Extractor Interceptor;

eg 没有加拦截器:
创建interceptors.conf

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

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

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


a1.sinks.k1.type = logger


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

启动flume向hadoop102:44444发送数据
在这里插入图片描述

headers字段为空

Timestamp Interceptor:

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

a1.sources.r1.type = netcat
a1.sources.r1.bind = hadoop102
a1.sources.r1.port = 44444
#设置一个拦截器(用来向headers中添加时间戳)
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = timestamp

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


a1.sinks.k1.type = logger


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

在这里插入图片描述
header字段为当前时间戳。

3.3 Flume拓扑结构

3.3.1 简单串联

在这里插入图片描述
这种模式是将多个flume顺序连接起来了,从最初的source开始到最终sink传送的目的存储系统。此模式不建议桥接过多的flume数量, flume数量过多不仅会影响传输速率,而且一旦传输过程中某个节点flume宕机,会影响整个传输系统。

3.3.2 复制和多路复用

在这里插入图片描述
Flume支持将事件流向一个或者多个目的地。这种模式可以将相同数据复制到多个channel中,或者将不同数据分发到不同的channel中,sink可以选择传送到不同的目的地。

3.3.3 负载均衡和故障转移

在这里插入图片描述
Flume支持使用将多个sink逻辑上分到一个sink组,sink组配合不同的SinkProcessor可以实现负载均衡和错误恢复的功能。

3.3.4 聚合

在这里插入图片描述
这种模式是我们最常见的,也非常实用,日常web应用通常分布在上百个服务器,大者甚至上千个、上万个服务器。产生的日志,处理起来也非常麻烦。用flume的这种组合方式能很好的解决这一问题,每台服务器部署一个flume采集日志,传送到一个集中收集日志的flume,再由此flume上传到hdfs、hive、hbase等,进行日志分析。

3.4 开发案例

3.4.1 简单串联

案例需求
监听hadoop102 22222端口,将内容输出到hadoop103 33333端口。

实现
1)分别编写conf文件
hadoop102上的netcatsource_avrosink.conf

#agent1(hadoop102)  netcatsource --> memorychannel --> arvosink
a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.type = netcat
a1.sources.r1.bind = hadoop102
a1.sources.r1.port = 22222

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


a1.sinks.k1.type = avro
#hostname是将数据写到的那台机器
a1.sinks.k1.hostname = hadoop103
a1.sinks.k1.port = 33333


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

hadoop103上的avrosource_loggersink.conf

#注意:先启动hadoop103因为hadoop103接收hadoop102的数据的
#agent2(hadoop103) avrosource ---> memorychannel ----> loggersink
a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.type = avro
a1.sources.r1.bind = hadoop103
a1.sources.r1.port = 33333

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

a1.sinks.k1.type = logger

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

2)分别启动两台机器上的flume监听(先hadoop103)

 flume-ng agent -n a1 -c conf/ -f datas2/avrosource_loggersink.conf -Dflume.root.logger=INFO,console
 flume-ng agent -n a1 -c conf/ -f datas2/netcatsource_avrosink.conf -Dflume.root.logger=INFO,console

3)向hadoop102端口发送数据
在这里插入图片描述
hadoop103 33333端口接收在这里插入图片描述

3.4.1 复制和多路复用

案例需求
使用Flume-1监控文件变动,Flume-1将变动内容传递给Flume-2,Flume-2负责存储到HDFS。同时Flume-1将变动内容传递给Flume-3,Flume-3负责输出到Local FileSystem。
在这里插入图片描述
实现复制

1)分别在hadoop102,103,104上创建agent1.conf,agent2.conf,agent3.conf
agent1.conf

#agent1(hadoop102)
a1.sources = r1
a1.channels = c1 c2
a1.sinks = k1 k2

a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/flume/demo/123.log

#配置channelSelector - replicating(复制-默认不配也可以)
#a1.sources.r1.selector.type = replicating



a1.channels.c1.type = memory
a1.channels.c2.type = memory


a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop103
a1.sinks.k1.port = 33333
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoop104
a1.sinks.k2.port = 44444

#一个source对接两个channel
a1.sources.r1.channels = c1 c2 
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2

agent2.conf:

#agent2为了便于观察以loggersink形式代替hdfssink
#agent2(hadoop103)
a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.type = avro
a1.sources.r1.bind = hadoop103
a1.sources.r1.port = 33333

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

a1.sinks.k1.type = logger

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

agent3.conf

#agent3(hadoop104)
a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.type = avro
a1.sources.r1.bind = hadoop104
a1.sources.r1.port = 44444

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

#a1.sinks.k1.type = logger
#将event数据存储到本地磁盘上
a1.sinks.k1.type = file_roll
#event存放的目录
a1.sinks.k1.sink.directory = /opt/module/flume/demo
#多久时间滚动一个新文件(30秒)
a1.sinks.k1.sink.rollInterval = 30

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

2)启动,先启动hadoop102与hadoop104监听端口

flume-ng agent -n a1 -c conf/ -f datas2/agent2.conf -Dflume.root.logger=INFO,console(hadoop103)
flume-ng agent -n a1 -c conf/ -f datas2/agent3.conf -Dflume.root.logger=INFO,console(hadoop102)
flume-ng agent -n a1 -c conf/ -f datas2/agent1.conf -Dflume.root.logger=INFO,console(hadoop104)

3)读取情况
hadoop103:
在这里插入图片描述
hadoop104:
在这里插入图片描述
实现复用
在agent1.conf中添加

#复用
a1.sources.r1.selector.type = multiplexing
#event(headers | body)根据headers中的key和value进行数据的发送
#state指的是headers,key的值
a1.sources.r1.selector.header = state
#CZ指的是key对应的value值那么就发送到c1
a1.sources.r1.selector.mapping.CZ = c1
#US指的是key对应的value值那么就发送到c2
a1.sources.r1.selector.mapping.US = c2

#需求:给event中的headers添加数据
#static拦截器可以给所有的eventheaders设置我们自定义的key和value
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = static
#设置key值
a1.sources.r1.interceptors.i1.key = state
#设置value值
a1.sources.r1.interceptors.i1.value = CZ

使用拦截器interceptors添加event中的header字段,按照header字段的不同,channel selector选择对应的channel传输
如上写法将全部传输给hadoop103

添加之后重新启动
hadoop103:
在这里插入图片描述
hadoop104中没有监听到
在这里插入图片描述

3.4.2 负载均衡和故障转移

故障转移:
案例需求
使用Flume1监控一个端口,其sink组中的sink分别对接Flume2和Flume3,采用FailoverSinkProcessor,实现故障转移的功能。
需求分析
在这里插入图片描述
实现:
1)分别在hadoop上创建agent1.conf,agent2.conf,agent3.conf
agent1.conf

#agent1(hadoop102)
a1.sources = r1
a1.channels = c1
a1.sinks = k1 k2

a1.sources.r1.type = netcat
a1.sources.r1.bind = hadoop102
a1.sources.r1.port = 22222

#一个channel对应多个sink时要设置一个sinkgroups
a1.sinkgroups = g1
#该sink组有哪些sink的实例
a1.sinkgroups.g1.sinks = k1 k2
#配置sinkProcessor的类型①failover故障转移 ②load_balance负载均衡
a1.sinkgroups.g1.processor.type = failover
#配置sink的优先级数值越大优先级越高
a1.sinkgroups.g1.processor.priority.k1 = 5
a1.sinkgroups.g1.processor.priority.k2 = 10


a1.channels.c1.type = memory


a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop103
a1.sinks.k1.port = 33333

a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoop104
a1.sinks.k2.port = 44444


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

agent2.conf,agent3.conf同案例3.4.1
2)分别启动三台机器上的flume
3)向hadoop102:22222发送数据,可以看到在agent2,agent3都正常运行的时候,会优先由hadoop:44444输出
在这里插入图片描述
当agent3挂掉的时候,会故障转移到hadoop103:33333输出。完成故障转移
在这里插入图片描述
当agent3冲新启动的时候会重新交由hadoop104:44444输出
在这里插入图片描述

在这里插入图片描述
负载均衡
配置agent1.conf中的sinkProcessor的类型为负载均衡。

#agent1(hadoop102)
a1.sources = r1
a1.channels = c1
a1.sinks = k1 k2

a1.sources.r1.type = netcat
a1.sources.r1.bind = hadoop102
a1.sources.r1.port = 22222

#定义一个sink组
a1.sinkgroups = g1
#指明sink组中的sink实例
a1.sinkgroups.g1.sinks = k1 k2
#设置sinkProcessor的类型(负载均衡)
a1.sinkgroups.g1.processor.type = load_balance
#①random-随机分配  ②round_robin-轮循
a1.sinkgroups.g1.processor.selector = random


a1.channels.c1.type = memory


a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop103
a1.sinks.k1.port = 33333

a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoop104
a1.sinks.k2.port = 44444


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

分别启动,向hadoop102:22222发送数据
可以看到输出是随机分配到hadoop103:33333 hadoop104:44444上。
在这里插入图片描述

3.4.3 聚合

案例需求
hadoop102上的Flume-1监控文件/opt/module/group.log,
hadoop103上的Flume-2监控某一个端口的数据流,
Flume-1与Flume-2将数据发送给hadoop104上的Flume-3,Flume-3将最终数据打印到控制台。
需求分析
在这里插入图片描述
即保证flume1,flume2的sink端口与flume3的source端口保持一致。

实现
1)分别编写agnet1.conf, agent2.conf, agent3.conf
添加如下内容
agent1.conf:

# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1

# Describe/configure the source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /opt/module/group.log
a1.sources.r1.shell = /bin/bash -c

# Describe the sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop104
a1.sinks.k1.port = 44444

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

agent2.conf

# Name the components on this agent
a2.sources = r1
a2.sinks = k1
a2.channels = c1

# Describe/configure the source
a2.sources.r1.type = netcat
a2.sources.r1.bind = hadoop103
a2.sources.r1.port = 44444

# Describe the sink
a2.sinks.k1.type = avro
a2.sinks.k1.hostname = hadoop104
a2.sinks.k1.port = 33333

# Use a channel which buffers events in memory
a2.channels.c1.type = memory
a2.channels.c1.capacity = 1000
a2.channels.c1.transactionCapacity = 100

# Bind the source and sink to the channel
a2.sources.r1.channels = c1
a2.sinks.k1.channel = c1


agent3.conf

# Name the components on this agent
a3.sources = r1
a3.sinks = k1
a3.channels = c1

# Describe/configure the source
a3.sources.r1.type = avro
a3.sources.r1.bind = hadoop104
a3.sources.r1.port = 44444

# Describe the sink
# Describe the sink
a3.sinks.k1.type = logger

# Describe the channel
a3.channels.c1.type = memory
a3.channels.c1.capacity = 1000
a3.channels.c1.transactionCapacity = 100

# Bind the source and sink to the channel
a3.sources.r1.channels = c1
a3.sinks.k1.channel = c1

2)分别执行。
可以看到hadoop102上对日志的监听与hadoop103:33333端口输入的监听都聚合输出到了hadoop104:44444端口。
在这里插入图片描述

3.5 自定义Interceptor

3.5.1 案例需求

使用Flume采集服务器本地日志,需要按照日志类型的不同,将不同种类的日志发往不同的分析系统。

3.5.2 需求分析

在实际的开发中,一台服务器产生的日志类型可能有很多种,不同类型的日志可能需要发送到不同的分析系统。此时会用到Flume拓扑结构中的Multiplexing结构,Multiplexing的原理是,根据event中Header的某个key的值,将不同的event发送到不同的Channel中,所以我们需要自定义一个Interceptor,为不同类型的event的Header中的key赋予不同的值。
在该案例中,我们以端口数据模拟日志,以数字(单个)和字母(单个)模拟不同类型的日志,我们需要自定义interceptor区分数字和字母,将其分别发往不同的分析系统(Channel)。
在这里插入图片描述

3.5.3 需求实现

1)创建maven项目,创建MyInterceptor类实现Interceptor接口

maven依赖:

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

MyInterceptor.java

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

import java.util.List;

/**
 * 自定义拦截器
 * 作用:根据body中的内容在headers中添加指定的key-value
 * 如果内容为字母,那么添加state=letter
 * 如果内同为数字,那么添加state=number
 */
public class MyInterceptor implements Interceptor {
    /**
     * 初始化
     */
    @Override
    public void initialize() {

    }

    /**
     * 为每个event中的header添加key-value
     * channelProcessor调用拦截器时会调用该方法并将event传过来
     *
     * @param event
     * @return
     */
    @Override
    public Event intercept(Event event) {
        //获取body中的内容
        byte[] body = event.getBody();
        //判断数据中的内容 根据类型写入headers
        if ((body[0] >= 'A' && body[0] <= 'Z') || (body[0] >= 'a' && body[0] <= 'z')) {
            event.getHeaders().put("type", "letter");
        } else if (body[0] >= '0' && body[0] <= '9') {
            event.getHeaders().put("type", "number");
        }
        return event;
    }

    @Override
    public List<Event> intercept(List<Event> list) {
        //从集合中遍历每一个event 对其进行修改
        for (Event event : list) {
            intercept(event);
        }
        return list;
    }

    /**
     * 拦截器结束时进行调用,关闭资源操作
     */
    @Override
    public void close() {

    }
    /**
     * 静态内部类
     * 返回MyInterceptor 拦截器调用的是该内部类
     */
    public static class Builder implements Interceptor.Builder{
        /**
         * 返回Interceptor接口的实例
         * @return
         */
        @Override
        public Interceptor build() {
            return new MyInterceptor();
        }

        @Override
        public void configure(Context context) {

        }
    }
}

2)编辑flume配置文件

#agent1(hadoop102)
a1.sources = r1
a1.channels = c1 c2
a1.sinks = k1 k2

a1.sources.r1.type = netcat
a1.sources.r1.bind = hadoop102
a1.sources.r1.port = 22222



#复用
a1.sources.r1.selector.type = multiplexing
a1.sources.r1.selector.header = type
a1.sources.r1.selector.mapping.letter = c1
a1.sources.r1.selector.mapping.number = c2


#自定义拦截器
a1.sources.r1.interceptors = i1
#注意:调用的是Interceptor的内部类Builder
a1.sources.r1.interceptors.i1.type = com.atguigu.demo.MyInterceptor$Builder



a1.channels.c1.type = memory
a1.channels.c2.type = memory


a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop103
a1.sinks.k1.port = 33333

a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoop104
a1.sinks.k2.port = 44444


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

-----------------------------------------------------------------

#agent2(hadoop103)
a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.type = avro
a1.sources.r1.bind = hadoop103
a1.sources.r1.port = 33333

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

a1.sinks.k1.type = logger

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

3)分别启动,先启动hadoop103与hadoop104,然后向hadoop102:22222发送数据(字母与数字),查看hadoop103:33333与hadoop104:44444的输出日志,可以看到实现通过拦截器分开输出。
在这里插入图片描述

3.6 自定义Source

3.6.1 介绍

Source是负责接收数据到Flume Agent的组件。Source组件可以处理各种类型、各种格式的日志数据,包括avro、thrift、exec、jms、spooling directory、netcat、sequence generator、syslog、http、legacy。官方提供的source类型已经很多,但是有时候并不能满足实际开发当中的需求,此时我们就需要根据实际需求自定义某些source。
官方也提供了自定义source的接口:
https://flume.apache.org/FlumeDeveloperGuide.html#source根据官方说明自定义MySource需要继承AbstractSource类并实现Configurable和PollableSource接口。
实现相应方法:
getBackOffSleepIncrement()//暂不用
getMaxBackOffSleepInterval()//暂不用
configure(Context context)//初始化context(读取配置文件内容)
process()//获取数据封装成event并写入channel,这个方法将被循环调用。
使用场景:读取MySQL数据或者其他文件系统。

3.6.2 需求

使用flume接收数据,并给每条数据添加前缀,输出到控制台。前缀可从flume配置文件中配置。
在这里插入图片描述

3.6.3 分析

在这里插入图片描述

3.6.4 实现

MySource.java

package com.atguigu.demo;

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
 * 使用flume接受数据,并给每条数据添加前缀,输出到控制台,前缀可以从flume配置文件中配置
 */
public class MySource extends AbstractSource implements Configurable, PollableSource {
    private String prefix;
    private Long delay;

    /**
     * 核心方法:获取数据封装成event,将创建的event放入到channel中,该方法会被循环调用。
     *
     * @return
     * @throws EventDeliveryException Status:一个枚举类,使用status的值来表示想Channel中添加的数据是否成功
     *                                READY:成功 BACKOFF:失败
     */
    @Override
    public Status process() throws EventDeliveryException {
        try {
            //创建事件头信息
            HashMap<String, String> headerMap = new HashMap<>();
            //创建事件
            SimpleEvent simpleEvent = new SimpleEvent();
            for (int i = 0; i < 5; i++) {
                //设置事件头信息
                simpleEvent.setHeaders(headerMap);
                //设置事件内容
                simpleEvent.setBody((prefix + i).getBytes());
                //将事件写入channel
                getChannelProcessor().processEvent(simpleEvent);
                Thread.sleep(delay);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Status.BACKOFF;
        }
        return Status.READY;
    }

    /**
     * 当Source没有数据可封装时,可以让Source所在的线程休息一会
     *
     * @return
     */
    @Override
    public long getBackOffSleepIncrement() {
        return 0;
    }

    /**
     * 当Source没有数据可封装时,Source最大可以休息多久
     *
     * @return
     */
    @Override
    public long getMaxBackOffSleepInterval() {
        return 0;
    }

    /**
     * 读取配置文件,可以获取配置文件中的内容
     *
     * @param context
     */
    @Override
    public void configure(Context context) {
        //将获取配置文件中的指定属性的内容,如果没有配那么默认值为空
        prefix = context.getString("prefix", "Hello!");
        delay = context.getLong("delay");

    }
}

配置文件:

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

#自定义的source
a1.sources.r1.type = com.atguigu.demo.MySource
#自定义设置的前缀内容,如果没有设置默认值是Hello!
a1.sources.r1.prefix = helloworld

a1.channels.c1.type = memory

a1.sinks.k1.type = logger

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

启动结果:
在这里插入图片描述

3.7 自定义Sink

3.7.1 介绍

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。
官方也提供了自定义sink的接口:
https://flume.apache.org/FlumeDeveloperGuide.html#sink根据官方说明自定义MySink需要继承AbstractSink类并实现Configurable接口。
实现相应方法:
configure(Context context)//初始化context(读取配置文件内容)
process()//从Channel读取获取数据(event),这个方法将被循环调用。
使用场景:读取Channel数据写入MySQL或者其他文件系统。

3.7.2 需求

使用flume接收数据,并在Sink端给每条数据添加前缀和后缀,输出到控制台。前后缀可在flume任务配置文件中配置。
在这里插入图片描述

3.7.3 实现

Mysink.java

package com.atguigu.demo;

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

import java.util.Arrays;

public class MySink extends AbstractSink implements Configurable {
    private String suffix;//读取到配置文件中的suffix内容
    Logger logger = LoggerFactory.getLogger(MySink.class);//获取Logger对象,可以将数据以日志的方式输出

    @Override

    public void configure(Context context) {
        suffix = context.getString("suffix", "test");
    }

    /**
     * 将channel中的内容写出去
     *
     * @return
     * @throws EventDeliveryException
     */
    @Override
    public Status process() throws EventDeliveryException {
        Status status = Status.READY;//表示成功输入一个或多个event
        //1.获取channel
        Channel channel = getChannel();
        //2.从channel中获取数据
        Transaction transaction = channel.getTransaction();
        try {
            Event event = null;
            //2.1 开启事物
            transaction.begin();
            //3.获取数据
            while (true) {
                event = channel.take();
                if (event != null) {
                    break;
                }
            }
            //4.将数据写出
            logger.info(new String(new String(event.getBody()) + suffix));
            //5.提交数据
            transaction.commit();
        } catch (Exception e) {
            status = Status.BACKOFF;
            //事务回滚
            transaction.rollback();
        } finally {
            //关闭事务
            transaction.close();
        }
        return status;
    }
}
	
a1.sources = r1
a1.channels = c1
a1.sinks = k1


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


a1.channels.c1.type = memory
#自定义sink
a1.sinks.k1.type = com.atguigu.demo.MySink
#给数据设置一个后缀
a1.sinks.k1.suffix = HelloWorld

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

打包提交,向hadoop102:44444发送数据:
在这里插入图片描述
可以看到接收到的数据都加上了后缀。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值