java实现清除kafka历史消息 如何清除kafka数据
转载
Kafka删除数据有两种方式,一种是按照时间,超过一段时间后删除过期消息,第二种是按照消息大小删除数据的,消息数量超过一定大小后删除最旧的数据
但是Kafka的数据是存储在文件系统内的,随机删除数据是不可能的,那么,Kafka是如何删除数据的呢?
Kafka删除数据主逻辑
对应配置: log.cleanup.interval.mins
当前使用值:1
file: core/src/main/scala/kafka/log/LogManager.scala
line: 271
/**
* Delete any eligible logs. Return the number of segments deleted.
*/
def cleanupLogs() {
debug("Beginning log cleanup...")
var total = 0
val startMs = time.milliseconds
for(log <- allLogs) {
debug("Garbage collecting '" + log.name + "'")
total += cleanupExpiredSegments(log) + cleanupSegmentsToMaintainSize(log)
}
debug("Log cleanup completed. " + total + " files deleted in " +
(time.milliseconds - startMs) / 1000 + " seconds")
}
|
Kafka 每隔 log.cleanup.interval.mins 分钟调用一次 cleanupLogs ,该函数对所有 Logs 执行清理操作,(目前不确定 Logs 对应的是 Topic 还是 Partition,目测应当是 Partition)
- cleanupExpiredSegments 负责清理超时的数据
- cleanupSegmentsToMaintainSize 负责清理超过大小的数据
清理超时数据 (必选策略)
对应配置:log.retention.hours
当前使用值: 72 (3天)
file: core/src/main/scala/kafka/log/LogManager.scala
line: 237
/**
* Runs through the log removing segments older than a certain age
*/
private
val startMs = time.milliseconds
val topic = parseTopicPartitionName(log.name).topic
val logCleanupThresholdMs = logRetentionMsMap.get(topic).getOrElse(this.logCleanupDefaultAgeMs)
val toBeDeleted = log.markDeletedWhile(startMs - _.messageSet.file.lastModified > logCleanupThresholdMs)
val total = log.deleteSegments(toBeDeleted)
total
}
|
- 该函数首先获取 topic,根据 topic 获取日志超时时间,该超时时间可以使用配置 log.retention.hours.per.topic 单独指定,如果没有单独指定,则使用统一的 log.retention.hours 配置。
- 然后扫描所有该日志对应的 Segment 文件,对所有最近修改时间与当前时间差距大于超时时间的日志的 Segment 文件,标记为删除
- 最后删除标记为删除的 Segment 文件
清理超大小数据 (可选策略)
对应配置:log.retention.bytes
当前使用值: -1 (默认值,即不采用该策略)
file: core/src/main/scala/kafka/log/LogManager.scala
line: 250
/**
* Runs through the log removing segments until the size of the log
* is at least logRetentionSize bytes in size
*/
private
val topic = parseTopicPartitionName(log.dir.getName).topic
val maxLogRetentionSize = logRetentionSizeMap.get(topic).getOrElse(config.logRetentionBytes)
if(maxLogRetentionSize < 0 || log.size < maxLogRetentionSize) return 0
var diff = log.size - maxLogRetentionSize
def shouldDelete(segment: LogSegment) = {
if(diff - segment.size >= 0) {
diff -= segment.size
true
} else {
false
}
}
val toBeDeleted = log.markDeletedWhile( shouldDelete )
val total = log.deleteSegments(toBeDeleted)
total
}
|
- 当不需要删除或者日志总大小小于配置时,不执行
- 按照从旧到新的顺序扫描各个 Segments,如果该Segment大小 <= 当前日志超过设置值的diff,该Segment会被标记为需要删除
- 执行删除操作
按照 Segment 删除的影响
对超时规则的影响
每个 Segment 文件实际会按照最后一条日志的时间进行删除。当日志中的最后一条日志没有超时时,该文件不会被删除。
对超过大小规则的影响
删除该Segment之后,数据仍然超过大小,才会删除该Segment。如果删除该Segment后,数据大小小于设定上限,则不删除该Segment。
Segment相关配置
log.segment.bytes
- 当前使用值:1073741824
- 注释:单个Segment 的大小设置,达到这个大小时,Kafka会新建一个 Segment 文件
log.roll.hours
- 当前使用值:24
- 隔一段时间,Kafka 会新建一个Segment文件,即便之前的Segment文件没有达到 log.segment.bytes
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。