Flume
概述
Flume 是 Cloudera 提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的软件
数据采集
- 数据从无到有的过程
- 把客观事件通过传感器等工具量化为数据
- 数据搬运迁移的过程
- 把数据从一个存储介质传递到另一个存储介质
flume的采集是数据搬运的采集
版本
Flume 0.9X
- 简称: Flume OG(original generation)
- 属于Cloudera
Flume 1.X
- 简称 Flume NG(next generation)
- 属于Apache
两个版本之间进行了架构重组, 存在较大的差异, 现在常用的是Flume NG
运行机制
Flume核心角色
- agent, 是一个java进程, 一般运行在日志收集节点
agent内部组件
- source
- 采集源
- 用于跟数据源对接, 获取数据
- sink
- 下沉地
- 将采集的数据传送到下一级agent 或者 存储到目的地
- channel
- agent内部的数据传输通道
- 缓存来自source的数据, 并传递给sink
整个传输过程中, 以event作为基本单元进行传输
- event包含
- event header (头信息)
- event body (消息体)
Flume安装
安装
- 上传安装包并解压
- flume-ng-1.6.0-cdh5.14.0.tar.gz
- 修改配置文件
- cp flume-env.sh.template flume-env.sh
- 从模板中拷贝一份进行修改
- 修改jdk路径
- export JAVA_HOME=/export/servers/jdk1.8.0_65
根据需求编写采集方案
- 可参考官方文档
指定采集方案的配置文件, 运行即可
简单案例
1. 监听本地网络端口, 把网络端口的数据采集并输出到console控制台
- 编写采集方案
- 确定组件类型
- source
- NetCat TCP Source
- channel
- Memory Channel
- sink
- Logger Sink (console)
- 编写采集方案配置文件
- netcat-logger.conf
# 定义这个 agent 中各组件的名字
- a1.sources = r1
- a1.sinks = k1
- a1.channels = c1
# 描述/配置 source 组件:r1
- a1.sources.r1.type = netcat
- a1.sources.r1.bind = localhost
- a1.sources.r1.port = 44444
# 描述/配置 sink 组件:k1
- a1.sinks.k1.type = logger
# 描述/配置 channel 组件,此处使用是内存缓存的方式
- a1.channels.c1.type = memory
- a1.channels.c1.capacity = 1000
- a1.channels.c1.transactionCapacity = 100
# 为source和sink绑定channel
- a1.sources.r1.channels = c1
- a1.sinks.k1.channel = c1
- 启动flume
- bin/flume-ng agent --conf conf --conf-file conf/netcat-logger.conf --name a1 -Dflume.root.logger=INFO,console
- bin/flume-ng agent -c ./conf -f ./conf/netcat-logger.conf -n a1 -Dflume.root.logger=INFO,console
- 参数说明
- –conf(-c)
- 指定flume自身的配置文件所在目录,
该路径下必须有两个文件
- flume-env.sh
- log4j.properties
- –conf-file(-f)
- 指定采集方案
- –name(-n)
- 指定agent进程名, 注意要和采集方案中的名字对应
- -Dflume.root.logger=INFO,console
- 开启日志, 打印在控制台
- 通过Telnet进行测试
- telnet anget-hostname port
2. 服务器的某特定目录下,会不断产生新的文件,每当有新文件出现,就需要把文件采集到 HDFS 中去
- 编写采集方案
- 确定组件类型
- source
- Spooling Directory Source
- channel
- Memory Channel
- sink
- HDFS Sink
- 编写采集方案配置文件
- spooldir-hdfs.conf
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /root/logs2 #注意:不能往监控目中重复丢同名文件
a1.sources.r1.fileHeader = true
# Describe the sink
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /flume/events/%y-%m-%d/%H%M/
a1.sinks.k1.hdfs.filePrefix = Woodpecker-
#配置时间取整, (目录多长时间切换) 例如: 当前时间为10:58, 则记为10-50
a1.sinks.k1.hdfs.round = true #是否开启时间取整
a1.sinks.k1.hdfs.roundValue = 10 #取整值
a1.sinks.k1.hdfs.roundUnit = minute #取整单位
#配置写入hdfs的方式为滚动方式
a1.sinks.k1.hdfs.rollInterval = 3 #按时间滚动的频率, 默认30s
a1.sinks.k1.hdfs.rollSize = 20 #按文件大小滚动, 默认1kb
a1.sinks.k1.hdfs.rollCount = 5 #按event个数滚动, 默认10个
a1.sinks.k1.hdfs.batchSize = 1
a1.sinks.k1.hdfs.useLocalTimeStamp = true
#生成的文件类型,默认是Sequencefile,可用DataStream,则为普通文本
a1.sinks.k1.hdfs.fileType = DataStream
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000 #该通道中最大的可以存储的 event 数量
a1.channels.c1.transactionCapacity = 100 #每次最大可以从 source 中拿到或者送到 sink 中的 event数量
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
- 注意
- 监听的目录必须提前存在
- 文件名不能重复
- 否则服务会中断
- 开启日志采集
- bin/flume-ng agent -c ./conf -f ./conf/spooldir-hdfs.conf -n a1 -Dflume.root.logger=INFO,console
- 采集结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-16VLRMcw-1593321933480)(assets/image-20200628125408707.png)]
3. 日志内容不断增加,需要把追加到日志文件中的数据实时采集到 hdfs
- 编写采集方案
- 确定组件类型
- source
- Exec Source
- channel
- Memory Channel
- sink
- HDFS Sink
- 编写采集方案配置文件
- tail-hdfs.conf
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /root/logs/test.log
# Describe the sink
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = /flume/tailout/%y-%m-%d/%H-%M/
a1.sinks.k1.hdfs.filePrefix = Woodpecker-
a1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 10
a1.sinks.k1.hdfs.roundUnit = minute
a1.sinks.k1.hdfs.rollInterval = 5
a1.sinks.k1.hdfs.rollSize = 1014
a1.sinks.k1.hdfs.rollCount = 3
a1.sinks.k1.hdfs.batchSize = 1
a1.sinks.k1.hdfs.useLocalTimeStamp = true
#生成的文件类型,默认是Sequencefile,可用DataStream,则为普通文本
a1.sinks.k1.hdfs.fileType = DataStream
# 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
- 启动flume
- bin/flume-ng agent -c ./conf/ -f ./conf/tail-hdfs.conf -n a1 -Dflume.root.logger=INFO,console
- 模拟数据
- while true;do date >> /root/logs/test.log;sleep 0.5;done
- 查看结果
- 控制台日志
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c53XOCLN-1593321933482)(assets/image-20200628125607627.png)] - hdfs上的结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-95gzYsLv-1593321933483)(assets/image-20200628125614066.png)]
用到的组件
- source
- netcat
监听网络端口数据
- spooldir
监视目录下文件的变化
注意:
被监视的目录必须存在
监视的目录中的文件名不能重复, 否则会报错, 然后停止监视服务
- exec
执行shell命令, 将命令执行的结果进行收集
tail -f xxx 监控文件尾部情况(主要是文件新增内容)
- http
监听HTTP的get和psot请求
- sink
- HDFS
roll相关配置 控制文件的滚动
round相关配置 控制目录的滚动
- channel
- memory channel
高阶特性
1. avro
- 在串联的flume架构中, 会涉及两级之间跨网络或跨进程传输数据
- flume专门设计了一套组件用于跨网络通信, 基于avro的rpc协议
- avro sink
- avro source
- 上级的avro sink通过ip、端口决定要发往哪个下级source
下级avro source绑定本机的ip和端口号, 进行监听, 等待上级sink传递数据
- 启动顺序
- 从远离数据源的方向开始启动
- avro串联成功, 可从日志中看到分别有OPEN, BOUND, CONNECTED信息
2. load-balance 负载均衡
- 概述
- 解决单个进程或机器无法响应所有请求, 由多个进程或机器共同处理的场景
- flume支持的算法
random 随机
round_robin 轮询
- 注意
- 当数据量较小, 单个agent能够应付所有请求的情况下, 即便配置了负载均衡, 也无法生效
- 配置方式
- 结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CQ9irycx-1593321933484)(assets/image-20200628130139497.png)] - 确定组件
- source
- Avro Source
- channel
- Memory Channel
- sink
- Avro Sink
- flume sink processor
- Load balancing Sink Processor
- 编写上级采集方案
- exec-avro.conf
#设置组件名
agent1.channels = c1
agent1.sources = r1
agent1.sinks = k1 k2
#设置下沉组名
agent1.sinkgroups = g1
#设置channel
agent1.channels.c1.type = memory
agent1.channels.c1.capacity = 1000
agent1.channels.c1.transactionCapacity = 100
#设置source
agent1.sources.r1.channels = c1
agent1.sources.r1.type = exec
agent1.sources.r1.command = tail -F /root/logs/123.log
#设置第一个sink
agent1.sinks.k1.channel = c1
agent1.sinks.k1.type = avro
agent1.sinks.k1.hostname = node-2
agent1.sinks.k1.port = 52020
#设置第二个sink
agent1.sinks.k2.channel = c1
agent1.sinks.k2.type = avro
agent1.sinks.k2.hostname = node-3
agent1.sinks.k2.port = 52020
#设置下沉组成员
agent1.sinkgroups.g1.sinks = k1 k2
#设置负载均衡
agent1.sinkgroups.g1.processor.type = load_balance
agent1.sinkgroups.g1.processor.backoff = true #是否开启黑名单
agent1.sinkgroups.g1.processor.selector = round_robin #设置负载均衡的算法为轮询, 还支持random(随机)
agent1.sinkgroups.g1.processor.selector.maxTimeOut=10000 #在黑名单放置的超时时间,超时结束时,若仍然无法接收,则超时时间呈指数增长
- 编写下级采集方案
- 第一台机器
- avro-logger.conf
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = avro
a1.sources.r1.channels = c1
a1.sources.r1.bind = node-2
a1.sources.r1.port = 52020
# Describe the sink
a1.sinks.k1.type = logger
# 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
- 第二台机器
- avro-logger.conf
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = avro
a1.sources.r1.channels = c1
a1.sources.r1.bind = node-3
a1.sources.r1.port = 52020
# Describe the sink
a1.sinks.k1.type = logger
# 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
3. failover 容错
- 概述
- 解决单点故障问题, 防止因为某台机器或进程出现故障而导致整个模块无法工作
- 整体流程与load-balance类似, 主要区别在于sink processor
- 确定组件
- source
- Avro Source
- channel
- Memory Channel
- sink
- Avro Sink
- flume sink processor
- Failover Sink Processor
- 具体配置方式参考官方说明文档
- 注意
- 在配置容错处理器时, 可以设置优先级, 优先级越大的作为主, 其他的都是备
- 当主出现故障, 由次优先级顶上
- 当优先级更高的主故障修复完毕, 重新上线, 则会重新成为主, 之前的主切换为备
- 如果没有指定优先级,则根据在配置中指定 Sink 的顺序来确定优先级
4. Flume拦截器
- 概述
- 拦截器(interceptor)是 Flume 中简单的插件式组件,设置在 source 和 channel 之间
- source 接收到的 event 事件,在写入 channel 之前,拦截器都可以进行转换或者删除这些事
- 每个拦截器只处理同一个 source 接收到的事件
- 分类
- 内置拦截器
- timestamp拦截器(时间戳)
- 功能
- 在event header插入时间戳
- 没有使用拦截器
- Event: { headers:{ } body: timestamp teset }
- 使用时间戳拦截器
- Event: { headers:{timestamp=1593165990402} body: timestamp teset }
- 配置参考官方文档
- host拦截器(主机名)
- 功能
- 在event header插入ip地址或者主机名
- 核心配置参数
- a1.sources.r1.interceptors = host
- a1.sources.r1.interceptors.host.type=host
- a1.sources.r1.interceptors.host.useIP=false
- a1.sources.r1.interceptors.timestamp.preserveExisting=true
- 详细配置参考
- static拦截器(静态)
- 功能
- 可在event header中插入自定义的kv键值对
- 核心配置参数
- a1.sources.r1.interceptors = i1
- a1.sources.r1.interceptors.i1.type = static
- a1.sources.r1.interceptors.i1.key = datacenter
- a1.sources.r1.interceptors.i1.value = NEW_YORK
- 详细配置参考
- 自定义拦截器
- 概述
- 内置拦截器只能实现对event header头信息的修改, 无法对event body中数据内容的修改
- 日志的数据信息是存储在event body中, 通过自定义拦截器, 可以对其中的内容进行过滤、加密等操作, 减少数据的传输量, 降低存储开销等
- 自定义拦截器步骤
- 自定义拦截器类CustomParameterInterceptor, 实现Interceptor接口
- 在 CustomParameterInterceptor 类中定义变量,用于存放 Flume的配置信息
- 每一行字段间的分隔符 (fields_separator)
- 通过分隔符分隔后,所需要列字段的下标(indexs)
- 多个下标使用的分隔符(indexs_separator)
- 多个下标使用的分隔符(indexs_separator)
- 添加 CustomParameterInterceptor 的有参构造方法, 对Flume配置信息变量初始化
- 编写具体拦截的方法intercept(), 通常需要编写两个方法, 一个用于单个拦截, 一个用于批量拦截
- 实现的接口中有一个内部接口Builder,
Flume都是通过该接口进行调用, 因此需要实现一个内部类, 用于接收Flume的配置信息
在内部类的build()方法中, 通过外部类的有参构造, 将Flume的配置信息传递给外部类 - 其他相关业务代码编写
- 将程序打成jar包, 放到Flume的lib目录下
- 编写采集方案, 运行即可
- 自定义拦截器伪代码
public class CustomParameterInterceptor implements Interceptor{
外部变量1;
外部变量2;
//3、执行外部类的构造器
public CustomParameterInterceptor(变量1,变量2) {
外部变量1=变量1;
外部变量2=变量2;
}
//4、针对拦截到event 结合用户配置参数 进行业务处理
public Event intercept(Event event) {
//拦截器获取到event进行业务逻辑处理的地方
数据 = event.getbody();
process(数据 外部变量 )
event.setboby(修改之后的数据)
return event;
}
public static class Builder implements Interceptor.Builder {
内部变量1;
内部变量2;
//1.通过上下文对象解析采集方案中的属性值 如果用户没有配置 使用默认值
public void configure(Context context) {
内部变量1 = context.getString(配置文件值1,默认值)
内部变量2 = context.getString(配置文件值2,默认值)
}
//2.通过内部类build方法 new外部类实例 通过构造方法 把解析属性赋值给外部类属性
public Interceptor build() {
return new CustomParameterInterceptor(内部变量1,内部变量2);
}
}
}
//在执行flume进行调用的过程中 基于内部类开始执行的
cn.miracle.interceptor.CustomParameterInterceptor$Builder