Kafka Log Cleaner 笔记

1,189 阅读2分钟

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.hourslog.retention.minteslog.retention.ms 三者的优先级依次增高,LogManager 中的 cleanupLogs 方法会根据配置的时间查找过期的日志分段文件,删除文件时会先移除跳跃表中待删除的日志分段,再以“.deleted”后缀比较要删除的日志分段,最后由延迟任务来执行真正的删除操作。

  • 基于日志大小 log.retention.bytes 配置所有日志文件的总大小,log.segment.bytes配置单个日志分段的大小。清理时会先计算日志文件的总大小,以及要删除的文件大小,然后查找可删除的文件,最后进行删除操作,与基于时间的删除策略相同。

  • 基于日志起始偏移量 当日志分段的下一个日志分段的起始偏移量小于等于 logStartOffset 时,可执行删除操作。

3. Log Compaction

Log Compaction 压缩的是只读的 LogSegment,activeSegment 不会参与到日志压缩操作中。在日志压缩过程中会启动多条 Cleaner 线程进行压缩,并且为了避免 Cleaner 线程与其他业务线程长时间竞争,对 LogSegment 压缩是分批进行的,不会一次压缩完成。