kafka服务端之日志存储
文章目录
- 日志布局
- 日志索引
- 日志清理
- 日志删除
- 基于时间
- 基千日志大小
- 基于日志起始偏移量
- 日志压缩
- 总结
日志布局
Ka饮a 中的消息是以主题为基本单位进行归类的, 各个主题在逻辑
上相互独立。 每个主题又可以分为一个或多个分区, 分区的数量可以在主题创建的时候指定,也可以在之后修改。 每条消息在发送的时候会根据分区规则被追加到指定的分区中, 分区中的每条消息都会被分配一个唯 一的序列号, 也就是通常所说的偏移量(offset )。
如果分区规则设置得合理, 那么所有的消息可以均匀地分布到不同的分区中, 这样就可以实现水平扩展。 不考虑多副本的情况, 一个分区对应一个日志(Log)。 为了防止Log过大,Ka住a又引入了日志分段(LogSegment)的概念,将Log切分为多个LogSegment, 相当于 一个巨型文件被平均分配为多个相对较小的文件, 这样也便于消息的维护和清理。 事实上, Log 和LogSegnient也不是纯粹物理意义上的概念, Log在物理上只以文件夹的形式存储, 而每个LogSegment对应于磁盘上的 一个日志文件 和两个索引文件, 以及可能的其他文件(比如以" . txnindex"为后缀的事务索引文件)。如下图简单描绘了日志存储结构。
向Log中追加 消息时是顺序写入的,只有最后 一 个LogSegment才能执行写入操作, 在此之 前所有的LogSegment都 不能写入数据。 为了方便描述, 我们将最后 一 个LogSegment称为"activeSegment" , 即表示当前活跃的日志分段。 随着消息的不断写入 , 当activeSegment满足一 定 的条件 时 , 就需要创建新的activeSegment, 之后追加的消息将写入新的activeSegment。
为了便于消息的检索, 每个LogSegment中的日志文件 (以 " .log"为文件后缀)都有对应的两个索引文件:偏移量 索引文件(以".index"为文件后缀)和时间戳索引文件(以".timeindex"为文件后缀) 。 每个LogSegment都有 一 个基准偏移量baseOffset, 用来表示当前LogSegment中第 一 条消息的offset。 偏移量是一 个64位的长整型数, 日志文件和两个索引文件都是根据 基准偏移量(baseOffset)命名 的, 名称固定为20 位数字, 没有达到的位数则用0填充。 比如第一 个LogSegment的基准偏移量为O, 对应的日志文件为00000000000000000000.log。
日志索引
每个日志分段文件对应了两个索引文件,主要用来提高查找消息的效率。偏移量索引文件用来建立消息偏移量( offset )到物理地址之间的映射关系,方便快速定位消息所在的物理文件位置;时间戳索引文件则根据指定的时间戳( timestamp )来查找对应的偏移量信息。
Kafka 中的索引文件以稀疏索引( sparse index )的方式构造消息的索引,它并不保证每个消息在索引文件中都有对应的索引 I页 。 每当写入一定量(由 broker 端参数 log.index.interval.bytes 指定,默认值为 4096 ,即 4KB )的消息时,偏移量索引文件和时间戳索引文件分别增加一个偏移量索引项和时间戳索引项,增大或减小 log.index . interval.bytes的值,对应地可以增加或缩小索引项的密度。
稀疏索引通过 MappedByteBuffer 将索引文件映射到内存中,以加快索引的查询速度。偏移量索引文件中的偏移量是单调递增的,查询指定偏移量时,使用二分查找法来快速定位偏移量的位置,如果指定的偏移量不在索引文件中,则会返回小于指定偏移量的最大偏移量 。 时间戳索引文件中的时间戳也保持严格的单调递增,查询指定时间戳时,也根据二分查找法来查找不大于该时间戳的最大偏移量,至于要找到对应的物理文件位置还需要根据偏移量索引文件来进行再次定位。稀疏索引的方式是在磁盘空间、内存空间、查找时间等多方面之间的一个折中。
对非当前活跃的日志分段而言,其对应的索引文件内容己经固定而不需要再写入索引项,所以会被设定为只读 。 而对当前活跃的日志分段 C activeSegment )而言,索引文件还会追加更多的索引项,所以被设定为可读写。在索引文件切分的时候, Kafka 会关闭当前正在写入的索引文件并置为只读模式,同时以可读写的模式创建新的索引文件,索引文件的大小由 broker 端参数 log . index.size . max.bytes 配置。 Kafka 在创建索引文件的时候会为其预分配log.index . size .m ax . bytes 大小的空间,注意这一点与日志分段文件不同,只有当索引文件进行切分的时候, Kafka 才会把该索引文件裁剪到实际的数据大小 。 也就是说,与当前活跃的日志分段对应的索引文件的大小固定为 log . index.s 工 ze.max.bytes ,而其余日志分段对应的索引文件的大小为实际的占用空间。
日志清理
Kafka 将 消息存储在磁盘中,为了 控制磁盘占用空间的不断增加就需要对消息做一 定的清理操作。 Kafka 中 每 一个分区副本都对应 一个 Log, 而Log又可以分为多个日志分段, 这样也便于日志的清理操作。 Kafka提供了两种日志清理策略。
- (1)日志删除(LogRetention): 按照 一 定的保留策略直接删除不符合条件的日志分段。
- (2)日志压缩 (Log Compaction): 针对每个消息的key进行整合, 对千有相同 key的不 同value 值, 只保留最后 一个版本。
我们可以通过broker端参数log.cleanup.police 来设置 日志清理策略,此参数的默认
值为"delete " , 即采用日志删除的清理策略。 如果要采用日志压缩的清理策略, 就需要将log.cleanup.police 设置为"compact" , 并且还需要将log.cleaner.enable (默认值
为true )设定为true。 通过将log.cleanup.police 参数 设置为"del ete,compact" , 还可以
同时支持日志删除和日志压缩两种策略。 日志清理的粒度可以控制到主题级别, 比如与log.cleanup.police 对应的主题级别的参数为cleanup.police。
日志删除
在Kafka 的日志管理器中会有一个专门的日志删除任务来周期性地检测和删除不符合 保留条件的日志分段文件,这个周期可以通过broker端参数log.retention.check.interval.ms来配置 ,默认值为300000, 即5分钟。 当前日志分段的保留策略有3 种:基于时间 的保留策略、基于日志大小的保留策略 和基于日志起始偏移量的保留策略 。实际应用中这些策略只要命中一个就可以触发日志删除。
基于时间
日志删除任务会检查当前日志文件中是否有保留时间超过设定的阙值(retentionMs)来寻找可删除的日志分段文件集合(deletableSegments)。etentionMs可以通过broker
端参数log.retention.hours、log.retention.minutes和log.retention.ms来配
置 , 其 中 log.retention.ms 的优先级最高, log.retention.minutes 次之,
log.retention.hours最低。 默认情况下只配置 了log.retention.hours参数, 其值为
168, 故默认情况下日志分段文件的保留时间为7天。
查找过期的日志分段文件,并不是简单地根据日志分段的最近修改时间lastModifiedTime来计算的, 而是根据日志分段中最大的时间戳largestTimeStamp来计算的。 因为日志分段的lastModifiedTime可以被有意或无意地修改, 比如执行了touch操作 , 或者分区副本进行了重新分配,lastModifiedTime并不能真实地反映出日志分段在磁盘的保留时间。要获取日志分段中的最大时间戳largestTimeStamp的值, 首先要查询该日志分段所对应的时间戳索引文件,查找 时间戳索引文件中最后 一条索引项, 若最后 一 条索引项的时间戳字段值 大于O,则取其值, 否则才设置为最近修改时间 lastModifedTime 。
若待删除的日志分段的总数等千该日志文件中所有的日志分段的数量, 那么说明所有的日志分段都已过期, 但该日志文件中还要有一个日志分段用千接收消息的写入, 即必须要 保证有一个活跃的日志分段activeSegment, 在此种情况下, 会先切分出一个新的日志分段作为activeSegment, 然后执行删除操作。
删除日志分段时,首先会从Log对象中所维护日志分段的跳跃表中移除待删除的日志分段,以保证没有线程对这些日志分段进行读取操作。 然后将日志分段所对应的所有文件添加上".deleted"的后缀(当然也包括对应的索引文件)。 最后交由 一个以"delete-fi le"命名的延迟任务来删 除这些 以 ".deleted "为 后 缀的 文 件 , 这个 任务的 延 迟执 行 时 间可 以 通 过file.delete.delay.ms参数来调配, 此参数的默认值为60000, 即1 分钟。
基千日志大小
日志删除任务会检查当前日志的大小是否超过设定的阀值 (retentionSize)来寻找可删除的日志分段的文件集合(deletableSegments), 如图所示。retentionSize可以通过broker端参数log.retention.bytes来配置 ,默认值为-1 , 表示无穷大。注意log.retention.bytes
配置的是Log中所有日志文件的总大小, 而不是单个日志分段(确切地说应该为log 日志文件)的大小。 单个日志分段的大小由broker 端参数log.segment.bytes 来限制, 默认值为1073741824, 即1GB。
基于日志大小的保留策略与基于时间的保留策略类似, 首先计算日志文件的总大小 size 和retentionSize的差值 diff, 即计算需要删除的日志总大小, 然后从日志文件中的第 一个日志分段开始进行查找可删除的日志分段的文件集合deletableSegments。 查找出deletableSegments之后就执行删除操作, 这个删除操作和基千时间的保留策略的删除操作相同, 这里不再赘述。
基于日志起始偏移量
一般情况下, 日志文件的起始偏移量 logStartOffset 等于第 一个日志分段的baseOffset , 但这并不 是绝对的, logStartOffset 的值 可 以 通 过DeleteRecordsRequest请求、 日志的清理和截断等操作 进行修改。
基于日志起始偏移量的保留策略的判断依据是某日志分段的下一个日志分段的起始偏移量baseOffset 是否小于等于logStartOffset, 若是, 则可以删除此日志分段 。 如图所示, 假设logStartOffset等于25, 日志分段 l 的起始偏移量为O, 日志分段2的起始偏移量为11, 日志分段 3的起始偏移量为23, 通过如下动作收集可删除的日志分段的文件集合deletableSegments:
- (1 )从头开始遍历每个日志分段 , 日志分段 l 的下一个日志分段的起始偏移量为11, 小 于logStartOffset的大小,将日志分段 l加入deletableSegments。
- (2)日志分段2的下 一个日志偏移量的起始偏移量为23 , 也小于logStartOffset的大小,将日志分段2页加入deletableSegments。
- (3)日志分段3的下 一个日志偏移量在logStartOffset的右侧, 故从日志分段3开始的所有日志分段都不会加入deletableSegments。
收集完可删除的日志分段的文件集合之后的删除操作同基于日志大小的保留策略和基千时间的保留策略相同, 这里不再赘述。
日志压缩
Kafa中的Log Compaction是指在默认的日志删除(Log Retention)规则之外提供的 一种
清理过时数据的方式。 如图所示, Log Compaction对于有相同key的不同value值, 只保留最后 一个版本。如果应用只关心key对应的最新value值,则可以开启Kafka的日志清理功能,Kafa会定期将相同key的消息进行合并, 只保留最新的value值。
Log Compaction执行前后, 日志分段中的每条消息的偏移量和写入时的偏移量保待 一致。Log Compaction 会生成新的日志分段 文件, 日志分段中每条消息的物理位置会重新按照新文件来组织。 Log Compaction执行过后的偏移量不再是连续的, 不过这并不影响日志的查询。
Log Compaction会保留key相应的最新value值 ,那么当需要删除 一个key时怎么办? Kafka提供了 一个墓碑消息(tombstone)的概念, 如果 一 条消息的key不为null, 但是其value为null,那么此消息就是墓碑消息 。 日志清理线程发现墓碑消息时会先进行常规的清理, 并保留墓碑消息 一 段 时间。
Log Compaction执行过后的日志分段的大小会比原先的日志分段的要小, 为了防止出现太多的小 文件, Kafa在实际清理过程 中并不对单个的日志分段进行单独清理,而是将日志文件中offset从0至frstUncleanableOffset的所有日志分段进行分组,每个日志分段只属于一 组,分组策略为:按照日志分段的顺序遍历, 每 组中日志分段的占用空间大小之和不超过segmentSize(可以通过broker端参数log.segment.bytes设置, 默认值为1GB) , 且对应的索引文件占用大小之和不超过maxindexSize(可以通过broker端参数log.index.interval.bytes设置, 默认值为10MB) 。 同 一个组的多个日志分段清理过后, 只会生成 一个新的日志分段 。
总结
注意将 日志压缩和日志删除区分开, 日志删除是指清除整个日志分段, 而日志压缩是针对相同key的消息的合并清理 。
相关文章:

kafka服务端之日志存储
文章目录 日志布局日志索引日志清理日志删除基于时间基千日志大小基于日志起始偏移量 日志压缩总结 日志布局 Ka饮a 中的消息是以主题为基本单位进行归类的, 各个主题在逻辑 上相互独立。 每个主题又可以分为一个或多个分区, 分区的数量可以在主题创建的…...

软件工程的熵减:AI如何降低系统复杂度
软件开发的世界,如同一个不断膨胀的宇宙。随着功能的增加和时间的推移,代码库越来越庞大,系统复杂度也随之水涨船高。代码膨胀、维护困难、开发效率低下等问题困扰着无数开发者。这不禁让人联想到物理学中的“熵增”原理——一个孤立系统的熵…...

模拟开发小鹅通首页网站练习
HTML代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>小鹅通-首页</title><!-- 引入页…...

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_strerror 函数
声明 ngx_strerror 函数声明在 ngx_errno.h 中: u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size); 实现 在 ngx_errno.c 中: u_char * ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) {size_t len;const char *ms…...

第26场蓝桥入门赛
5.扑克较量【算法赛】 - 蓝桥云课 C: #include <iostream> #include <algorithm> using namespace std;int a[100005];int main() {int n,k;cin>>n>>k;for (int i1; i<n; i)cin>>a[i], a[i] % k;sort(a1, a1n);int mx a[1]k-a…...

【CAPL实战】实现弹窗提示及操作
文章目录 前言1、TestWaitForTesterConfirmation函数2、测试举例 前言 在使用CANoe进行车载通信测试的过程中,可能因为一些条件限制,我们需要在测试执行的过程中去观察一些硬件显示或者调整相关硬件状态。比如测试过程中,需要手动去调整小电…...

基于ESP32的远程开关灯控制(ESP32+舵机+Android+物联网云平台)
目录 材料环境准备物理材料软件环境 物联网平台配置(MQTT)MQTT阿里云平台配置创建产品添加设备自定义topic esp32配置接线代码 Android部分和云平台数据流转 前言:出租屋、宿舍网上关灯问题,计划弄一个智能开关以及带一点安防能力…...

协议-ACLLite-ffmpeg
是什么? FFmpeg是一个开源的多媒体处理工具包,它集成了多种功能,包括音视频的录制、转换和流式传输处理。FFmpeg由一系列的库和工具组成,其中最核心的是libavcodec和libavformat库。 libavcodec是一个领先的音频/视频编解码器库&…...

ARM嵌入式学习--第十四天(SPI)
SPI -介绍 SPI(Serial Peripheral Interface)串行外围设备接口。是由Motorola公司开发,用来在微控制器和外围设备芯片之间提供一个低成本,易使用的接口。这样接口可以用来连接存储器、AD转换器、DA转换器、实时时钟、LCD驱动器、…...

DeepSeek-V2 论文解读:混合专家架构的新突破
论文链接:DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model 目录 一、引言二、模型架构(一)多头部潜在注意力(MLA):重塑推理效率(二)DeepSeekM…...

5分钟了解回归测试
1. 什么是回归测试(Regression Testing) 回归测试是一个系统的质量控制过程,用于验证最近对软件的更改或更新是否无意中引入了新错误或对以前的功能方面产生了负面影响(比如你在家中安装了新的空调系统,发现虽然新的空…...

路由器如何进行数据包转发?
路由器进行数据包转发的过程是网络通信的核心之一,主要涉及以下几个步骤: 接收数据包:当一个数据包到达路由器的一个接口时,它首先被暂时存储在该接口的缓冲区中。 解析目标地址:路由器会检查数据包中的目标IP地址。…...

【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(四) -> 常见组件(一)
目录 1 -> List 1.1 -> 创建List组件 1.2 -> 添加滚动条 1.3 -> 添加侧边索引栏 1.4 -> 实现列表折叠和展开 1.5 -> 场景示例 2 -> dialog 2.1 -> 创建Dialog组件 2.2 -> 设置弹窗响应 2.3 -> 场景示例 3 -> form 3.1 -> 创建…...

iOS 自动翻滚广告条(榜单条)实现方案
引言 在直播场景中,榜单信息、活动公告或者广告推广通常需要以醒目的方式展示,但由于屏幕空间有限,一次只能显示一条内容。为了让用户能够持续关注这些信息,我们可以实现一个自动翻滚的广告条(或榜单条)&a…...

TensorFlow深度学习实战(7)——分类任务详解
TensorFlow深度学习实战(7)——分类任务详解 0. 前言1. 分类任务1.1 分类任务简介1.2 分类与回归的区别 2. 逻辑回归3. 使用 TensorFlow 实现逻辑回归小结系列链接 0. 前言 分类任务 (Classification Task) 是机器学习中的一种监督学习问题,…...

动态规划问题——青蛙跳台阶案例分析
问题描述: 一只青蛙要跳上n级台阶,它每次可以跳 1级或者2级。问:青蛙有多少种不同的跳法可以跳完这些台阶? 举个例子: 假设台阶数 n 3 ,我们来看看青蛙有多少种跳法。 可能的跳法: 1. 跳1级…...

element-ui使用el-table,保留字段前的空白
项目名称项目编号1、XXXXX1111111111111111111 1.1 XXXXX11111111111111222222222 如上表格中,实现项目名称字段1.1前空白的效果。 从JAVA返回的数据带有空白,即数据库中插入的数据带有空白。 原先写法: <el-table><el-tabl…...

kamailio中路由模块汇总
功能模块描述请求路由 (request_route)主要处理进入的SIP请求,包含初步检查、NAT检测、CANCEL请求处理、重传处理等。处理通过REQINIT、NATDETECT、RELAY等子模块的调用。CANCEL处理对CANCEL请求进行处理,包括更新对话状态并检查事务。如果事务检查通过&…...

如何使用 DeepSeek 搭建本地知识库
使用 DeepSeek 搭建本地知识库可以帮助您高效管理和检索本地文档、数据或知识资源。以下是详细的步骤指南: 1. 准备工作 (1) 安装 DeepSeek 确保您的系统已安装 Python 3.8 或更高版本。使用 pip 安装 DeepSeek: bash pip install deepseek (2) 准备…...

网络HTTP详细讲解
学习目标 什么是HTTPHTTP的请求和响应常见的HTTP状态码HTTP的安全性 什么是HTTP?HTTP的请求和响应,常见的HTTP状态码,HTTP的安全性 什么是HTTP HTTP(HyperText Transfer Protocol,超文本传输协议)是一种用…...

《Origin画百图》之边际分布曲线图
《Origin画百图》第六集——边际分布曲线图 入门操作可看《30秒,带你入门Origin》 边际分布曲线图,其中包含散点图形,而在图的边际有着分布曲线图。在比较数据以查看多个变量之间是否存在关系时非常有用。 1.数据准备:为多列XY数…...

【Milvus】向量数据库pymilvus使用教程
以下是根据 Milvus 官方文档整理的详细 PyMilvus 使用教程,基于 Milvus 2.5.x 版本: PyMilvus 使用教程 目录 安装与环境准备连接 Milvus 服务数据模型基础概念创建集合(Collection)插入数据创建索引向量搜索删除操作完整示例注…...

React 生命周期函数详解
React 组件在其生命周期中有多个阶段,每个阶段都有特定的生命周期函数(Lifecycle Methods)。这些函数允许你在组件的不同阶段执行特定的操作。以下是 React 组件生命周期的主要阶段及其对应的生命周期函数,并结合了 React 16.3 的…...

第 26 场 蓝桥入门赛
2.对联【算法赛】 - 蓝桥云课 问题描述 大年三十,小蓝和爷爷一起贴对联。爷爷拿出了两副对联,每副对联都由 N 个“福”字组成,每个“福”字要么是正的(用 1 表示),要么是倒的(用 0 表示&#…...

组合(力扣77)
从这道题开始,我们正式进入回溯算法的学习。之前在二叉树中只是接触到了一丢丢,而这里我们将使用回溯算法解决很多经典问题。 那么这道题是如何使用回溯算法的呢?在讲回溯之前,先说明一下此题是如何递归的。毕竟回溯递归不分家&a…...

网络工程师 (22)网络协议
前言 网络协议是计算机网络中进行数据交换而建立的规则、标准或约定的集合,它规定了通信时信息必须采用的格式和这些格式的意义。 一、基本要素 语法:规定信息格式,包括数据及控制信息的格式、编码及信号电平等。这是协议的基础,确…...

Linux之文件IO前世今生
在 Linux之文件系统前世今生(一) VFS中,我们提到了文件的读写,并给出了简要的读写示意图,本文将分析文件I/O的细节。 一、Buffered I/O(缓存I/O)& Directed I/O(直接I/O&#…...

如何在Windows中配置MySQL?
MySQL是一个广泛使用的开源关系型数据库管理系统,它支持多种操作系统平台,其中包括Windows。无论是开发者进行本地开发,还是管理员为应用程序配置数据库,MySQL都是一个非常流行的选择。本篇文章将详细介绍如何在Windows操作系统中…...

Kafka 入门与实战
一、Kafka 基础 1.1 创建topic kafka-topics.bat --bootstrap-server localhost:9092 --topic test --create 1.2 查看消费者偏移量位置 kafka-consumer-groups.bat --bootstrap-server localhost:9092 --describe --group test 1.3 消息的生产与发送 #生产者 kafka-cons…...

数学知识学习1
1、数论 1质数判定 i<n/i优化O(sqrt(n)) bool is_prime(int n){if(n<2)return false;for(int i2;i<n/i;i){if(n%i0)return false;} true; } 分解质因数 i<n/i优化O(sqrt(n)) // 定义一个函数 divide,接收一个整数 n 作为参数,用于分解质…...