kafka日志简单介绍(九)

      kafka日志压缩确保Kafka将始终至少保留单个主题分区数据日志中每个消息键的最新已知值,它用于提供更细粒度的每条记录保留,而不是基于时间的粗粒度保留。我们看下下面这张图片,它显示了Kafka日志的逻辑结构,以及每个消息的偏移量。


    从图片中我们可以看出这个日志是经过了压缩的,因为其中一些偏移量值已经不存在了,然而偏移量的值是一直有序增加的,并且不是重复使用偏移值,假如我们需要读取36,37,38这3个位置的偏移量,然而经过了日志的压缩处理后,我们可以看到只有38的位置还有偏移量存在,因此读取出来的偏移量位置也只能从38开始了,我们在看下下面这幅图,看看日志压缩前后的对比


    通过图片我们可以看出来,每个偏移量里面都包含了key-value键值对,在执行压缩前,有多对相同的key但是不同的value,经过压缩后我们只保留了最新的key-value值,这也说明为了保证能够存储更多的数据,经过压缩后我们把相同key的存在过的值都做了移除操作,需要注意的是如果你传入的键值对是的值是null的,那么说明你是要删除这个key对应的所有值,在删除完后如第一幅图所标识有个删除保留点(delete retention point),用来记录删除的位置,并且该记录点将在一段时间后从日志中清除,以释放空间。日志的压缩是在后台通过周期性地重新读取日志段来完成的。清理不会阻塞读取,并且可以调整为使用不超过可配置数量的I/O吞吐量,以避免影响生产者和消费者。那么日志压缩又做了哪些数据保证呢?
    1.任何消费者只要能到达日志头部的都能看到所有写入的消息,并且所有的消息将会保存一个有序的偏移量。min.compaction.lag.ms可以用来设置在消息被写入后在被压缩之前必须经过最小的时间长度。max.compaction.lag.ms可以用来设置消息被写入到消息符合压缩条件的时间之间的最大延迟时间。
    2.始终保持消息的有序排序。压缩不会重新进行消息的排序,只是删除一些消息。
    3.消息的偏移量永远不会改变。它是日志中某个位置的永久标识符。
    4.任何从日志一开始就有的使用者至少可以看到按照消息记录被写入的顺序的所有记录的最终状态。同时如果消费者在比delete.retention.ms(默认24小时)设置的时间的更短的时间内到达日志头部,则可以看到已删除记录的所有删除标记,也就是说因为删除标记的删除是与读取同时发生的,所以如果延迟的时间超过delete.retention.ms配置的时间,消费者就有可能会错过删除标记。
    日志压缩是由日志清理器处理的,它是一个后台线程池,它重新复制日志段文件,删除出现在日志头部的键的已存在过的记录。每个比较线程的工作方式如下:
    1.选择头尾比例最高的那个日志。
    2.给日志头部的每个键创建最后偏移量的简洁摘要。
    3.从头到尾重复日志,删除稍后在日志中出现的键。新的、干净的段会被立即交换到日志中,因此所需的额外磁盘空间只是一个额外的日志段(而不是日志的完全副本),因此占用磁盘空间应该不会很大。
    4.日志头的摘要本质上就是一个空间紧凑的哈希表。而每个条目占用24个字节。因此,使用8GB的清理缓冲区,一次清理迭代可以清理大约366GB的日志头(假设有1k条消息)。
    在默认情况下日志压缩是默认开启的,一般不需要管理,它的启动是一个线程池线程,如果需要对特定的topic进行压缩管理,我们可以通过配置log.cleanup.policy=compact来设置,这个配置是服务器节点级别的配置,会对该集群下的所有节点的日志压缩生效。
log.cleaner.min.compaction.lag.ms可以用来设置保留日志中未压缩的“头”的最小数量,这样就可以用来防止比最小消息年龄更新的消息被压缩。如果没有设置,除最后一个段(即当前写入的那个)外,所有日志段都可以进行压缩。即使活动段的所有消息都大于最小压缩时间延迟,活动段也不会被压缩。
    log.cleaner.max.compaction.lag.ms可以用来设置未压缩的日志“头”符合日志压缩条件后的最大延迟时间,防止生产率低的日志在不受限制的时间内不符合压缩条件。如果未设置,则不超过min.cleanable.dirty.ratio的日志信息不会被压缩。请注意,这个压缩最后期限并不是一个硬性保证,因为它仍然取决于日志清理器线程的可用性和实际压缩时间。同时需要监视uncleanable-partitions-count, max-clean-time-secs和max-compaction-delay-secs指标数据。

    我们这里有一个日志主题名为“my_topic”,假如它有两个分区,那么它将由两个目录(即my_topic_0和my_topic_1)组成,其中每个目录填充了包含该主题消息的数据文件。一个格式化的日志文件是一个有序的“日志条目”,每个日志条目是存储消息长度的4字节整数N,N表示的是消息的字节数。每个消息都有一个64位整数偏移量唯一标识,这个64位整数偏移量提供了该消息在该分区上曾经发送到该主题的所有消息流中开始的字节位置。每个日志文件都以其包含的第一个消息的偏移量命名,所以创建的第一个文件是00000000000.kafka,每个附加文件将有一个整数名大约S字节从上一个文件,其中S是在配置中给定的最大日志文件大小。


    每条记录的内容格式都是通过版本控制的,因此不用担心在生产者、broker节点以及消费者进行操作时需要进行转换等操作。作为消息的id一般并不是使用消息偏移量来确定的,在kafka中是通过生产者使用GUID进行生成的随机id,并且在每个节点上都会维护一个GUID和偏移量的关系。但是自从消费者必须给每个server维护一个id后,GUID的全局唯一性就不再不提供任何值。此外,维护从随机id到偏移量的映射的复杂性需要一个必须与磁盘同步的重权重索引结构,本质上需要一个完整的持久随机访问数据结构。因此,为了简化查找结构,kafka使用一个简单的每个分区原子计数器,它可以与分区id和节点id耦合,以唯一地标识消息;一旦我们确定了一个计数器,那么跳转到直接使用偏移量似乎很自然——毕竟两者都是单调递增的整数,并且对于一个分区来说也是唯一的,同时偏移量对消费者API是隐藏的。
    日志消息的读取是通过给出消息的64位逻辑偏移量和s字节的最大块大小来完成的。这将在s字节缓冲区中包含的消息上返回一个迭代器。S要比任何单个消息都大,但如果出现异常大的消息,可以多次重试读取,每次读取都将缓冲区大小加倍,直到成功读取消息。可以指定最大的消息和缓冲区大小,以使服务器拒绝大于某个大小的消息,并为客户端提供获取完整消息所需的最大读取值的绑定。读缓冲区很可能以部分消息结束,这很容易通过大小分隔检测到。
从偏移量读取数据首先必须定位存储数据的日志段文件,并计算与全局偏移量相关的文件偏移量,然后根据文件偏移量读取数据。而搜索是根据为每个文件维护的内存范围执行简单的二进制搜索变化。日志提供了获取最近写的消息的功能,以允许客户从“现在”开始订阅。如果使用者未能在其sla指定的天数内使用其数据时,当客户端尝试使用一个不存在的偏移量时,它会抛出一个OutOfRangeException异常,并且可以根据用例的情况自行重置或者失败。我们看下最终发给消费者的格式化消息格式:
获取单个结果
MessageSetSend (fetch result)

total length     : 4 bytes
error code       : 2 bytes
message 1        : x bytes
...
message n        : x bytes

获取多个结果
MultiMessageSetSend (multiFetch result)

total length       : 4 bytes
error code         : 2 bytes
messageSetSend 1
...
messageSetSend n
    对应日志的删除,每次只删除一个日志段。日志管理器应用两个指标来识别适合删除的段:时间和大小。对于基于时间的策略,将考虑记录时间戳,用段文件中最大的时间戳(记录的顺序无关)定义整个段的保留时间。大小的策略默认情况下是禁用的。当启用日志管理器时,日志管理器会一直删除最旧的段文件,直到分区的总大小符合在配置的限制之内。为了避免在删除修改段列表的同时锁定读取,kafka实现即写即拷风格的段列表,该实现提供了一致的视图,允许在删除的同时在日志段的不可变静态快照视图上进行二进制搜索。
    日志提供了一个配置参数M,用于控制在强制刷新磁盘之前写入的最大消息数。在启动时,将运行一个日志恢复进程,该进程会遍历最新日志段中的所有消息,并验证每个消息条目是否有效。如果消息条目的大小和偏移量之和小于文件的长度,并且消息有效负载的CRC32匹配与消息存储的CRC,则该消息条目是有效的。在检测到损坏时,日志被截断到最后一个有效偏移量。注意的是这里有两种类型的损坏需要进行处理:截断(由于崩溃而丢失未写块)和损坏(将无意义块添加到文件中)。这是由于操作系统并不保证写入的命令在文件iNode和真实块之间,因此,除了丢失写入数据之外,如果inode被更新为新的大小,但是在包含该数据的块被写入之前发生崩溃,那么该文件将获得无意义数据。CRC检测到这种情况,并防止它破坏日志。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值