Flume案例——自定义interceptor处理数据,并使用mutilplexing selector将数据分路存储

实际需求:

将多个日志文件中的数据分类处理,采集出不同业务的数据,然后分路存储

主要知识点:

  • 自定义interceptor
  • 使用multiplexing selector将数据分路存储

1.模拟日志生成器

可以写一个shell脚本,模拟生成日志数据,规定日志数据格式:uid,behavior,type,timestamp

while true
do
if [ $(($RANDOM % 2)) -eq 0]
then
echo "u$RANDOM,e1,shop,`date +%s`000" >> test.log
else
echo "u$RANDOM,e1,food,`date +%s`000" >> test.log
fi
sleep 0.2
done 

此处仅为测试使用,因此只随机生成shopping和food两个业务的日志数据

注意:上述脚本若直接在shell中执行,则最好变为unix格式

2.创建agent的配置文件

## 到flume的安装目录下,创建agentconf,即存放agent配置文件的文件夹
## 后缀名为 conf / properties 都可以

vi multiplexing.conf         

将如下配置信息写入

a1.sources = r1                          ## source名字
a1.channels = c1 c2                      ## channel名字,此处有两个channel
a1.sinks = k1 k2                         ## sink的名字,有两个sink

a1.sources.r1.channels = c1 c2           ## r1 连接两个 channel c1和c2
a1.sources.r1.type = TAILDIR             ## source的采集方式为 taildir
a1.sources.r1.filegroups = g1            ## r1监控文件组g1,监控指定路径下的文件
a1.sources.r1.filegroups.g1 = /root/test.*
a1.sources.r1.fileHeader = false         ## 不开启 fileheader

a1.sources.r1.interceptors = i1          ## source中的event先传给拦截器i1
a1.sources.r1.interceptors.i1.type = Test.MultiplexingInterceptorDemo$MultiplexingInterceptorDemoBuilder   ## i1的拦截器为自定义拦截器
a1.sources.r1.interceptors.i1.flagfield = 2   ## i1中获取event中指定的数据
a1.sources.r1.interceptors.i1.timestampfield = 3

a1.sources.r1.selector.type = multiplexing    ## 选择器类型为  multiplexing,多路选择器
a1.sources.r1.selector.header = flag          ## 指定header中的key为flag 
a1.sources.r1.selector.mapping.shop = c1      ## 若对应flag的值为 shop,将数据传给c1
a1.sources.r1.selector.mapping.food = c2      ## 若对应flag的值为 food,将数据传给c2
a1.sources.r1.selector.default = c2           ## 默认传给c2


a1.channels.c1.type = memory                  ## c1和c2的类型都为 memory channel
a1.channels.c1.capacity = 2000                ## c1的容量
a1.channels.c1.transactionCapacity = 1000     ## c1的事务容量

a1.channels.c2.type = memory
a1.channels.c2.capacity = 2000
a1.channels.c2.transactionCapacity = 1000


a1.sinks.k1.channel = c1                      ## k1连接c1,从c1中取数据
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink      ## k1的类型,将数据传到kafka
a1.sinks.k1.kafka.bootstrap.servers = linux01:9092,linux01:9092,linux01:9092  ## 三台broker地址
a1.sinks.k1.kafka.topic = shop                ## 传入kafka的shop中  
a1.sinks.k1.kafka.producer.acks = 1           ## 生产者的通知代号,决定吞吐量大小


a1.sinks.k2.channel = c2                      ## k2连接c2
a1.sinks.k2.type = hdfs                       ## k2的类型是 hdfs
a1.sinks.k2.hdfs.path = hdfs://linux01:8020/food/%Y-%m-%d/%H    ## 数据存放路径
a1.sinks.k2.hdfs.filePrefix = test-log-
a1.sinks.k2.hdfs.fileSuffix = .log
a1.sinks.k2.hdfs.rollSize = 268435456
a1.sinks.k2.hdfs.rollInterval = 120
a1.sinks.k2.hdfs.rollCount = 0
a1.sinks.k2.hdfs.batchSize = 1000
a1.sinks.k2.hdfs.fileType = DataStream        ## 文件类型
a1.sinks.k2.hdfs.useLocalTimeStamp = false

3.创建一个Java类,继承Interceptor

此处的拦截器(Interceptor)逻辑是根据具体需求具体实现的,要重写Interceptor中的多个方法

public class MultiplexingInterceptorDemo implements Interceptor {

    //创建成员变量,接收传出的 flagfield
    private Integer flagfield = 0;

    //使用有参构造给成员变量 flagfield赋值
    public MultiplexingInterceptorDemo(Integer flagfield) {
        this.flagfield = flagfield;
    }

    /**
     * 拦截器构造实例后的初始化操作
     */
    @Override
    public void initialize() {

    }

    /**
     * 接收一个 event ,处理后 ,返回一个event
     * @param event
     * @return
     */
    @Override
    public Event intercept(Event event) {

        //根据 event 中的数据内容,以及参数中指定的标记字段,产生不同的header值
        byte[] body = event.getBody();
        //将 字节数组转换为 String
        String line = new String(body);
        //将result按照逗号分割
        String[] split = line.split(",");
        //因为flagfield是一个Int类型的值,因此会取出数组中对应的值,即会取出shop/food
        String flag = split[this.flagfield];
        //再将flag放入header中,header是一个hashmap,给后续选择器进行使用
        event.getHeaders().put("flag",flag);
        //最后再将 event 返回
        return event;
    }

    /**
     * 接收一个存放event 的 List,返回的也是一个 处理后的存放 event 的 List
     * @param list
     * @return
     */
    @Override
    public List<Event> intercept(List<Event> list) {
        //可以直接调用上述方法
        for (Event event : list) {
            intercept(event);
        }
        //由于会将event取出,处理以后再放回list中,所以可以直接返回list
        return list;
    }

    /**
     * 收尾操作
     */
    @Override
    public void close() {

    }

    /**
     * 程序执行开始,首先运行的是MultiplexingInterceptorDemoBuilder
     * 然后得到 configure ,得到配置信息
     * 再 new 一个实例,传到外部类中
     */
    public static class MultiplexingInterceptorDemoBuilder implements Interceptor.Builder{

        //创建成员变量
        Integer flagfield = 0;

        /**
         * 用户构建一个拦截器实例
         * @return
         */
        @Override
        public Interceptor build() {
            //得到flagfield后,new一个实例
            return new MultiplexingInterceptorDemo(flagfield);
        }

        /**
         * 获取配置参数的入口
         * @param context
         */
        @Override
        public void configure(Context context) {
            flagfield = context.getInteger("flagfield");

        }
    }
}

上述代码只为理清逻辑,代码本身还不够健壮

4.启动Kafka、Zookeeper、hdfs

由于Kafka依赖于zookeeper,因此要先启动zookeeper,可以创建多个脚本文件,同时启动多台机器的zk和Kafka

5.启动flume agent

## 进入到flume安装目录

bin/flume-ng agent -c conf/ -f agentconf/multiplexing.conf -n a1 -Dflume.root.logger=DEBUG,console

6.得到分流结果

6.1Kafka中

使用消费者消费数据

bin/kafka-console-consumer.sh --bootstrap-server doitedu01:9092,doitedu02:9092,doitedu03:9092 --topic shop

6.2HDFS中

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值