未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用范围与待维护事项
本文仅用于本机学习 netcat → memory → logger 数据流,前提是 Flume、兼容的 Java 环境及 nc 已安装,FLUME_HOME 已配置且 44444 端口可用。日志示例用于识别组件启动和事件输出,线程名、源码行号及格式可能随版本变化,不代表本轮实测结果。Source 返回 OK 仅说明事件已写入 Channel,不代表 Sink 已输出;Memory Channel 不持久化,Ctrl+C 也不保证排空。请勿将此配置用于需要可靠保存的生产数据。
warning 关联材料边界
以下原引用目标缺失或无法唯一确认,已取消跳转并保留提及:01-Flume概述与核心概念;06-Channel通道详解。相关素材/延伸说明暂不可用,不能据此声称已经提供配套材料。
第一个 Flume 应用
info 前置知识
- Flume 环境搭建:FLUME_HOME 已配置,
flume-ng version能正常输出 - Flume 概述与核心概念(原引用“01-Flume概述与核心概念”未能确定有效目标,暂不可跳转):理解 Source、Channel、Sink 三者的关系
本文用最经典的 netcat → memory → logger 示例,带你走完一次完整的 Flume 数据流:从写配置文件,到启动 Agent,到用 nc 命令发数据,到在日志里看到数据输出。整个过程大约 15 分钟,不需要 HDFS、Kafka 等任何额外依赖。
示例架构
%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
flowchart LR
classDef default fill:#FDFBF5,stroke:#6E6A60,color:#2D2A26,stroke-width:1.5px
classDef startend fill:#2D2A26,stroke:#2D2A26,color:#FDFBF5,font-weight:bold
classDef decision fill:#F6EAD8,stroke:#C08A1A,color:#2D2A26,font-weight:bold
classDef hub fill:#3B5A80,stroke:#3B5A80,color:#FDFBF5,font-weight:bold
classDef io fill:#E5EAF0,stroke:#3B5A80,color:#2D2A26
classDef accent fill:#A6432C,stroke:#A6432C,color:#FDFBF5,font-weight:bold
classDef storage fill:#F3EEDF,stroke:#9A9488,color:#2D2A26
A[nc 命令\n发送文本] -->|TCP:44444| B[Netcat Source\n监听端口]
B --> C[Memory Channel\n内存缓冲]
C --> D[Logger Sink\n输出到控制台日志]
class A,B,C,D default
三个组件的分工:
- Netcat Source:监听 TCP 端口,每收到一行文本就生成一个 Event
- Memory Channel:把 Event 暂存在 JVM 堆内存中,起到解耦和缓冲的作用
- Logger Sink:从 Channel 取出 Event,打印到控制台(通过 log4j)
第一步:编写配置文件
Flume 配置文件是标准的 Java Properties 格式,命名惯例是 <用途>.conf。
# 创建配置目录
mkdir -p ~/flume-demo
# 编写配置文件
cat > ~/flume-demo/netcat-logger.conf << 'EOF'
# ============================================================
# Agent 组件声明
# 语法:<agentName>.<组件类型> = <组件名1> <组件名2> ...
# ============================================================
agent.sources = r1
agent.channels = c1
agent.sinks = k1
# ============================================================
# Source 配置:Netcat Source
# ============================================================
agent.sources.r1.type = netcat
agent.sources.r1.bind = localhost
agent.sources.r1.port = 44444
# 声明该 Source 将数据写入哪个 Channel
agent.sources.r1.channels = c1
# ============================================================
# Channel 配置:Memory Channel
# ============================================================
agent.channels.c1.type = memory
# capacity:Channel 最多能存多少条 Event
agent.channels.c1.capacity = 1000
# transactionCapacity:每次事务最多处理多少条 Event
agent.channels.c1.transactionCapacity = 100
# ============================================================
# Sink 配置:Logger Sink
# ============================================================
agent.sinks.k1.type = logger
# 声明该 Sink 从哪个 Channel 取数据
agent.sinks.k1.channel = c1
EOF
echo "配置文件创建完毕"
note 配置文件的命名规则
配置文件中 agent 是 Agent 的名字,可以任意取(如 myagent、collector),但启动命令里的 --name 参数必须和配置文件里的名字保持一致。同一个配置文件里可以定义多个 Agent,用不同的名字区分,启动时通过 --name 指定运行哪个。
第二步:启动 Agent
flume-ng agent \
--conf $FLUME_HOME/conf \
--conf-file ~/flume-demo/netcat-logger.conf \
--name agent \
-Dflume.root.logger=INFO,console
参数说明:
| 参数 | 含义 |
|---|---|
--conf |
指定 Flume 系统配置目录(放置 flume-env.sh 和 log4j 配置) |
--conf-file |
指定业务配置文件路径(即我们刚写的 .conf 文件) |
--name |
指定要运行的 Agent 名称,必须与配置文件中的前缀一致 |
-Dflume.root.logger |
覆盖日志级别和输出目标,INFO,console 表示打印到控制台 |
启动成功后,终端会持续输出日志,关键行如下:
INFO [conf-file-poller-0] (org.apache.flume.node.Application.startAllComponents:182) - Starting Sink k1
INFO [conf-file-poller-0] (org.apache.flume.node.Application.startAllComponents:196) - Starting Source r1
INFO [lifecycleSupervisor-1-0] (org.apache.flume.source.NetcatSource.start:155) - Source starting
INFO [lifecycleSupervisor-1-0] (org.apache.flume.source.NetcatSource.start:169) - Created serverSocket:sun.nio.ch.ServerSocketChannelImpl[/127.0.0.1:44444]
看到 Created serverSocket 这行,说明 Netcat Source 已经在 44444 端口监听了。
第三步:发送测试数据
另开一个终端窗口,用 nc(netcat)命令连接到 Flume 的监听端口,然后输入文本:
# 连接到 Flume Netcat Source
nc localhost 44444
连接成功后,终端会进入交互模式。输入任意文本并按回车,例如:
Hello Flume
This is a test message
2024-01-15 user_id=1001 action=login
每按一次回车,Flume 会回复 OK,表示这条 Event 已被 Source 接收并放入 Channel。
第四步:验证数据输出
切换回运行 Flume 的终端,可以看到 Logger Sink 的输出:
INFO [SinkRunner-PollingRunner-DefaultSinkProcessor] (org.apache.flume.sink.LoggerSink.process:95) - Event: { headers:{} body: 48 65 6C 6C 6F 20 46 6C 75 6D 65 Hello Flume }
INFO [SinkRunner-PollingRunner-DefaultSinkProcessor] (org.apache.flume.sink.LoggerSink.process:95) - Event: { headers:{} body: 54 68 69 73 20 69 73 20 61 20 74 65 73 74 20 6D This is a test m }
输出格式解读:
headers:{}:Event 的 Header 是空 Map(Netcat Source 默认不添加 Header)body: 48 65 6C ...:Event Body 的十六进制表示,后面跟着可读文本预览- Logger Sink 默认只显示 Body 的前 16 字节,完整内容需要调整
maxBytesToLog参数
tip 查看完整 Event Body
Logger Sink 有一个参数 maxBytesToLog,默认 16 字节。如果你的消息超过 16 字节且想完整显示,在配置文件里加上:
agent.sinks.k1.maxBytesToLog = 512
配置文件结构总结
通过这个例子,Flume 配置文件的结构规律很清晰:
# 第一部分:声明(声明有哪些组件)
<agentName>.sources = <sourceName1> [sourceName2 ...]
<agentName>.channels = <channelName1> [channelName2 ...]
<agentName>.sinks = <sinkName1> [sinkName2 ...]
# 第二部分:配置(为每个组件设置参数)
<agentName>.sources.<sourceName>.type = <类型>
<agentName>.sources.<sourceName>.<参数> = <值>
...
# 第三部分:绑定(声明组件之间的连接关系)
<agentName>.sources.<sourceName>.channels = <channelName>
<agentName>.sinks.<sinkName>.channel = <channelName>
Source 写 channels(复数,可写入多个 Channel),Sink 写 channel(单数,只从一个 Channel 读取)。
停止 Agent
在 Flume 运行的终端按 Ctrl+C,Agent 会触发组件关闭,但不保证等待 Channel 中的数据被 Sink 全部处理完。Memory Channel 不持久化,停止后尚未处理的 Event 可能丢失;本练习应先观察测试消息的 Logger Sink 输出,再停止 Agent。
掌握检查
- [ ] 能解释配置文件中
agent.sources.r1.channels = c1这行的含义 - [ ] 知道
--name参数和配置文件前缀名不一致会发生什么(Agent 找不到配置,启动失败) - [ ] 能解读 Logger Sink 输出中
headers和body字段的含义 - [ ] 知道如何让 Logger Sink 显示超过 16 字节的 Event 内容
实践练习
基础题:将 Agent 名称从 agent 改为 demo,修改配置文件和启动命令,确认仍能正常运行。
进阶题:在配置文件中为 Source 加上 timestamp 拦截器(agent.sources.r1.interceptors = ts,agent.sources.r1.interceptors.ts.type = timestamp),重启后观察 Logger Sink 输出的 headers 字段有何变化。
下一步
- Source 数据源详解:从 Netcat Source 进阶到 Taildir Source,学会采集真实日志文件
- Channel 通道详解(原引用“06-Channel通道详解”未能确定有效目标,暂不可跳转):了解 File Channel 和 Memory Channel 的可靠性差异
- Sink 输出详解:把数据写到 HDFS 或 Kafka,而不只是打印到日志