一、高可靠传输:Kafka 在日志管道中的核心作用
日志采集上来之后,最怕什么?
怕丢。怕堵。怕下游一挂,整个管道都崩了。
我在早期做日志平台的时候,用过直接写磁盘、用过 Redis 队列、也试过 RabbitMQ。说实话,小规模都能跑,但一旦日均日志量上了百亿条,问题就全冒出来了。后来全面切到 Kafka,才算真正把「高可靠传输」这件事落地了。
1.1 为什么是 Kafka?
你想想看,日志管道对消息队列的要求其实很明确:
- 吞吐量要大——日志是海量的,每秒几十万条是常态
- 持久化要稳——不能因为进程重启就丢数据
- 顺序要保证——至少同一个分片内的日志顺序不能乱
- 回溯要灵活——出问题时能重新消费某段时间的数据
Kafka 恰好把这几点都做到了。它的核心设计就是「追加写 + 顺序读」,说白了就是日志本身的数据结构。嗯,用日志系统来传输日志,这件事本身就挺有意思的。
核心结论:Kafka 在日志管道中扮演的是「可靠缓冲层」的角色。它不负责计算,只负责把数据安全地从 Producer 搬到 Consumer。
1.2 分区机制:并行与顺序的平衡艺术
分区是 Kafka 实现高吞吐的关键。每个 Topic 可以拆成多个 Partition,每个 Partition 内部保证顺序,Partition 之间可以并行消费。
我在项目中遇到过一个问题:某个业务线的日志量突然暴涨,导致单个 Consumer 消费不过来。后来我们把 Topic 的分区数从 3 调整到 12,消费能力直接翻了 4 倍。当然,分区也不是越多越好——你想想看,分区太多会导致文件句柄膨胀、Leader 选举变慢。
分区数量的建议:
| 场景 | 分区数建议 | 说明 |
|---|---|---|
| 日均日志量 < 1 亿条 | 3 ~ 6 | 单机部署足够 |
| 日均日志量 1 ~ 10 亿条 | 6 ~ 12 | 建议 3 台 Broker 起步 |
| 日均日志量 > 10 亿条 | 12 ~ 24 | 注意监控 ISR 状态 |
个人习惯:我一般按「目标吞吐量 / 单分区吞吐量」来估算分区数。单分区在 SSD 上大概能扛 10MB/s 的写入,你可以拿这个做基准。
1.3 副本机制:数据不丢的底气
副本是 Kafka 高可用的基石。每个 Partition 可以有多个 Replica,其中一个是 Leader,其余是 Follower。读写都走 Leader,Follower 只负责同步。
这里有个关键参数:acks。
- acks=0:发出去就不管了,性能最高,但可能丢数据
- acks=1:Leader 写成功就返回,性能与可靠性的折中
- acks=all:所有 ISR 副本都写成功才返回,最安全
我曾经踩过一个坑:线上日志 Topic 的 acks 设成了 1,结果某台 Broker 宕机时,刚好有几秒的数据还没来得及同步到 Follower。重启后那几秒的日志就丢了。后来我统一改成 acks=all,配合 min.insync.replicas=2,再没出过类似问题。
避坑指南:我曾经以为副本数越多越安全,于是设了 5 个副本。结果发现写入延迟飙升,因为每次都要等 5 个副本都确认。后来改成 3 副本 + min.insync.replicas=2,既保证了可靠性,性能也扛得住。
1.4 ISR 机制:动态的副本管理
ISR(In-Sync Replicas)是 Kafka 用来管理副本同步状态的机制。只有跟 Leader 保持同步的副本才会被列入 ISR 列表。如果某个 Follower 落后太多,就会被踢出 ISR。
为什么会落后?说白了就是网络延迟、磁盘 I/O 瓶颈、或者 GC 停顿。我见过一个案例:某台 Broker 的磁盘是机械盘,写入速度跟不上,结果它的副本一直被踢出 ISR,导致整个集群的可用副本数不足,写入直接报错。
ISR 相关的核心参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
| replica.lag.time.max.ms | 30000 | Follower 超过 30 秒没同步,踢出 ISR |
| min.insync.replicas | 1 | 最少同步副本数,建议设为 2 |
| unclean.leader.election.enable | false | 是否允许非 ISR 副本成为 Leader,建议 false |
一句话总结:ISR 就是 Kafka 的「健康检查机制」。它保证了只有数据完整的副本才有资格提供服务。
1.5 日志管道中的 Kafka 架构图
下面这张图展示了日志从采集到消费的完整链路,以及 Kafka 在其中扮演的角色:
1.6 生产环境配置建议
最后,我分享一下自己在生产环境中常用的 Kafka 配置。这些配置经过多次踩坑和调优,基本能覆盖大部分日志场景:
# 日志 Topic 配置
log.retention.hours=72 # 保留 3 天,够回溯用了
log.segment.bytes=1073741824 # 1GB 一个段文件
log.retention.check.interval.ms=300000 # 5 分钟检查一次
# 可靠性配置
acks=all
min.insync.replicas=2
unclean.leader.election.enable=false
# 性能配置
num.network.threads=8
num.io.threads=16
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
个人建议:别一上来就追求极致性能。先把可靠性做扎实了,再慢慢调优。日志丢了,性能再高也没用。
好了,这一章我们聊了 Kafka 在日志管道中的核心作用,重点讲了分区和副本机制。说白了,Kafka 就是靠「分区并行 + 副本冗余」这两招,撑起了海量日志的高可靠传输。下一章我们会深入聊聊日志采集端的架构设计,到时候再细说。
公众号:蓝海资料掘金营,微信deep3321