Kafka 有两种清理日志的策略:
- Log Retention,根据时间、大小、起始偏移量删除日志
- Log Compaction,对具有相同 key 的消息,只保留最后一个 value
Kafka 采用哪种清理策略由 server.properties 配置文件中的 log.cleanup.policy 参数决定,取值如下:
- delete:采用 Log Retention
- compact:采用 Log Compaction
- delete,compact:同时支持 Log Retention 和 Log Compaction 两种方式。
1. LogManager
一个 Broker 上的所有日志都由 LogManager 进行管理,LogManager 会根据配置启动 5 个周期性的后台任务和 1 个清理线程:
- kafka-log-retention,日志保留任务,定期对 LogSegment 进行清理
- kafka-log-flusher,日志刷写任务,保证数据的持久性
- kafka-recovery-point-checkpoint 检查点刷新任务
- kafka-log-start-offset-checkpoint,日志起始偏移量检查
- kafka-delete-logs,日志删除
- LogCleaner线程,日志清理线程
LogManager 类中的 startup 方法如下
private[log] def startupWithConfigOverrides(defaultConfig: LogConfig, topicConfigOverrides: Map[String, LogConfig]): Unit = {
loadLogs(defaultConfig, topicConfigOverrides) // this could take a while if shutdown was not clean
/* Schedule the cleanup task to delete old logs */
if (scheduler != null) {
info("Starting log cleanup with a period of %d ms.".format(retentionCheckMs))
scheduler.schedule("kafka-log-retention",
cleanupLogs _,
delay = InitialTaskDelayMs,
period = retentionCheckMs,
TimeUnit.MILLISECONDS)
info("Starting log flusher with a default period of %d ms.".format(flushCheckMs))
scheduler.schedule("kafka-log-flusher",
flushDirtyLogs _,
delay = InitialTaskDelayMs,
period = flushCheckMs,
TimeUnit.MILLISECONDS)
scheduler.schedule("kafka-recovery-point-checkpoint",
checkpointLogRecoveryOffsets _,
delay = InitialTaskDelayMs,
period = flushRecoveryOffsetCheckpointMs,
TimeUnit.MILLISECONDS)
scheduler.schedule("kafka-log-start-offset-checkpoint",
checkpointLogStartOffsets _,
delay = InitialTaskDelayMs,
period = flushStartOffsetCheckpointMs,
TimeUnit.MILLISECONDS)
scheduler.schedule("kafka-delete-logs", // will be rescheduled after each delete logs with a dynamic period
deleteLogs _,
delay = InitialTaskDelayMs,
unit = TimeUnit.MILLISECONDS)
}
if (cleanerConfig.enableCleaner) {
_cleaner = new LogCleaner(cleanerConfig, liveLogDirs, currentLogs, logDirFailureChannel, time = time)
_cleaner.startup()
}
}
2. Log Retention
日志保留策略有 3 种:
-
基于时间
log.retention.hours、log.retention.mintes、log.retention.ms三者的优先级依次增高,LogManager 中的 cleanupLogs 方法会根据配置的时间查找过期的日志分段文件,删除文件时会先移除跳跃表中待删除的日志分段,再以“.deleted”后缀比较要删除的日志分段,最后由延迟任务来执行真正的删除操作。 -
基于日志大小
log.retention.bytes配置所有日志文件的总大小,log.segment.bytes配置单个日志分段的大小。清理时会先计算日志文件的总大小,以及要删除的文件大小,然后查找可删除的文件,最后进行删除操作,与基于时间的删除策略相同。 -
基于日志起始偏移量 当日志分段的下一个日志分段的起始偏移量小于等于 logStartOffset 时,可执行删除操作。
3. Log Compaction
Log Compaction 压缩的是只读的 LogSegment,activeSegment 不会参与到日志压缩操作中。在日志压缩过程中会启动多条 Cleaner 线程进行压缩,并且为了避免 Cleaner 线程与其他业务线程长时间竞争,对 LogSegment 压缩是分批进行的,不会一次压缩完成。