未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用范围与待维护事项
本文用于已跑通 Flume Agent 的读者比较 Source 并完成配置练习,示例只给出 Source 片段,须补齐 Agent、Channel 与 Sink 配置。原稿未注明或核实 Flume 与 Kafka 客户端版本,参数支持和恢复行为须按部署版本验证。Spooling Directory 要求投递文件内容不再变化且文件名不复用;练习中的 /tmp 路径仅供临时测试。生产采集需另行验证持久化 Channel、日志轮转、重试去重,以及 HTTP 监听的鉴权、请求大小限制和网络隔离,不能据本文认定零丢失或零重复。
warning 关联材料边界
以下原引用目标缺失或无法唯一确认,已取消跳转并保留提及:01-Flume概述与核心概念;06-Channel通道详解;08-Flume拦截器详解。相关素材/延伸说明暂不可用,不能据此声称已经提供配套材料。
Source 数据源详解
info 前置知识
- 第一个 Flume 应用:已经跑通 Netcat Source 的基础示例
- Flume 概述与核心概念(原引用“01-Flume概述与核心概念”未能确定有效目标,暂不可跳转):理解 Event 的 Header 和 Body 结构
Source 是 Flume 管道的入口,负责从外部系统接收数据并转换为 Event 写入 Channel。选择合适的 Source 类型是配置 Flume 的第一步决策。
不同 Source 的核心差异在于两点:数据从哪里来(文件、网络端口、消息队列),以及可靠性保障机制(是否支持断点续传、是否会丢数据)。
Source 类型总览
| Source 类型 | 数据来源 | 断点续传 | 适用场景 |
|---|---|---|---|
| Taildir Source | 文件系统(实时跟踪) | 支持 | 生产环境日志采集首选 |
| Spooling Directory | 文件系统(批量处理) | 文件级 | 定时批量文件导入 |
| Exec Source | Shell 命令输出 | 不支持 | 临时脚本输出,不推荐生产 |
| Netcat Source | TCP 端口 | 不支持 | 开发调试 |
| Kafka Source | Kafka Topic | 依赖 Consumer Offset | 消费 Kafka 数据再分发 |
| HTTP Source | HTTP POST | 不支持 | RESTful 接口数据接收 |
| Avro Source | Avro RPC | 不支持(依赖上游) | 多级 Agent 级联汇聚 |
Taildir Source(推荐)
Taildir Source 是生产环境日志采集的首选,它同时具备:
- 实时跟踪:监控一组文件(支持正则通配),文件有新内容就立刻采集
- 断点续传:把每个文件的读取位置(offset)保存到一个 JSON 格式的 position 文件,Agent 重启后可根据已保存的位置恢复读取;异常退出、位置保存时机、Channel 持久性和文件轮转方式都会影响恢复结果,不能保证零重复或零丢失
- 多文件支持:一个 Taildir Source 可以同时监控多组文件规则(filegroups)
核心配置
agent.sources.taildir_src.type = TAILDIR
agent.sources.taildir_src.channels = c1
# --------------------------------------------------------
# positionFile:断点续传的关键配置
# 记录每个被监控文件的 inode 号和当前读取 offset
# 重启后 Flume 根据此文件恢复读取位置
# --------------------------------------------------------
agent.sources.taildir_src.positionFile = /var/lib/flume/taildir_position.json
# --------------------------------------------------------
# filegroups:定义要监控的文件组,可以配置多组
# 每个 filegroup 对应一个正则路径表达式
# --------------------------------------------------------
agent.sources.taildir_src.filegroups = nginx_access app_error
# 第一组:Nginx 访问日志(正则匹配所有 access.log* 文件)
agent.sources.taildir_src.filegroups.nginx_access = /var/log/nginx/access\\.log.*
# 第二组:应用错误日志
agent.sources.taildir_src.filegroups.app_error = /var/log/app/error\\.log.*
# --------------------------------------------------------
# 为每组文件添加自定义 Header(可选)
# 方便下游 Sink 做路由判断
# --------------------------------------------------------
agent.sources.taildir_src.headers.nginx_access.logType = nginx-access
agent.sources.taildir_src.headers.app_error.logType = app-error
# 性能参数
agent.sources.taildir_src.batchSize = 1000
agent.sources.taildir_src.maxBatchCount = 1000
warning positionFile 的位置很重要
生产环境的 positionFile 应存放在持久化存储路径,避免放在 /tmp 下(可能在重启或定期清理时被删除);临时练习使用 /tmp 时,不应将其作为持久恢复保障。建议放在 /var/lib/flume/ 或 $FLUME_HOME/positions/ 这类不会被系统清理的目录。目录需要提前创建,且 Flume 进程用户有写权限。
断点续传的工作原理
position 文件是一个 JSON 数组,每个元素描述一个被监控文件的当前状态:
[
{
"inode": 12345678,
"pos": 204800,
"file": "/var/log/nginx/access.log"
},
{
"inode": 12345679,
"pos": 0,
"file": "/var/log/nginx/access.log.1"
}
]
Taildir Source 在读取位置记录中使用 inode 和文件路径等信息识别文件;对于保留 inode 的重命名轮转(access.log → access.log.1),若轮转后的文件仍能被发现且未被提前删除,可利用保存的位置继续读取。复制后截断、inode 复用或异常退出等情况仍需验证,不能据此保证不漏采、不重复。
Spooling Directory Source
Spooling Directory Source 适合批量文件导入场景:监控一个目录,每当有新文件出现就完整读取,读完后把文件改名为 .COMPLETED 标记已处理。
agent.sources.spooldir_src.type = spooldir
agent.sources.spooldir_src.channels = c1
# 监控的目录路径(Flume 只处理直接在此目录中的文件,不递归子目录)
agent.sources.spooldir_src.spoolDir = /data/flume/spool
# 文件处理完成后的处理方式:
# never(默认):重命名加 .COMPLETED 后缀
# immediate:立刻删除文件
agent.sources.spooldir_src.deletePolicy = never
agent.sources.spooldir_src.fileSuffix = .COMPLETED
# 只处理匹配此正则的文件,忽略其他文件
agent.sources.spooldir_src.includePattern = .*\\.log$
# 忽略以点开头的隐藏文件(避免处理临时文件)
agent.sources.spooldir_src.ignorePattern = ^\\..*$
# 每个 Event 包含来源文件名(方便追踪数据来源)
agent.sources.spooldir_src.basenameHeader = true
agent.sources.spooldir_src.basenameHeaderKey = filename
# 性能参数
agent.sources.spooldir_src.batchSize = 1000
与 Taildir Source 的关键区别:Spooling Directory 用于已完整写入且内容不再变化的文件,要求投递文件名不复用;它会记录处理进度,中途重启并非必然从头读取,但故障恢复仍可能重复投递部分 Event。Taildir Source 用于持续追加的日志文件,记录字节偏移以支持恢复;两者的端到端可靠性都还取决于 Channel、Sink 和故障条件。
Exec Source 及其局限性
Exec Source 执行一个 Shell 命令,把命令的标准输出转换为 Event。看起来很灵活,实际上有严重的可靠性问题,不推荐在生产环境使用。
agent.sources.exec_src.type = exec
agent.sources.exec_src.channels = c1
# 执行的命令(以 tail -F 为例)
agent.sources.exec_src.command = tail -F /var/log/app/app.log
# 每隔多少毫秒重启失败的命令
agent.sources.exec_src.restartThrottle = 10000
agent.sources.exec_src.restart = true
Exec Source 的致命弱点:
| 问题 | 说明 |
|---|---|
| 无断点续传 | Agent 重启后,tail -F 命令重新执行,不会从 Flume 上次读取位置恢复;默认重新输出文件末尾若干行可能造成重复,停机期间的数据也可能漏采 |
| 命令崩溃丢数据 | 子进程意外退出时,还在管道缓冲区中未交给 Source 的数据直接丢失 |
| 多文件管理受限 | 一个 Exec Source 执行一条命令,但命令本身可以读取多个文件;文件边界和来源标识需额外处理,也可配置多个 Exec Source |
| 依赖外部命令 | 依赖 tail、cat 等系统命令,可移植性差 |
warning 生产环境替代方案
如果你现在用的是 exec tail -F 采集追加式日志,可评估迁移到 Taildir Source,以获得读取位置记录和多文件组管理能力。Taildir 不能替代任意 Shell 命令输出,迁移时仍需验证文件轮转、Channel 持久性和故障恢复行为。
HTTP Source
HTTP Source 启动一个嵌入式 HTTP 服务器,接收 HTTP POST 请求,将请求 Body 转换为 Event。适合需要把数据 POST 到 Flume 的场景,例如移动端埋点数据上报、Webhook 数据接收。
agent.sources.http_src.type = http
agent.sources.http_src.channels = c1
# 监听端口
agent.sources.http_src.port = 8080
# 绑定地址(默认 0.0.0.0,监听所有网卡)
agent.sources.http_src.bind = 0.0.0.0
# Handler 类:决定如何解析 HTTP 请求
# 内置 JSONHandler:解析 JSON 格式的 Event 数组
# 内置 BlobHandler:把整个请求 Body 作为一个 Event 的 Body
agent.sources.http_src.handler = org.apache.flume.source.http.JSONHandler
# enableDecoding 不是请求 Body 大小限制参数
# 以下配置的支持情况与解码语义须按所用 Flume 版本确认
# 请求大小限制需另行配置并验证
agent.sources.http_src.enableDecoding = false
发送数据的方式(JSONHandler 格式):
# JSONHandler 期望的请求格式:JSON 数组,每个元素是一个 Event
curl -X POST \
-H "Content-Type: application/json" \
-d '[{"headers":{"source":"mobile","user_id":"1001"},"body":"user clicked button_A"}]' \
http://localhost:8080
note HTTP Source 的可靠性
HTTP Source 本身不能独立保证端到端 at-least-once;这还依赖客户端重试、Channel 持久性和下游处理。若写入 Channel 成功后客户端因网络抖动未收到成功响应而重试,可能产生重复;重复并不违反 at-least-once,但意味着并非 exactly-once。生产环境接收关键数据时,建议在业务层做幂等处理,或在 Event Header 加唯一 ID 供下游去重。
Kafka Source
Kafka Source 作为 Kafka 消费者,从指定 Topic 拉取消息并转换为 Flume Event。常见于已有 Kafka 的架构中,用 Flume 把 Kafka 数据再路由到 HDFS 或其他存储。
agent.sources.kafka_src.type = org.apache.flume.source.kafka.KafkaSource
agent.sources.kafka_src.channels = c1
# Kafka 集群地址
agent.sources.kafka_src.kafka.bootstrap.servers = kafka01:9092,kafka02:9092
# 订阅的 Topic
agent.sources.kafka_src.kafka.topics = app-logs,nginx-access
# 消费者组 ID(同一 group.id 的多个 Flume Agent 会负载均衡消费)
agent.sources.kafka_src.kafka.consumer.group.id = flume-consumer-group
# 批量大小
agent.sources.kafka_src.batchSize = 1000
# 批量超时(毫秒):等待凑够一批的最长时间
agent.sources.kafka_src.batchDurationMillis = 1000
选型决策指南
%%{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 TD
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{数据来自哪里?} --> B[文件]
A --> C[网络/API]
A --> D[消息队列]
B --> E{需要实时采集?}
E -->|是| F[Taildir Source]
E -->|否,批量文件| G[Spooling Directory Source]
C --> H{接口类型?}
H -->|HTTP POST| I[HTTP Source]
H -->|Avro RPC| J[Avro Source]
H -->|调试测试| K[Netcat Source]
D --> L{队列类型?}
L -->|Kafka| M[Kafka Source]
L -->|JMS| N[JMS Source]
class A,E,H,L decision
class B,C,D,F,G,I,J,K,M,N default
掌握检查
- [ ] 能解释 Taildir Source 的
positionFile中 inode、文件路径和读取位置的作用,以及文件轮转时恢复读取的条件 - [ ] 知道 Exec Source 在 Agent 重启后会出现什么问题,以及如何替代
- [ ] 能写出 Taildir Source 同时监控两组文件(nginx 日志和应用日志)的配置
- [ ] 理解 HTTP Source 接收 JSON 格式 Event 时的请求格式
实践练习
基础题:配置一个 Taildir Source 监控 /tmp/test-logs/ 目录下的所有 .log 文件,positionFile 存放在 /tmp/flume-pos/taildir.json,数据输出到 Logger Sink,启动后向目录写入文件验证采集效果。
进阶题:将上题中的 Taildir Source 改为两个 filegroups(access 监控 access*.log,error 监控 error*.log),并分别给两组文件打上不同的 Header(type=access 和 type=error),观察 Logger Sink 的输出。
下一步
- Channel 通道详解(原引用“06-Channel通道详解”未能确定有效目标,暂不可跳转):了解 Memory Channel 与 File Channel 的可靠性差异
- Sink 输出详解:配置 HDFS Sink 将采集到的日志写入数据仓库
- 拦截器详解(原引用“08-Flume拦截器详解”未能确定有效目标,暂不可跳转):在 Source 读完数据后、进入 Channel 前对 Event 做过滤和标注