Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kafka参数retentionBytes探究 #1

Open
snipercy opened this issue Feb 23, 2017 · 1 comment
Open

kafka参数retentionBytes探究 #1

snipercy opened this issue Feb 23, 2017 · 1 comment

Comments

@snipercy
Copy link
Owner

snipercy commented Feb 23, 2017

引言

kafka 是一个重度依赖系统文件系统的message queue,消息都是直接存于硬盘,与一些基于内存的 message queue 速度相比,kafka 并不慢甚至更快,原因有顺序读写、零拷贝、日志分段等。而这些保存在硬盘中的数据也不能无休止地存在, kafka 也提供了多种机制来删除它们。由于大数据运营管理平台中需要纳管 kafka,用户可以在该平台上创建 topic,但存储是有限的,为了能够限制用户的存储使用量,故需要一种基于文件大小的消息删除机制,而与此息息相关的一个参数是 retention.bytes ,下文会从该参数出发探究该删除机制。

小试牛刀

kafka中有两个地方可以设置参数 retention.bytes:server 启动时的配置文件和topic 级别的配置(后者的设置会覆盖前者),官网对该参数的解释分别如下:
picture1
args2

为了验证该参数,将某一 topic 的 retention.bytes 设为4096B,server 和 topic 中相关配置如下:

3
4

往该topic发送一些消息观察log 文件的大小,下图显示出 log 的大小为 4206B,已经超出了参数 retention.bytes 的值,但此时 kafka 并没有执行任何的删除策略。
5

retention.bytes 的探究

为了了解 retention.bytes 是如何生效的,故找到kafka删除 log 的相关代码如下:

6

可以看出,kafka 会启动一个定时任务去删除日志,每隔 retentionCheckMs 毫秒(由参数 log.retention.check.interval.ms 指定)就执行一次 cleanupLogs ,该函数定义如下:
7

cleanupLogs 对所有 log 调用了 deleteOldSegments 函数,并记录了删除的总量(日志清理策略 log.cleanup.policy 需设置为 delete)。
8

而 deleteOldSegments 会调用 deleteRetentionSizeBreachedSegments 来执行基于 retention.bytes 的删除算法:首先,它计算出最多可以删除的文件大小(diff = size - config.config.retentionSize),接下来调用的 deleteOldSegments(shouldDelete) 会从最老的日志分段(segments)开始,遍历所有的分段,对于小于diff并且不是 active segment (用于写入消息的那个segment为active segment,一个 topic 至少要有一个分段用于读写消息)则可以被删除。下图是 deleteOldSegments(shouldDelete) 中的一段关键代码。

至此,筛选出了满足删除条件的 segments,接下来就是真正的删除它们,其主要逻辑是先对可删除segment 的文件添加后缀名(.delete)以标识,再启动一个定时任务去执行删除操作,定时任务的时延通过参数 file.delete.delay.ms 指定。

再试牛刀

此次,参数retention.bytes 和 log.segment.bytes都设置成了128B, log.segment.bytes 是日志文件分段阈值,当分段超过该值时就会创建新的分段,这样才会出现可能会被删除旧的日志分段(old segment),为了快速验证,故将其设置为一个较小的值。

10

根据前文的删除算法,上图所示的 topic 的diff=112+75-128(retention.bytes)=22,即可以删除的数据大小为22B,但是old segment 只有一个大小113B的分段,超过了22B,所以不会删除任何分段。
继续往该topic中发送一些消息,如下图 diff=113+77+75-128=137,该值大于最老的分段(34 ),所以它被标记为可删除。此时diff更新为137-113=24,而所剩下的旧分段(37)大小为75B大于diff,不符合要求,所以此次删除操作中只会将34分段删除。
11

总结

基于retention.bytes 的日志删除策略并不是一个严格限制topic大小的参数,要想该参数生效需要将log.cleanup.policy 需设置为 delete,并且需要合理的设置 log.segment.bytes 的大小,只有当有 old segment出现并且删除某old segment 后,数据仍然超过我们设定的 retention.bytes,才会真的触发删除操作。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant