flume监控日志写到 Kafka,我为什么不用 log4j2 直连
日志采集有一个常见的争议:应用到底该直接把日志打到 Kafka,还是先写本地文件再让 Flume 采?
我之前也纠结过这个问题。后来线上出过一次事故——Kafka 集群抖动,log4j2 的 Kafka appender 直接把应用线程堵死了,服务全挂。从那以后我就认了:应用只管写文件,采集的事交给 Flume。
这篇我就讲一下 Flume 监控文件写到 Kafka 的配置方法,以及几个我用下来觉得关键的参数。
为什么中间要加一层 Flume?
直接让应用通过 log4j2 写 Kafka,确实省事,配置几行就搞定。但带来的问题是:
- Kafka 出问题会影响应用。Broker 不可用、网络抖动、topic 被删,应用的生产者线程会阻塞,业务接口跟着超时。
- 应用要关心 Kafka 的配置。bootstrap.servers、序列化方式、acks 这些参数都塞到应用的配置文件里,跟业务配置混在一起。
- 没法做数据清洗。log4j2 的 appender 只负责发,你想在写入前做格式转换、过滤敏感信息,基本没法搞。
加了 Flume 这一层之后:
- 应用只写本地文件,write 完就结束,Kafka 死活跟它没关系
- Flume 负责采、负责发、负责重试,采集挂了也不影响业务
- 想清洗数据?加个拦截器就行,随时改随时生效
实战配置:从文件监控到 Kafka 写入
先用一个最简单的方案把流程跑通:Exec Source 监控一个文件,Memory Channel 暂存,Kafka Sink 发到 Kafka。
1 | # 1. 定义组件名称(Agent、Source、Channel、Sink) |
关键参数解析
配置文件中以下参数直接影响可靠性和性能,需重点关注:
| 组件 | 参数 | 作用与建议值 |
|---|---|---|
| Source | restart = true |
命令失败后自动重启,确保监控不中断 |
| Channel | capacity = 10000 |
Memory Channel 的 capacity 设太小,高峰流量直接撑爆;设太大,占内存。我一般先估算每秒多少条日志,乘以 3-5 秒的缓冲量,比如每秒 200 条,capacity 设 1000 就够了。 |
| Sink | kafka.producer.acks = 1 |
可靠性配置:0(最快)、1(平衡)、-1(最可靠) |
| Sink | batch.size + linger.ms |
batch.size:攒到多少字节再发,默认 16KB linger.ms:攒不够 batch.size 的话,等多久强制发,默认 0 表示立刻发这两个是”二选一触发”的关系。我一般把 batch.size 调大到 64KB,linger.ms设 500ms,吞吐能上来不少,延迟也就多个几百毫秒,日志采集完全能接受。 |
启动 Flume Agent命令
执行以下命令启动 Flume,开始监控文件并写入 Kafka:
1 | flume-ng agent \ |
验证数据写入 Kafka
通过 Kafka 命令行工具验证数据是否成功写入:
方法 1:消费 Kafka 主题
1 | 启动 Kafka 消费者,监听 flume-kafka 主题 |
若配置正确,消费者会实时输出日志文件中的新增内容。
方法 2:查看 Kafka 日志文件
Kafka 消息物理存储在日志文件中,可通过以下命令查看:
1 | 查看主题分区日志(需替换实际日志路径) |
输出中 payload 字段即为 Flume 写入的日志内容,例如:
1 | payload: "2024-07-22 10:00:00 [INFO] User login success: user_id=123" |
生产环境别用这套配置,得换几个组件
1. 替换 Source 为 Taildir Source
Flume 挂了再起来,tail -F 会从文件开头重新读,数据重复,生产环境建议使用 Taildir Source 监控文件,支持断点续传:
1 | # 替换 Source 配置为 Taildir Source |
这个 Source 会把每个文件的读取进度记到 positionFile 里,重启之后接着读,不重不漏。
2. 使用 File Channel 增强可靠性
Memory Channel 在 Flume 崩溃时会丢失数据,对可靠性要求高的场景建议使用 File Channel:
1 | # 替换 Channel 配置为 File Channel |
3. Kafka 生产者参数调优
根据业务需求调整 Kafka 生产者参数,平衡性能与可靠性:
1 | # 提高吞吐量:增大批量发送大小和缓冲区 |
另外:Flume 启动的时候不会帮你创建 topic(会报错 Topic flume-kafka does not exist),得提前建好
1 | kafka-topics.sh --bootstrap-server localhost:9092 --create --topic flume-kafka --partitions 3 --replication-factor 1 |
4. 日志清洗与转换
Flume 的拦截器可以在 Source 往 Channel 发之前,对 Event 做加工。加时间戳是最常见的用法:
1 | # 配置拦截器:添加时间戳头信息 |
这样每个 Event 的 Header 里会多一个 timestamp 字段,下游消费的时候可以用来做时间窗口聚合。
如果你想过滤掉 DEBUG 级别的日志,或者脱敏手机号,也可以写自定义拦截器,实现 Interceptor 接口就行。
5. 保证日志文件权限
错误提示:Permission denied: /var/log/app/app.log
解决:确保 Flume 进程对监控文件有读权限,或修改文件权限:
1 | chmod 644 /var/log/app/app.log |