Flume
flume前置
-
flume是一个日志收集系统,可以从各种地方收集数据来存放到指定的地方
-
flume有sources、channels、sinks,分别是数据源,管道,存放数据的位置,配置好这三个就能开始收集数据了
-
flume的启动命令
bin/flume agent -n a1 -f 自己写的配置文件 -Dflume.root.logger=INFO,console
-
一般来说flume会和kakfa一起配合使用,flume用来采集数据,kafka用于保存数据
-
事件是flume采集数据的最小单位,一条数据就是一个事件
-
总结:flume解压之后写一个配置文件,需要包含sources/channels/sinks,然后启动就可以
# example.conf: A single-node Flume configuration # Name the components on this agent a1.sources = r1 a1.sinks = k1 a1.channels = c1 # Describe/configure the source a1.sources.r1.type = netcat a1.sources.r1.bind = localhost a1.sources.r1.port = 44444 # 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
Flume常用的source/Sink
- 配置从哪个地方读取数据,可以有很多地方,比如一个端口,一个文件等。。。
Avro(Source/Sink)
-
用于实现多个flume连接,实现多级流动
Source,接收上一级的数据
a1.sources = r1 a1.channels = c1 a1.sources.r1.type = avro a1.sources.r1.channels = c1 a1.sources.r1.bind = 0.0.0.0 a1.sources.r1.port = 4141
SInk,用于把数据输出到下一级
a1.channels = c1 a1.sinks = k1 a1.sinks.k1.type = avro a1.sinks.k1.channel = c1 a1.sinks.k1.hostname = 10.10.10.10 a1.sinks.k1.port = 4545
Exec(Source)
-
用于采集日志文件中的数据,通常指定一个
tail -F 文件路劲
命令来采集数据a1.sources = r1 a1.channels = c1 a1.sources.r1.type = exec a1.sources.r1.command = tail -F /var/log/secure a1.sources.r1.channels = c1
Kafka(source/Sink)
-
采集kafka中主题的数据,kafkaSource实际上就是一个kafka的消费者,从topic中读取信息
-
Source有两种消费主题的配置方式
第一种使用逗号隔开消费的多个主题
a1.sources.r1.type = org.apache.flume.source.kafka.KafkaSource a1.sources.r1.kafka.bootstrap.servers = localhost:9092 a1.sources.r1.kafka.topics = test1, test2 a1.sources.r1.batchSize = 5000 a1.sources.r1.batchDurationMillis = 2000 a1.sources.r1.kafka.consumer.group.id = test-consumer-group a1.sources.r1.channels = c1
第二种是使用正则的方式来匹配多个主题
a1.sources.r1.type = org.apache.flume.source.kafka.KafkaSource a1.sources.r1.kafka.bootstrap.servers = localhost:9092 a1.sources.r1.kafka.topics.regex = ^topic[0-9]$ a1.sources.r1.channels = c1
-
Sink可以指定保存数据的topic和分区
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink a1.sinks.k1.kafka.topic = topic a1.sinks.k1.kafka.bootstrap.servers = localhost:9092 a1.sinks.k1.defaultPartitionId = 4 a1.sinks.k1.chennel = c1
NetcatTCP(Source)
-
监听一个TCP端口来接收数据,转成event写入channel
a1.sources = r1 a1.channels = c1 a1.sources.r1.type = netcat a1.sources.r1.bind = 0.0.0.0 a1.sources.r1.port = 6666 a1.sources.r1.channels = c1
Spooling Directory(Source)
-
用于监视一个文件夹,如果有新增文件则转成event写入channel,需要注意这些文件是不可变的,就是说不能对这些文件进行增删改操作,而且不能重名,如果改了会被重新采集
a1.channels = c1 a1.sources = r1 # 使用这种方式监视的文件夹中不能有子文件夹 a1.sources.r1.type = spooldir a1.sources.r1.channels = c1 # 监控的文件夹的路径 a1.sources.r1.spoolDir = /var/log/apache/flumeSpool a1.sources.r1.fileHeader = true # 采集完成的文件自动加上后缀 a1.sources.r1.fileSuffix = .ok
Taildir(Source)
-
监听多个文本文档,如果这个文件夹中有文件写入了新数据,那么写入的数据会被读取到
a1.sources = r1 a1.channels = c1 a1.sources.r1.type = TAILDIR a1.sources.r1.channels = c1 a1.sources.r1.positionFile = /var/log/flume/taildir_position.json a1.sources.r1.filegroups = f1 f2 a1.sources.r1.filegroups.f1 = /var/log/test1/example.log a1.sources.r1.headers.f1.headerKey1 = value1 a1.sources.r1.filegroups.f2 = /var/log/test2/.*log.* a1.sources.r1.headers.f2.headerKey1 = value2 a1.sources.r1.headers.f2.headerKey2 = value2-2 a1.sources.r1.fileHeader = true a1.sources.ri.maxBatchCount = 1000
HDFS(Sink)
-
用于把获取的数据存入到hdfs中
a1.channels = c1 a1.sinks = k1 a1.sinks.k1.type = hdfs a1.sinks.k1.channel = c1 # %y-%m-%d可以获取当前的时间来命名文件夹存放到hdfs中 a1.sinks.k1.hdfs.path = /flume/events/%y-%m-%d/%H%M/%S # 创建文件的前缀与后缀 a1.sinks.k1.hdfs.filePrefix = FlumeData a1.sinks.k1.hdfs.fileSuffix = xxx # 正在写入文件的前缀与后缀 a1.sinks.k1.hdfs.inUsePrefix = xxx a1.sinks.k1.hdfs.inUseSuffix = .tmp # 以固定时间触发滚动,单位秒(0表示不触发) a1.sinks.k1.hdfs.rollInterval = 30 # 以文件大小触发滚动,单位字节(0表示不触发) a1.sinks.k1.hdfs.rollSize = 1024 # 以事件多少触发滚动,单位事件(0表示不触发) a1.sinks.k1.hdfs.rollCount = 10 # 当事件达到该数量式写入内容(试了多次好像并没有什么用,只会刷新一次) a1.sinks.k1.hdfs.batchSize = 100
Hive(Sink)
-
可以把数据存入到Hive中
a1.channels = c1 a1.channels.c1.type = memory a1.sinks = k1 a1.sinks.k1.type = hive a1.sinks.k1.channel = c1 a1.sinks.k1.hive.metastore = thrift://127.0.0.1:9083 a1.sinks.k1.hive.database = logsdb a1.sinks.k1.hive.table = weblogs a1.sinks.k1.hive.partition = asia,%{country},%y-%m-%d-%H-%M a1.sinks.k1.useLocalTimeStamp = false a1.sinks.k1.round = true a1.sinks.k1.roundValue = 10 a1.sinks.k1.roundUnit = minute a1.sinks.k1.serializer = DELIMITED a1.sinks.k1.serializer.delimiter = "\t" a1.sinks.k1.serializer.serdeSeparator = "\t" a1.sinks.k1.serializer.fieldnames =id,,msg
Logger(Sink)
-
用于把收集的数据输出到控制台
a1.channels = c1 a1.sinks = k1 a1.sinks.k1.type = logger a1.sinks.k1.channel = c1
HBase(Sink)
-
用于把收集的数据存入到HBase中
a1.channels = c1 a1.sinks = k1 a1.sinks.k1.type = hbase a1.sinks.k1.table = foo_table a1.sinks.k1.columnFamily = bar_cf a1.sinks.k1.serializer = org.apache.flume.sink.hbase.RegexHbaseEventSerializer a1.sinks.k1.channel = c1
Flume的Channel
- channel用于临时存放数据,相当于一个缓冲区
File Channel
-
使用文件作为暂存区
a1.channels = c1 a1.channels.c1.type = file a1.channels.c1.checkpointDir = /mnt/flume/checkpoint a1.channels.c1.dataDirs = /mnt/flume/data
Memory Channel
-
将数据队列存储在内存中,可以配置分配的内存大小
a1.channels = c1 a1.channels.c1.type = memory a1.channels.c1.capacity = 10000 a1.channels.c1.transactionCapacity = 10000 a1.channels.c1.byteCapacityBufferPercentage = 20 a1.channels.c1.byteCapacity = 800000
使用flume采集文件到hdfs
-
如果使用默认的配置会使hdfs中过多小文件,需要进行配置其他参数让其文件大一些
# 类型与路径不能落下,这个路径只会让文件存储在这个文件夹下 a1.sinks.k1.type = hdfs a1.sinks.k1.hdfs.path = /test/xxx # 关闭以时间来触发关闭文件(时间) a1.sinks.k1.hdfs.rollInterval = 0 # 关闭以事件数量来触发关闭文件(Event) a1.sinks.k1.hdfs.rollCount = 0 # 开启以采集一定大小的数据量来触发关闭文件(字节) a1.sinks.k1.hdfs.rollSize = 1024 # 如果使用了以日期时间来命名文件,则需要开启使用本地的时间语义 a1.sinks.k1.hdfs.filePrefix = %Y-%m-%d a1.sinks.k1.hdfs.useLocalTimeStamp = true # 开启收集多少个事件再往文件中写入 a1.sinks.k1.hdfs.batchSize = 100
拦截器配置
-
首先使用
java
代码编写拦截器public class interceptor1 implements Interceptor { // 存储事件列表用 private static List<Event> events; // flume拦截器启动时会运行一次 public void initialize() { events = new ArrayList<>(); System.out.println("开启拦截器"); } // 编写逻辑为事件加上头信息 public Event intercept(Event event) { Map<String, String> headers = event.getHeaders(); String body = new String(event.getBody()); if (body.split(",")[0].equals("0")) { headers.put("id", "zero"); } else { headers.put("id", "rest"); } System.out.println(headers + "---" + body); return event; } // 将采集的世界列表使用intercept方法加上头信息 public List<Event> intercept(List<Event> list) { for (Event e : list) { events.add(intercept(e)); } return events; } // flume拦截器关闭时会触发一次 public void close() { System.out.println("关闭拦截器"); } // 内部类 public static class Builder implements Interceptor.Builder { // 返回一个拦截器 public Interceptor build() { return new interceptor1(); } // 配置文件 public void configure(Context context) { } } }
-
编写之后打包到
flume/lib
目录中,然后编写配置文件# sources、channels、sinks编写 a1.sources = r1 a1.channels = c1 c2 a1.sinks = k1 k2 # sources配置 a1.sources.r1.type = exec a1.sources.r1.command = tail -F <fileName> # 拦截器配置 a1.sources.r1.interceptors = i1 a1.sources.r1.interceptors.i1.type = <java编写flume拦截器的包名> # 配置多路选择器(在自定义的拦截器jar包中选择头信息) a1 sources.r1.selector.type = multiplexing a1.sources.r1.selector.header = <代码中给头设置的键是什么就填什么> a1.sources.r1.selector.mapping.<代码中id对应的值是什么就填什么> = <要输出到哪个channel> a1.sources.r1.selector.mapping.zero = c2 # channels配置(需要给多一些线程和事件最大容量) a1.channels.c1.type = memory a1.channels.c1.capacity = 1000 a1.channels.c1.transactionCapacity = 1000 a1.channels.c2.type = memory a1.channels.c2.capacity = 1000 a1.channels.c2.transactionCapacity = 1000 # sinks配置 a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink a1.sinks.k1.kafka.topic = order1 a1.sinks.k1.kafka.bootstrap.servers = master:9092 a1.sinks.k1.kafka.defaultPartitionId = 3 a1.sinks.k2.type = hdfs a1.sinks.k2.hdfs.path = /user/test/flumebackup a1.sinks.k2.hdfs.rollInterval = 30 a1.sinks.k2.hdfs.rollCount = 0 a1.sinks.k2.hdfs.rollSize = 0 # 组装 a1.sources.r1.channels = c1 c2 a1.sinks.k1.channel = c1 a1.sinks.k2.channel = c2
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术