kafka日志分段(segment)是存储与清理的底层支柱,每个partition由多个segment组成,含.log、.index、.timeindex三类文件;分段实现高效查找与整段删除,滚动由大小(默认1gb)或时间(默认7天)触发,清理仅针对已封存segment按保留时间批量执行。

Kafka 的日志分段(Segment)不是可选项,而是其存储和清理机制的底层支柱。它直接决定了消息怎么存、怎么查、什么时候删——不理解 Segment,就很难真正掌控 Kafka 的磁盘行为和数据生命周期。
Segment 是什么?为什么必须分段?
每个 Partition 在磁盘上对应一个文件夹,里面实际由多个 Segment 文件组成。每个 Segment 包含三个核心文件:
- .log:真实存放消息二进制数据
- .index:稀疏索引,记录 offset 到 .log 中物理位置的映射
- .timeindex:按时间戳快速定位 offset 的辅助索引
不分段的话,一个 Partition 就是单个巨型文件。查找某条消息要线性扫描,删除旧数据得截断或重写文件——IO 开销大、操作慢、还容易阻塞写入。分段后,Kafka 把“查找”和“清理”都降维到文件粒度:先找 Segment,再用索引精确定位;过期 Segment 直接整个删除,不碰其他文件。
Segment 怎么滚动?谁决定新段诞生?
新 Segment 不是定时生成的,而是由两个条件触发其创建(满足任一即滚动):
- 当前活跃段(Active Segment)大小达到 log.segment.bytes(默认 1GB)
- 当前活跃段存在时间超过 log.roll.ms(默认 7 天)
滚动后,原 Active Segment 变为已封存(Sealed)状态,不再接受写入;新 Segment 成为新的 Active Segment。注意:只有 Sealed Segment 才可能被清理线程处理,Active Segment 永远不会被删,哪怕里面部分消息早已过期。
清理怎么发生?Segment 级别才是关键
Kafka 默认启用基于时间的日志保留策略(log.retention.hours,常见值 168 小时/7 天)。但清理动作不是逐条删消息,而是按 Segment 批量判定:
- 检查每个 Sealed Segment 的最后一条消息时间戳
- 若该时间早于当前时间减去 retention 阈值,整个 Segment 被标记为可删除
- LogCleaner 线程随后直接 unlink 对应的 .log、.index、.timeindex 等全套文件
这意味着:即使你设了 1 天保留,但如果某个 Segment 还在写入中(Active),或者刚封存但最后一条消息才写入 23 小时,它仍会完整保留,直到满足条件才整段清除。这也是为什么有时“数据没被删”——不是策略失效,而是 Segment 还没到清理窗口。
如何观察和验证 Segment 行为?
进入 Kafka 数据目录(如 kafka-data-dir/topics/topic-name/partition-0/),你会看到类似命名的文件:
-
00000000000000000000.log:起始 offset 为 0 的段 -
00000000000000000105.log:起始 offset 为 105 的段
文件名中的数字就是该 Segment 的 base offset。配合 kafka-log-dirs.sh 工具,可以查看各 Partition 当前 Segment 数量、大小、最早/最晚时间戳,进而判断是否符合预期的滚动与清理节奏。










