Flume

Flume

一、概述

1. flume的定义

Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。Flume基于流式架构,灵活简单。

2. 为什么使用flume

flume的作用就是将数据实时的从本地磁盘上传到HDFS

业务数据分为两种:

  • 爬虫数据:从http的返回值中爬取信息(不建议)。
  • Java后台日志:后台记录的用户的行为操作日志(主要数据来源)。

3. flume架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3CX3N35o-1663863485261)(E:\笔记\hadoop\图片\image-20220922220133251.png)]

flume的基础架构如上图:

flume的一个完整的组件叫做一个agent,是一个JVM进程。agent又存在三个组件:

  1. source:将数据从本地磁盘读取,将数据推送到channel。

  2. channel:连接source和sink的缓冲通道,channel允许source和sink以不同的速度开始工作。并且channel的线程安全,支持多个source、多个sink并行运行。

    channel有两种:

    • memory channel:存在内存中,传输速度快,但是容易丢数据。
    • file channel:存在磁盘中,传输速度慢,但是不会丢数据。
  3. sink:将数据从channel中不断轮询的拉取到存储节点、索引系统或是其他的agent。传输成功的数据会被sink批量的从channel中移除

    同一个source可以将数据推送到不同的channel;

    但是同一个sink只能从一个channel中拉取数据。

二、flume的工作机制

1. flume的数据格式

数据在agent中以event为单位传输。当数据被写进source时就会封装成event。

event由两部分组成:

  • header:存放event的属性信息,是K-V键值对结构,底层是HashMap。
  • body:存放真实的数据信息,是字节数组

2. 配置agent组件

使用flume实现文件采集,需要配置flume的组件信息,当启动采集项目时启用配置。配置步骤如下:

  1. 定义组件信息;
  2. 配置sources信息;
  3. 配置channels信息;
  4. 配置sinks信息;
  5. 将组件拼装成一个agent。

使用flume可以实时的监控目标路径下的文件信息,使用TailDir Source,适用于监听多个实时追加的文件,并且支持断点续传。

TailDir是按行读取数据。

# 定义组件
a1.sources = r1
a1.channels = c1 c2
a1.sinks = k1 k2

# 配置source
a1.sources.r1.type = TAILDIR
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /opt/module/applog/files/.*log.*
a1.sources.r1.positionFile = /opt/module/flume/taildir_position.json

# 配置channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 100
a1.channels.c1.transactionCapacity = 200


a1.channels.c2.type = memory
a1.channels.c2.capacity = 100
a1.channels.c2.transactionCapacity = 200

# 配置sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop102
a1.sinks.k1.port = 44444
a1.sinks.k1.batch-size = 100

a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoop103
a1.sinks.k2.port = 44444
a1.sinks.k2.batch-size = 100


# 拼接
a1.sources.r1.channels = c1 c2
a1.channels.c1.sinks = k1
a1.channels.c2.sinks = k2

三、 flume事务

数据通过flume采集时,发生了事务。

1. put事务

source将数据推送到channel时,发生了put事务

source将数据按批次读取到事务中,先执行doPut()开启事务,将数据写到putList临时缓冲区,之后执行doCommit()检查channel的内存队列能否完成合并,如果能就将event按顺序推送到channel;如果不能,就把数据回滚到putList中等待执行。

2. take事务

sink从channel中拉取数据时,发生了take事务

sink拉取数据,限制性doTake()开启事务,将event按批次拉取到takeList缓冲区,执行doCommit()检查能否将数据写出,如果数据全部写完,sink会将channel中的数据全部清空;如果不能,则将数据回滚到channel中,等待下次执行。

3. flume的数据相关问题

flume中不会出现丢失数据的情况,但是会出现数据重复的情况。

因为断点续传的机制,flume在传输数据时不会丢失数据。但是如果传输上一个断点完成后,下一批次数据已经写入一部分,此时发生故障暂停传输,再次启动flume传输数据时,会检查上一个断点的位置,从断点后开始写入数据,这样就造成了数据重复的情况。

四、agent的内部工作原理

数据写入进source后会被封装成event,之后将event推送到Channel Processor,由控制器将数据发送到拦截器链,按照拦截器中设置的规则将数据处理,并将处理过的数据返回给Channel Processor;之后Channel Processor将数据发送给Channel Selector,选择每一个event应该被发送的channel,并将选择结果返回给Channel Processor,之后将数据发送到channel。

Channel Selector有两个类型:

  • ReplicatingSelector:默认的选择器类型(复制类型),将数据发送给所有的channel。使用这个选择器不需要配置。
  • Multiplexing:按照配置要求将数据发送到特定的channel(多路复用)。如果使用此类型,必须配合拦截器使用,在拦截其中给header做标记,根据标记选择channel。

channel在将数据发送给sink之前,会经过SinkProcessor对sink进行选择。

SinkProcessor有三种类型:

  • DefaultSinkProcessor:默认的类型,一个sink只能对应一个channel拉取数据。
  • LoadBalancingSinkProcessor:负载均衡类型,sink组以轮询的方式从channel拉取数据。
  • FailoverSinkProcessor:自动故障转移类型,给每个sink配置权重参数,由权重最高的sink从channel拉取数据;如果sink挂了,会由第二高权重的sink拉取数据,并以此类推。

注意:一台节点上的flume进程,只能读取本节点上的数据,不能够读取到其他节点上的数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ixYfWUJP-1663863485262)(E:\笔记\hadoop\图片\image-20220923001750885.png)]

五、 自定义拦截器

自定义拦截器需要实现interceptor接口,重写接口方法,最后再声明一个静态内部类,实现Interceptor.Builder接口,重写接口的方法,在方法中创建拦截器对象并返回。

public class ETLInterceptor implements Interceptor {
    @Override
    public void initialize() {

    }

    /*
        获取body中的数据,并将数据转换成字符串
     */
    @Override
    public Event intercept(Event event) {
        // 获取body数据,并转换string
        byte[] body = event.getBody();
        String log = new String(body, StandardCharsets.UTF_8);

        // 判断数据是否完整
        if(JSONUtil.isJSONValidate(log)){
            return event;
        }else {
            return null;
        }
    }

    // 将传入的list遍历取出
    @Override
    public List<Event> intercept(List<Event> list) {
        Iterator<Event> iterator = list.iterator();
        while (iterator.hasNext()){
            Event next = iterator.next();
            if(next == null){
                iterator.remove();
            }
        }

        return list;
    }

    @Override
    public void close() {

    }

    // 自定义Builder类
    public  static class Builder implements Interceptor.Builder{

        @Override
        public Interceptor build() {
            return new ETLInterceptor();
        }

        @Override
        public void configure(Context context) {

        }
    }
}

{

    @Override
    public Interceptor build() {
        return new ETLInterceptor();
    }

    @Override
    public void configure(Context context) {

    }
}

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值