• flume--为搬砖而生,日志传输的一把好手


    (一)flume的产生

    为什么会有flume

    随着互联网的发展,人们对网络日志产生的信息也越来越重视。不仅如此,我们的服务器,比如Nginx,每天都会产生大量的日志。我们要将这些日志收集到指定的地方,比如hdfs平台,进行分析。但是大量的日志产生的位置比较分散,可能来自于Tomcat、Nginx、甚至是数据库等等,而且存储的目的地也不一样,这就导致了数据采集的复杂性。然鹅最关键的问题是,如果在采集的过程中,出现问题了该怎么办?比如我们要把日志收集到hdfs平台上进行分析,我们可以通过hdfs shell的方式,但是我们无法对日志采集的状况进行监控。针对以上种种问题,flume就诞生了,因此看到这里小伙伴也能猜到flume是干什么的了。

    flume是什么

    关于flume是什么?官网给出了定义,我们来看一下。因为flume是Apache的一个顶级项目,所以官网就是flume.apache.org

    flume是一个分布式、高可靠、高可用的服务,用于高效地收集、聚合、移动大量的数据集。flume具有一个简单、灵活并基于数据流的架构,它具备可调节的可靠机制和许多故障转移以及恢复机制,并具有很强的健壮性和容错性。通过使用一种简单可扩展的数据模型来提供应用程序的在线分析。

    我们从图中,可以看到一个长方形,里面围住的部分就是flume的一个agent。我们通过flume移动数据就相当于在写一个配置文件。source:源。表示我们要从哪里收集,比如这里来自于web服务器。sink:下沉。表示我们要把数据沉到什么地方去,这里是hdfs。那么中间还有一个channel是干什么的呢?channel:管道,我们不会把刚收集到的日志立刻sink到hdfs上面,那样效率太慢,而是会先存到channel里面,这个channel就是消息队列,一般是kafka,当管道满了,然后再把管道里面的数据一次性sink的目的地,这里是hdfs。

    因此通俗一点的说:

    flume就是一个日志采集工具,或者理解为一个搬运工,将日志从一个地方搬到另一个地方去。特征是:具备高可用、高可靠、分布式处理模式。里面定制了很多的source和sink,支持我们从不同的源端读取日志文件,然后sink到不同的地方去。

    flume的特征

    • flume可以高效率地从多个服务器中收集日志并存储到hdfs/hbase中

    • 除了日志信息,flume也可以用来接入收集规模宏大的社交网络节点事件数据,比如Facebook、Twitter等等

    • 支持各种不同数据源,并能够输送到不同的地方

    • 支持多路径,多管道输入,多管道输出,上下文路由等等

      什么意思呢?意思就是我们sink的时候,也可以作为下一个agent的source,不一定要是hdfs等平台,并且多个sink还可以到同一个source里面。
      

      同理,一个source也可以到多个channel,然后sink到多个地方
      

    • 可以水平扩展

    flume的应用场景

    flume其实还可以有其他的功能,比如数据的处理,但是在大数据实际应用中,flume基本上只用于日志收集工作,根据不同的业务场景,编写不同的配置文件。
    

    (二)flume的client

    flume的客户端

    什么是flume的客户端呢?实际上,部署flume的机器就可以称之为一个客户端。部署flume,是不是需要一些环境呢?
    

    根据官网的要求,至少要满足以下几点

    • 1.jdk1.8或更高,大数据的这些组件都和java脱不开关系
    • 2.内存。因为flume是基于流式的,因此内存也是必须的
    • 3.磁盘空间,我们不会把数据一直保存到内存里面,最终要刷到磁盘上,因此磁盘空间也是必须的。
    • 4.目录权限,你要往一个目录里面写文件的话,总要有写或者读的权限吧

    感觉2、3、4都是废话,这不是显然的吗?

    (三)flume的source

    我们之前说过,一个agent就相当于一个配置文件,里面有三剑客,分别是source、channel、sink。通过编写配置文件,配置source、channel、sink,来将数据从一端传输到另一端。
    我们来看看source。
    

    source就是我们的源端,从不同的数据源读取日志信息放到channel里,然后sink取出channel里面的日志信息到其他的地方,比如hdfs、hbase等等。

    因此flume的架构很好理解,就这三个组成部分。既然flume的source支持不同的数据源,那么我们就来看看,它都支持哪些不同的数据源呢?

    source支持的数据源

    支持以下几种source

    • Avro Source

      flume第一种数据来源,可以监听IP和端口,并不一定是本机的IP,可以监听其他机器的IP和port,用于获取数据。从外部的Avro client streams接收events,当与另一个flume agent内置的avro sink配对时,可以创建分层搜集的拓扑结构。感觉官网说的好阳春白雪,其实说白了,还是下面这张图,一个agent的source可以是上一个agent的sink,之间通过avro去连接

      字体加粗的属性必须进行设置

      因为source的类型是avro,因此type也要指定为avro

    • Thrift Source

      和avro source基本类似,但是avro可以支持ip过滤,但是thrift不支持。
      

      因为source是thrift,所以type要改成thrift。是什么样的source,那么type就改成什么。

    • Exec Source

      比较常用的一种source,可以运行Unix命令,然后该命令会一直执行,读取文件,作为flume数据的来源,需要配置相应的channel、type、以及运行的命令。并且根据官网介绍,本方式不保证数据百分百会传送到指定的位置,如果出现问题,数据可能丢失。可以使用Spooling Directory等其他手段,保证数据传输

    • JMS Source

      本方式会从JMS消息队列的目的地,比如一个队列或者一个topic中读取数据;需要在plugins.d即插件目录下放置相应的jar包;不过此来源一般用的较少,因为局限性比较强。

    • Spooling Directory Source

      Spooling Directory Source监测配置的目录下新增的文件,并将文件中的数据读取出来。其中,Spool Source有2个注意地方,第一个是拷贝到spoolDir指定的目录下的文件不可以再打开编辑,第二个是spool目录下不可包含相应的子目录。这个主要用途作为对日志的准实时监控。

      加粗的表示必须填写,其中spooldir,就是我们指定的目录,当然type也要指定为spooldir

    • 自定制source

      其实flume提供的source还是不能完全满足我们的需求,因此我们也可以自定义source。
      

    当然还有其它source,不过不常用。这里可能有点抽象,先来清楚一下概念,了解一下flume的架构、各个组成部分的功能,后续会进行演示

    (四)flume的channel

    还是这张放了好几遍的图,source我们已经介绍过了,下面介绍channel。
    channel我们其实我们之前也说过了,是一个管道,类似于golang里面的channel。或者我们把它理解为一个缓存也行,source收集过来的日志并不直接sink到hdfs上面,而是会放到缓存里面,等缓存满了再一次性sink到指定的地方。
    为什么要这么设计呢?介绍source收集日志的速度很快,但是sink的速度很慢,如果source直接对接sink的话,那么就会导致读写速度不一致了,这就跟双十一要引入消息队列一样,如果上游的订单系统直接对接下游的库存系统,那么上游爆发的流量很容易将下游冲垮,所以才需要引入消息队列进行削峰填谷,两者的道理是类似的。
    
    关于缓存,有两种。一种是基于内存的缓存,另一种是基于磁盘的缓存。
    基于内存的缓存:速度快,但是不安全,而且容量有限
    基于磁盘的缓存:可靠性高,容量大,但是读写速度会慢一些。
    

    flume官方为我们提供了如下channel

    基于内存的channel,我们很少使用,因为数据容易丢失。File channle和kafka channel很常用

    比如file  channel,那么这里的type要指定为file,因为这里的缓存使用文件来实现的。配置的话可以指定大小

    (五)flume的sink

    我们之前说过,source是用于收集数据,channel是用于缓存数据,sink是用于将数据写到外部的存储设备。那我们外部的存储设备不一样,那么sink的类型就会不一样,因此sink实际上也是可定制的,可配置的。对于不同的外部地址,那么sink就有不同的实现。

    flume也为我们提供了很多sink,比如hdfs sink、hive sink等等。当然还有avro sink,这个在之前介绍过,是为了对接下一个agent的avro source

    当然每一个sink都有很多额外的配置,比如文件的前缀啊、回滚间隔、回滚策略啊等等

    (六)flume的interceptor

    flume的拦截器,这是什么?

    flume可以在移动数据时修改/删除事件,这是在拦截器的帮助下完成的。所有的拦截器都是实现了org.apache.flume.interceptor.Interceptor接口的类,拦截器可以基于开发人员所选择的任意条件来修改、甚至删除事件。并且flume还支持链式的拦截器(补充:意思就是可以设置多个拦截器,然后顺序的调用。),这可以通过在配置中指定多个拦截器的类名组成的列表来实现。拦截器在源配置中通过一系列的空格进行分隔,拦截器被指定的顺序也是它们被调用的顺序,每一个拦截器所返回的事件在列表中会链式的传递到下一个拦截器,并且可以修改或者删除事件。如果一个拦截器需要删除事件,那么它只需要在列表中将该返回的事件不进行返回即可。如果要删除所有事件,只需要简单地返回一个空列表即可。拦截器是一个命名组件,以下是如何通过配置创建拦截器的一个例子。
    

    拦截器主要用于source端,我们可以将获取的数据拦截下来,然后加上一个键值对,可以指定文件的名字、来源、时间戳等等,然后sink到不同的地方去。比如我们 收集了很多日志,比如登陆日志、行为日志等等,那么我们在拦截的时候,便可以指定哪些日志都是什么类型,然后输出的时候,不同的日志输出到不同的地方去

    (七)flume的selector

    我们的source在收集完数据之后要写到哪一个channel里面呢?比如我们搜集的日志有三种,一种是只包含字母,另一种只包含数字,最后一种只包含符号(假设是这样蛤)。hdfs上面有三个文件,正好对应三种日志类型。现在我们的问题是,不同类型的日志怎么存到不同的文件里面去呢?既然要存到不同的文件里面,那么首先要存到不同的channel里面,channel1只包含字母、channel2只包含数字、channel3只包含符号,然后sink1对接channel1、sink2对接channel2、sink3对接channel3,理论上情况是这样的。

    但是现在问题又来了,怎么存到不同的channel里面呢?这个时候选择器就出现了

    官网提供了哪些selector呢

    • Replicating Channel Selector (default)

      这也是默认的channel,type指定为replicating。意思是数据会复制到每一个channel中。
      
    • Multiplexing Channel Selector

      复分模式的channel,不会把数据拷贝了,而是将数据整体分发到不同的channel中,当然要指定type为multiplexing。可以看到不管是source、channel、sink还是这里的selector,都有不同的类型,然后在各自的type中指定即可。
      
    • Custom Channel Selector

      自己实现的channel,不同的数据分发到不同的channel中,相当于对Multiplexing Channel Selector进行了自定制,这样就可以按照我们自己的逻辑来决定数据分发到哪一个channel当中。
      

    (八)flume的event

    例如一些消息队列,发送的数据并不是原生的数据,而是对数据要进行一个封装,我们可以通过python往activemq里面发送数据,然后使用golang去接。但是python最终发到mq里面不是一个简单的数据,golang接收的也不是一个简单的数据,而是对数据进行了一个封装。同理flume也是一样,在flume中,有一个event,我们好像在拦截器的时候提到过,那么它是什么呢?event在flume当中叫做事件,flume在传输日志的时候,每一条数据都会被封装成一个event。

    为什么要有event呢?

    首先我们可以想一下,数据格式有很多种,source也不同,channel不同、sink也各不相同,那么我如何才能将其统一起来呢?这个时候就需要event了,将每一条记录都封装为大家都认识event不就行了吗?这就是为什么要有event。当然event主要包含两个部分,一个是header,一个body。body是一个字节数组,里面记录了日志信息,header则是一个hashmap,我们可以添加一些自己的信息,如果只有body没有header的话,那么我们的信息就会打到body里面,这样就对我们要传送的数据造成污染了,具有侵入性,所以要有header
    

    (九)flume的agent

    agent是flume的运行核心,是flume运行的最小单位。一个flume的agent就是包含了source、channel、sink的一个jvm进程,用于日志的收集和传输。
    

    首先我们到目前为止介绍的都是概念,其实flume的概念也很好理解,主要就是各个组件的那些配置还没有介绍,后面会介绍,目前先了解flume的基础架构即可。因此之前也说过,用flume传输日志,就相当于在指定agent中各个组件的配置。一个agent可以包含多个source、多个channel、多个sink

    A Flume event is defined as a unit of data flow having a byte payload and an optional set of string attributes. A Flume agent is a (JVM) process that hosts the components through which events flow from an external source to the next destination (hop).
    一个flume事件被定义为一个数据流单元,具有字节负载和可选的字符属性集。一个flume agent就是一个jvm进程,承载着各个组件(source、channel、sink),事件可以通过这些组件从外部源流向下一个目的地。
    

    当然不要忘记,agent还是可以串联的,一个agent的sink对接下一个agent的source

    (十)flume的安装

    flume下载地址:http://archive.cloudera.com/cdh5/cdh/5
    选择flume即可,为什么不到官网下载,因为cdh版本的话可以避免很多问题,比如jar包的冲突。
    因此大数据组件安装的话,推荐去这个网站下载,不建议使用社区版本的。
    

    我用的是阿里云的云服务器,所有大数据相关的软件都放在/opt目录下,因此我们在/opt下面新建一个flume目录,然后把相应的安装包放进去解压

    解压完成之后,我们来看看flume的结构

    我们进入conf目录下,修改一下配置。如果我们只修改一个配置的话,那么需要修改什么呢?不用想,肯定是jdk的路径。对,我们需要在flume-env.sh中指定JAVA_HOME,但是进入目录发现没有这个文件,但是有一个flume-env.sh.template,这是模板,我们用这个模板生成一个即可

    然后将flume加到环境变量里面去

    export FLUME_HOME=/opt/flume/apache-flume-1.6.0-cdh5.7.5-bin
    export PATH=$FLUME_HOME/bin:$PATH
    

    然后source一下

    输入flume-ng version查看版本,和其他框架不一样,flume的话需要加上-ng,至于原因后面会说。
    

    (十一)flume的两种版本

    flume分为两个版本,一个1.x之前的版本,叫做flume og,另一个是1.x版本,叫做flume ng
    至于差别就不介绍了,总之现在用的话就是用flume 1.x版本的就行了。
    

    (十二)flume的avro_source

    任务:使用avro_source收集数据,打印到控制台

    终于到实战部分了,我们下面就通过编写配置文件的方式来移动数据,之前也说了,使用flume就是编写配置文件。
    至于channel,我们就无所谓了,使用内存channel还是磁盘channel都无所谓,我们这里主要是介绍source。而sink则就是控制台
    

    那么配置怎么写呢?

    # 这里的a1就是我们agent的名字
    a1.sources = r1  #  命名agent的source为r1
    a1.channels = c1  # 同理c1是channel的名字
    a1.sinks = k1  # 同理k1是sink的名字
    
    a1.sources.r1.type = avro  # 配置r1的的类型avro
    a1.sources.r1.bind = localhost  # 绑定的端口为本地
    a1.sources.r1.port = 4141  # 端口为4141
    
    a1.channels.c1.type = memory  # 指定c1的类型为内存
    a1.channels.c1.capacity = 1000  # 指定c1的容量为1000个event
    a1.channels.c1.transcactionCapacity = 1000  # 指定c1的每次处理容量为1000个event
    
    a1.sinks.k1.type = logger  # 表示不产生实体文件,就打印在控制台
    
    # 将source和sink与channel绑定起来
    a1.sources.r1.channels = c1  # source r1的channel指定为c1 
    a1.sinks.k1.channel = c1  # sink k1的channel指定为c1。但是这里不再是channels,而是channel,要注意
    

    我们随便在一个目录,新建一个文件,将上面的内容去掉注释然后写进去

    那么如何启动flume呢?
    flume-ng agent -c $FLUME_HOME/conf -f 我们写的配置文件的路径 -n a1 -Dflume.root.logger=INFO,console
    
    参数解释:
    -c $FLUME_HOME/conf:首先flume启动是有默认配置的,这个配置就在$FLUME_HOME/conf下面
    -f 我们写的配置文件的路径:这个很好理解,我们自己写的配置可以通过-f来指定
    -n a1:我们在配置文件中指定的agent名字
    -Dflume.root.logger=INFO,console:表示flume自身运行状态的日志,按需配置,详细信息控制台打印
    

    我们启动服务,由于我们自己的conf就在当前目录下,所以直接flume-ng agent -c $FLUME_HOME/conf -f ./conf -n a1 -Dflume.root.logger=INFO,console启动即可

    服务已经启动了,监听本地的4141端口,那么我们就往这个端口里面发送数据。

    发送数据,我们可以发送一个文件,可以使用flume自带的一个方法。
    flume-ng avro-client -c $FLUME_HOME/conf -H localhost -p 4141 -F ~/.bashrc
    
    avro-client:创建一个客户端
    -c $FLUME_HOME/conf:指定配置,刚才说了
    -H localhost:指定目的ip
    -p 4141:指定目的端口
    -F ~/.bashrc:指定发送的文件
    

    显示内容已经接受到了,会将文件打开,每一条都是一个event,包含header(我们这里没有指定)和event(是一个字节数组)

    (十三)flume的exec_source

    下面来看看flume的exec_source,flume之所以有这么多source、channel、sink,主要是为了解决不同场景的业务,那么这个exec_source是用来干什么的呢?
    

    exec_source可以实时监控一个文本文件,如果文件有变化,可以打印出来

    下面就来写配置文件,在当前目录新建一个conf1,写上如下内容(不含注释)

    a1.sources = r1  #  命名agent的source为r1
    a1.channels = c1  # 同理c1是channel的名字
    a1.sinks = k1  # 同理k1是sink的名字
    
    a1.sources.r1.type = exec  # 配置r1的的类型exec
    # a1.sources.r1.bind = localhost  # 绑定的端口为本地
    # a1.sources.r1.port = 4141  # 端口为4141
    # 由于是监控一个文件,所以不需要在绑定ip和端口了
    a1.sources.r1.command = tail -F /root/mashiro.txt  # 指定命令,监控这个文件
    
    a1.channels.c1.type = memory  # 指定c1的类型为内存
    a1.channels.c1.capacity = 1000  # 指定c1的容量为1000个event
    a1.channels.c1.transcactionCapacity = 1000  # 指定c1的每次处理容量为1000个event
    
    a1.sinks.k1.type = logger  # 表示不产生实体文件,就打印在控制台
    
    # 将source和sink与channel绑定起来
    a1.sources.r1.channels = c1  # source r1的channel指定为c1 
    a1.sinks.k1.channel = c1  # sink k1的channel指定为c1。但是这里不再是channels,而是channel,要注意
    

    启动flume,flume-ng agent -c $FLUME_HOME/conf -f ./conf1 -n a1 -Dflume.root.logger=INFO,console

    此时服务启动成功,但是还没有东西过来

    (十四)file channel

    基于内存的channel,我们在介绍source的时候,演示过了,下面来看看基于文件的channel。
    
    a1.sources = r1  
    a1.channels = c1 
    a1.sinks = k1  
    
    a1.sources.r1.type = exec 
    a1.sources.r1.command = tail -F /root/mashiro.txt  
    
    a1.channels.c1.type = file  # 指定类型为file
    a1.channels.c1.checkpointDir = /root/checkPoint  # checkpoint将被存储的目录
    a1.channels.c1.dataDirs = /root/data  # 数据的存储位置
    
    a1.sinks.k1.type = logger  # 表示不产生实体文件,就打印在控制台
    
    # 将source和sink与channel绑定起来
    a1.sources.r1.channels = c1  # source r1的channel指定为c1 
    a1.sinks.k1.channel = c1  # sink k1的channel指定为c1。但是这里不再是channels,而是channel,要注意
    

    先来看看/root目录的内容

    然后执行命令,flume-ng agent -c $FLUME_HOME/conf -f ./conf2 -n a1 -Dflume.root.logger=INFO,console

    再来查看当前目录

    可以看到checkPoint和data两个目录,而且这是flume帮我们创建的,我们来往文件里面写点东西

    (十五)hdfs sink

    下面介绍sink,这里介绍一下hdfs sink,因为收集过来的日志主要放到hdfs平台上面。
    既然要把收集的数据放大hdfs上面,那么flume就必须能连接hdfs,需要把依赖的jar包,放到$FLUME_HOME/lib下面,需要哪些jar包呢?又从哪里找呢?我们可以从$HADOOP_HOME/share/hadoop目录里面找。
    commons-configuration-x.x.jar  
    hadoop-auth-x.x.x.jar
    hadoop-common-x.x.x.jar
    hadoop-hdfs-x.x.x.jar
    # jar前面的x表示版本号,在找的时候可以使用模糊查询,比如我现在在$HADOOP_HOME/share/hadoop目录下,要找commons-configuration-x.x.jar  的话,便可以通过find ./ -name commons-configuration*即可。
    
    如果你的flume版本是1.99的话,那么还需要以下两个jar包,否则的话就不需要
    commons-io-x.x.jar
    htrace-core-.x.x.x-incubating.jar
    
    找到之后,cp到$FLUME_HOME/lib下面
    

    下面就是编写配置文件

    # 给source、channel、sink指定名字
    a1.sources = r1
    a1.channels = c1
    a1.sinks = k1
    
    # source的配置
    a1.sources.r1.type = exec
    a1.sources.r1.command = tail -F /root/test.log
    
    # channel的配置
    a1.channels.c1.type = memory
    a1.channels.c1.capacity = 1000
    a1.channels.c1.transactionCapacity = 100
    
    # sink的配置
    a1.sinks.k1.type = hdfs
    a1.sinks.k1.hdfs.path = hdfs://localhost:9000
    # 这条配置是给文件起一个前缀
    a1.sinks.k1.hdfs.prefix = hive-  
    
    # 绑定channel
    a1.sources.r1.channels = c1
    a1.sinks.k1.channel = c1
    
  • 相关阅读:
    解决phpcms图片太大撑破表格图片自适应图片按比例缩小
    CSS代码使纯英文数字自动换行
    CSS网页布局错位:CSS宽度计算
    CSS控制div宽度最大宽度/高度和最小宽度/高度
    鼠标HOVER时区块动画旋转变色的CSS3样式掩码
    记录--正则表达式
    写在前面
    ruby Mixin用法
    ruby 模块 的引入
    ruby 编写迭代器
  • 原文地址:https://www.cnblogs.com/traditional/p/11289126.html
Copyright © 2020-2023  润新知