Flume

概述

分布式的海量日志采集,聚合和传输的系统。

优点:可以高速采集数据,采集的数据能够以想要的文件格式及压缩方式存储在HDFS上。事务功能保证了数据在采集的过程中数据不丢失,部分Source保证了Flume挂了以后重启依旧能够继续在上一次采集点采集数据,正真做到数据零丢失。

体系结构

体系结构图:

核心组件:

  • Client->生产数据,运行在一个独立的线程
  • Event->一个数据单元,消息头和信息体组成(Event可以是日志记录、avro对象等)
  • Flow->Event从源点到达目的点的迁移的抽象
  • Agent->一个独立的Flume进程,包含组件Source、Channel、Sink

Source:数据收集组件。(source从Client收集数据,传递给Channel) Channel:中转Event的一个临时存储,保存由Source组件转递过滤的Event。(Channel连接source和sink有点像消息队列) Sink:从Channel中读取并移除Event,将Event传递到FlowPipeline中的下一个Agent(Sink从Channel收集数据,运行在下一个独立线程)

事务机制

Flume处理流程中,有两个事务机制:推送事务机制和拉取事务机制

推送事务机制

doput:把批数据写入到临时缓冲区putList中,便于回滚,提高数据可靠性

doCommit:检查Channel容量是否足够,如果容量足够则把putList里的数据发送到Channel

doRollBack:如果Channel容量不够,则把数据回滚到putList

拉取事务机制

doTake:把数据读取到临时缓冲区takeList

doCommit:检查数据是否发送成功,成功则把event从takeList中移除

doRollBack:如果发送失败,则把takeList的数据回滚到Channel

事务机制的可靠性与恢复性
  • 可靠性:只有当sink接收到,数据落地完成的信息之后,才会将数据从管道中删除。事件在每个代理上的一个通道中上游。然后将事件传递到流中的下一个代理或终端存储库 (如HDFS)。仅将事件存储在下一个代理程序的通道或终端存储库中之后,才将其从通道中 删除。这就是Flume中单条消息传递语义如何提供流的端到端可靠性的方式。数据传输的方式不是byte,而是一个个的event,Flume使用事务性方法来确保事件的可靠传 递。源和接收器分别在事务中封装存储在通道中或由通道提供的事务中提供的事件的存储/检索。这确保了事件集在流中从点到点可靠地传递。在多条流的情况下,来自上一条的接收器 和来自下一条的源均运行其事务,以确保将数据安全地存储在下一条的通道中。
  • 可恢复性:当数据丢失了,只有从存储在磁盘的方式,才能将数据找回,事件在通道中恢复,该通道管理从故障中恢复。Flume支持持久的文件通道,该通道由本地文件系统支持。还有一个内存通道可以将事件简单地存储在内存队列中,这虽然速度更快,但是当代理进行死亡时,仍保留在内存通道中的任何事件都无法恢复。

拦截器

拦截器结构:header:key-value,body:数据

使用场景

场景一:时间戳拦截器

  • 解决的问题:零点漂移
  • 问题的产生:

2023-11-17 23:59:59:59此时产生的数据应该属于17号。由于机器运行的时间是根据系统时间来的,有可能此时的数据保存到了18号 生产数据的时间:2023-11-17 23:59:59:59 保存时的时间:2023-11-18 00:00:01:00。

  • 需求分析:使用拦截器根据生产时间来解决问题,通过Hive分析每日的销售数据--保存在hive分区表year=2023 month=11 day=17

场景二:拦截器与channel配合实现数据分流

两个特性:复制与多路复用

复制:利用Channel Selector将相同的数据发送到不同Channel中,不同Channel中的数据分发到不同的Sink,不同的Sink再将数据发送到指定位置。

多路复用:利用拦截器和Channel Selector将不同的数据发送到不同的Channel中,不同Channel中的数据分发到不同的Sink,不同的Sink再将数据发送到指定位置。

拦截器分类
自定义拦截器

java编写拦截器

typescript 复制代码
package com.flume;


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

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Hello01CustomInterceptor implements Interceptor {

    //声明一个全局变量
    private int count=0;

    //声明用户自定义参数
    private static Map<String, String> customParams;

    @Override
    public void initialize() {
        System.out.println("Hello01CustomInterceptor.initialize["+System.currentTimeMillis()+"]");
    }

    /**
     * 可以获取本批次【Batch】传递的所有事件
     * @param events
     * @return
     */
    @Override
    public List<Event> intercept(List<Event> events) {
        //声明一个List装载处理完毕后的Event
        List<Event> eventsNew = new ArrayList<>();
        //遍历传入的Event
        for (Event event :events) {
            Event eventNew = this.intercept(event);
            if(eventNew!=null){
                eventsNew.add(eventNew);
            }
        }
        return eventsNew;
    }

    /**
     * 将本批次内的数据依次进行处理
     * @param event
     * @return
     */
    @Override
    public Event intercept(Event event) {
        //获取Event的Header
        Map<String, String> headers = event.getHeaders();
        //获取Event的Body
        String body = new String(event.getBody());

        //设置Event的Header
        headers.put("master","cy_yyds");
        //设置Event的Body
        event.setBody(body.concat("_yjxxt_"+customParams.get("yjxxt")+"_"+ ++count).getBytes());

        //判断是否返回--只有能被3整除才能返回
        if (count%3==0){
            return event;
        }
        return null;
    }

    @Override
    public void close() {
        System.out.println("Hello01CustomInterceptor.close["+System.currentTimeMillis()+"]");
    }

    public static class Builder implements Interceptor.Builder{

        @Override
        public Interceptor build() {
            System.out.println("Builder.build["+System.currentTimeMillis()+"]");
            return new Hello01CustomInterceptor();
        }

        @Override
        public void configure(Context context) {
            Map<String, String> parameters = context.getParameters();
            customParams=parameters;
            parameters.entrySet().stream().forEach(System.out::println);
        }
    }
}

然后打成jar包放入liunx下的flume的lib中

option下的配置文件:

案例

简单案例与文件读取
Flume的高阶特性
  • Flume自连接:达到解耦
  • 故障转移:实现高可用
  • 负载均衡:增加吞吐量
相关推荐
Data跳动4 小时前
Spark内存都消耗在哪里了?
大数据·分布式·spark
woshiabc1115 小时前
windows安装Elasticsearch及增删改查操作
大数据·elasticsearch·搜索引擎
lucky_syq6 小时前
Saprk和Flink的区别
大数据·flink
lucky_syq6 小时前
流式处理,为什么Flink比Spark Streaming好?
大数据·flink·spark
袋鼠云数栈6 小时前
深入浅出Flink CEP丨如何通过Flink SQL作业动态更新Flink CEP作业
大数据
小白学大数据7 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
15年网络推广青哥7 小时前
国际抖音TikTok矩阵运营的关键要素有哪些?
大数据·人工智能·矩阵
节点。csn8 小时前
Hadoop yarn安装
大数据·hadoop·分布式
arnold668 小时前
探索 ElasticSearch:性能优化之道
大数据·elasticsearch·性能优化
NiNg_1_2349 小时前
基于Hadoop的数据清洗
大数据·hadoop·分布式