大数据开发学习1.8-Flume入门和部署

268 阅读5分钟

Flume概述

Flume定义

Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。

Flume基于流式架构,灵活简单

graph LR
	a1[Java后台日志数据] --> B[服务器本地文件夹]
	a2[其他日志数据]-->B
	B-->C[Flume]
	D[网络端口数据]-->C
	C-->E[HDFS]
	C-->F[Kafka]

Flume基础架构

Flume组成架构如下图(官网图)所示:

image-20220830181654438.png

Agent

Agent是一个JVM进程,它以事件(Event)的形式将数据从源头送至目的地 Agent主要有3个部分组成:SourceChannelSink

Source

Source是负责接收数据到Flume Agent的组件

Source组件可以处理各种类型、各种格式的日志数据

Sink

Sink不断地轮询Channel中的事件且批量地移除它们,并将这些事件批量写入到存储或索引系统、或者被发送到另外的Channel

Channel

Channel是位于SourceSink之间的缓冲区。因此,Channel允许SourceSink运作在不同的速率上。Channel是线程安全的,可以同时处理几个Source的写入操作和几个Sink的读取操作。 Flume自带两种ChannelMemory ChannelFile Channel Memory Channel:是内存中的队列。Memory Channel在不需要关心数据丢失的情景下适用。程序死亡、机器宕机或者重启都会导致数据丢失。 File Channel:将所有事件写到磁盘。因此在程序关闭或机器宕机的情况下不会丢失数据。

Event

传输单元,Flume数据传输的基本单元,以Event的形式将数据从源头送至目的地。

EventHeaderBody两部分组成

Header用来存放该event的一些属性,为K-V结构

Body用来存放该条数据,形式为字节数组。

Flume入门

Flume官网地址:flume.apache.org/

文档查看地址:flume.apache.org/FlumeUserGu…

下载地址:archive.apache.org/dist/flume/

Flume安装部署

  1. apache-flume-1.9.0-bin.tar.gz上传到linux的/opt/software目录下
  2. 解压apache-flume-1.9.0-bin.tar.gz/opt/module/目录下
tar -zxvf /opt/software/apache-flume-1.9.0-bin.tar.gz -C /opt/module/
  1. 修改apache-flume-1.9.0-bin的名称为flume
mv /opt/module/apache-flume-1.9.0-bin /opt/module/flume
  1. lib文件夹下的guava-11.0.2.jar删除以兼容Hadoop 3.1.3
rm /opt/module/flume/lib/guava-11.0.2.jar
  1. 修改conf下的log4j.properties确定日志打印的位置
#console表示同时将日志输出到控制台
flume.root.logger=INFO,LOGFILE,console
#固定日志输出的位置
flume.log.dir=/opt/module/flume/logs
#日志文件的名称
flume.log.file=flume.log

Flume入门案例

官方案例

  1. 案例需求: 使用Flume监听一个端口,收集该端口数据,并打印到控制台。

  2. 实现步骤: (1)安装netcat工具

    sudo yum install -y nc
    

    (2)判断44444端口是否被占用

    sudo netstat -nlp | grep 44444
    

    (3)在flume目录下创建job文件夹 (4)在job文件夹下创建Flume Agent配置文件nc_to_logger.conf

    vim nc_to_logger.conf
    

    (5)在nc_to_logger.conf文件中添加如下内容,加内容如下:

# Name the components on this agent
# 设置agent各个组件名称,包括sources,channels,sinks
a1.sources = r1
a1.sinks = k1
a1.channels = c1

# Describe/configure the source
# 设置source为netcat,地址为localhost,端口为44444
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444

# Describe the sink
# 设置sink类型为logger控制台输出
a1.sinks.k1.type = logger

# Use a channel which buffers events in memory
#设置channel类型为内存类型,大小为1000M
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100

# Bind the source and sink to the channel
# 绑定sources,channel,sink的对应关系
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

注:配置文件来源于官方手册flume.apache.org/FlumeUserGu…

所有组件的其他类型的配置方式均可参考官网所给出的配置方法

(6)先开启flume监听端口

  • 第一种写法:
bin/flume-ng agent --conf conf/ --name a1 --conf-file job/nc_to_logger.conf
  • 第二种写法:
bin/flume-ng agent -c conf/ -n a1 -f job/nc_to_logger.conf

参数说明:

--name/-n:表示给agent起名为a1

--conf/-c:表示配置文件存储在conf/目录

--conf-file/-f:flume本次启动读取的配置文件是在job文件夹下的nc_to_logger.conf文件。

(6)使用netcat工具向本机的44444端口发送内容

[user@hadoop102 ~]$ nc localhost 44444
10 
OK

(7)在Flume监听页面观察接收数据情况

[INFO -org.apache.flume.sink.LoggerSink.process(LoggerSink.java:95)] Event: { headers:{} body: 31 30                   10 }

​ 解析:由于我们没有对事务进行头部的添加,因此headers为空,传输的10被转换为字节数组存储在body中,1的16进制ASCII码为31,0的16进制ASCII码为30,因此body数组中存储的为31 30

(8)event打印的源码介绍 LoggerSinkprocess方法:

if (event != null) {
    if (logger.isInfoEnabled()) {
        logger.info("Event: " + EventHelper.dumpEvent(event, maxBytesToLog));
    }
}

dumpEvent方法返回值:buffer是固定长度的字符串,前端是16进制表示的字符的阿斯卡码值。

return "{ headers:" + event.getHeaders() + " body:" + buffer + " }";

实时监控目录下的多个追加文件

Taildir Source适合用于监听多个实时追加的文件,并且能够实现断点续传

(1) 案例需求

使用Flume监听整个目录的实时追加文件,并上传至HDFS

(2) 实现步骤

  1. job目录下创建配置文件file_to_hdfs.conf,添加如下内容
a1.sources = r1
a1.sinks = k1
a1.channels = c1

# Describe/configure the source
a1.sources.r1.type = TAILDIR
a1.sources.r1.filegroups = f1 f2
# 必须精确到文件,可以写匹配表达式匹配多个文件
a1.sources.r1.filegroups.f1 = /opt/module/flume/files1/.*file.*
a1.sources.r1.filegroups.f2 = /opt/module/flume/files2/.*log.*
# 实现断点续传的文件存放位置 不改有默认位置也能实现断点续传
a1.sources.r1.positionFile = /opt/module/flume/taildir_position.json


# Describe the sink
a1.sinks.k1.type = hdfs
# 地址值可以填写hdfs://hadoop102:8020也可以省略,flume会自动读取hadoop配置文件信息获取地址
a1.sinks.k1.hdfs.path = hdfs://hadoop102:8020/flume/%Y%m%d/%H
#上传文件的前缀
a1.sinks.k1.hdfs.filePrefix = log-

#是否使用本地时间戳
a1.sinks.k1.hdfs.useLocalTimeStamp = true

#设置文件类型 分为二进制文件SequenceFile和文本文件DataStream(不能压缩) 和CompressedStream(可以压缩)
a1.sinks.k1.hdfs.fileType = DataStream

#多久生成一个新的文件
a1.sinks.k1.hdfs.rollInterval = 30
#设置每个文件的滚动大小大概是128M
a1.sinks.k1.hdfs.rollSize = 134217700
#文件的滚动与Event数量无关
a1.sinks.k1.hdfs.rollCount = 0

# 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
  1. 在/opt/module/flume目录下创建files1files2文件夹

  2. 启动监控文件夹命令

bin/flume-ng agent --conf conf/ --name a1 --conf-file job/file_to_hdfs.conf
  1. 向文件夹中添加文件
echo hello >> file1.txt
echo world >> file2.txt
  1. 查看HDFS上的数据

Taildir说明: Taildir Source维护了一个json格式的position File,其会定期的往position File中更新每个文件读取到的最新的位置,因此能够实现断点续传。

Linux中储存文件元数据的区域就叫做inode,每个inode都有一个号码,操作系统用inode号码来识别不同的文件,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。TailDir source使用inode和文件的全路径一起识别同一个文件,所以修改文件名之后如果表达式也能够匹配上,会再重新读取一份文件的数据

Flume进阶

Flume事务

Flume事务.png

Put事务流程:

  • doPut:将批数据先写入临时缓冲区putList
  • doCommit:检查channel内存队列是否足够合并
  • doRollbackchannel内存队列空间不足,回滚数据

Take事务:

  • doTake:将数据取到临时缓冲区takeList,并将数据发送到HDFS
  • doCommit:如果数据全部发送成功,则清除临时缓冲区takeList
  • doRollback:数据发送过程中如果出现异常,rollback将临时缓冲区takeList中的数据归还给channel内存队列

Flume Agent内部原理

graph TD
Data --1.接收数据-->Source
Source--2.处理事件-->Channel_Processor
Channel_Processor--3.将事件传递给拦截器链-->Interceptor1
Interceptor1-->Interceptor2
Interceptor2-->Interceptor3
Interceptor3-->Channel_Processor
Channel_Processor--4.将事件交给Chnnel选择器-->Channel_Selector
Channel_Selector--5.返回写入事件的Channel列表-->Channel_Processor
Channel_Processor--6.将事件写入相应Channel-->Channel1
Channel_Processor-->Channel2
Channel_Processor-->Channel3
Channel1-->SinkProcessor
Channel2-->SinkProcessor
Channel3-->SinkProcessor
SinkProcessor-->Sink1
SinkProcessor-->Sink2
SinkProcessor-->Sink3

ChannelSelector

ChannelSelector的作用就是选出~将要被发往哪个Channel

其共有两种类型,分别是Replicating(复制)和Multiplexing(多路复用)

  • ReplicatingSelector会将同一个Event发往所有的Channel

  • Multiplexing会根据相应的原则,将不同的Event发往不同的Channel

SinkProcessor

SinkProcessor共有三种类型,分别是

  • DefaultSinkProcessor(默认1对1)

  • LoadBalancingSinkProcessor(负载均衡)

  • FailoverSinkProcessor(故障转移)

DefaultSinkProcessor对应的是单个的Sink

LoadBalancingSinkProcessorFailoverSinkProcessor对应的是Sink Group

LoadBalancingSinkProcessor可以实现负载均衡的功能

FailoverSinkProcessor可以错误恢复的功能

自定义拦截器

在实际的开发中,一台服务器产生的日志类型可能有很多种,不同类型的日志可能需要发送到不同的分析系统。此时会用到Flumechannel selecter中的Multiplexing结构,Multiplexing的原理是,根据eventHeader的某个key的值,将不同的event发送到不同的Channel中,所以我们需要自定义一个Interceptor,为不同类型的event的Header中的key赋予不同的值。

我们以端口数据模拟日志,以数字(单个)和字母(单个)模拟不同类型的日志,我们需要自定义interceptor区分数字和字母,将其分别发往不同的分析系统(Channel)

实现步骤

  1. 创建一个maven项目,并引入以下依赖
<dependencies>
	<dependency>
		<groupId>org.apache.flume</groupId>
		<artifactId>flume-ng-core</artifactId>
		<version>1.9.0</version>
	</dependency>
</dependencies>
  1. 定义MyInterceptor类并实现Interceptor接口
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;

import java.util.List;
import java.util.Map;
/**
 * 1. 实现interceptor接口
 * 2. 实现接口的4个方法
 * 3. 实现一个静态内部类创建拦截器
 */
public class MyInterceptor implements Interceptor {
	//初始化方法,不需要实现
    @Override
    public void initialize() {}

	//处理单条event
    @Override
    public Event intercept(Event event) {
        // 需要配合channel选择器使用  向headers当中put对应的参数
        // 根据传入的数据 首位是数字还是字母  判断他是不同类型的日志
        byte[] body = event.getBody();
        byte b = body[0];
        Map<String, String> headers = event.getHeaders();
        if (b >= '0' && b <= '9'){
            // b为数字
            headers.put("type","number");
        }else if((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')){
            // b 为字母
            headers.put("type","letter");
        }
        // 可以不需要在写放回headers(可写可不写)
        event.setHeaders(headers);
        return event;
    }

    //处理多条event,调用上述的处理单挑event的方法即可
    @Override
    public List<Event> intercept(List<Event> events) {
        for (Event event : events) {
            intercept(event);
        }
        return events;
    }

    //close方法,不需要实现
    @Override
    public void close() {}

    // 静态内部类
    public static class MyBuilder implements Builder{
        //以建造者模式为设计模式,build方法返回该拦截器对象
        @Override
        public Interceptor build() {
            return new MyInterceptor();
        }
        // 配置方法,不需要实现
        @Override
        public void configure(Context context) {}
    }
}

将代码打包,然后将jar包放到flume根目录的lib目录下,方便flume去调用

flume配置文件配置自定义的拦截器

# 拦截器配置
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = com.atguigu.flume.MyInterceptor$MyBuilder

注意:在拦截器的type参数中为自定义拦截器的全类名$静态内部类名

Flume数据流监控

Ganglia的安装与部署

(1) 安装Ganglia

  1. hadoop102、hadoop103、hadoop104分别安装epel-release依赖
sudo yum -y install epel-release
  1. hadoop102安装gmetadwebgmond
sudo yum -y install ganglia-gmetad 
sudo yum -y install ganglia-web
sudo yum -y install ganglia-gmond
  1. hadoop103、hadoop104安装gmond
sudo yum -y install ganglia-gmond

(2) 在hadoop102修改配置文件/etc/httpd/conf.d/ganglia.conf

sudo vim /etc/httpd/conf.d/ganglia.conf
#
# Ganglia monitoring system php web frontend
#
Alias /ganglia /usr/share/ganglia
<Location /ganglia>
  #Order deny,allow
  #Deny from all
  #Allow from 127.0.0.1
  #Allow from ::1
  # Allow from .example.com
  Require all granted
</Location> 

(3) 在hadoop102修改配置文件/etc/ganglia/gmetad.conf

sudo vim /etc/ganglia/gmetad.conf

修改为:

data_source "hadoop102" hadoop102

(4) 在hadoop102、hadoop103、hadoop104修改配置文件/etc/ganglia/gmond.conf

sudo vim /etc/ganglia/gmond.conf
cluster {
  name = "hadoop102"
  owner = "unspecified"
  latlong = "unspecified"
  url = "unspecified"
}
udp_send_channel {
  #bind_hostname = yes # Highly recommended, soon to be default.
                       # This option tells gmond to use a source address
                       # that resolves to the machine's hostname.  Without
                       # this, the metrics may appear to come from any
                       # interface and the DNS names associated with
                       # those IPs will be used to create the RRDs.
  # mcast_join = 239.2.11.71
  # 数据发送给hadoop102
  host = hadoop102
  port = 8649
  ttl = 1
}
udp_recv_channel {
  # mcast_join = 239.2.11.71
  port = 8649
  # 接收来自任意连接的数据
  bind = 0.0.0.0
  retry_bind = true
  # Size of the UDP buffer. If you are handling lots of metrics you really
  # should bump it up to e.g. 10MB or even higher.
  # buffer = 10485760

(5) 在hadoop102修改配置文件/etc/selinux/config

sudo vim /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

注意:selinux本次生效关闭必须重启,如果此时不想重启,可以临时生效

sudo setenforce 0

(6) 启动ganglia

  1. hadoop102、hadoop103、hadoop104启动gmond
sudo systemctl  start gmond
  1. hadoop102启动httpdgmetad
sudo systemctl start httpd
sudo systemctl start gmetad

(7) 打开网页浏览ganglia页面

http://hadoop102/ganglia