找回密码
 立即注册
首页 业界区 业界 Kafka 社区KIP-405中文译文(分层存储)

Kafka 社区KIP-405中文译文(分层存储)

貊淀 2025-6-9 08:33:14
原文链接:https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage
译者:Kafka KIP-405是一篇非常优秀的多层存储的设计稿,不过此设计稿涉及内容很多,文章量大、严谨、知识点诸多。我们国内还没有对其有相对完整的译文,面对如此上乘的文章,译者想降低其门槛,让国内更多的人了解其设计,因此花费了诸多时间精力将此文进行了全文翻译,同时有一些可能让人产生疑惑的技术细节,译者也都打上了注释,希望可以帮助更多的人。当然如果有一些Kafka基础,且英文阅读流畅的话,译者还是建议去看原文
背景

Kafka是基础数据重要的组成部分,并且已经得到用户广泛的认可,增长势头迅猛。随着集群规模的增加,越来越多的数据将会被存储在Kafka上,其消息的保留时长、集群的弹缩、性能以及运维等日益变得越来越重要

Kafka采用append-only的日志追加模式,将数据存在在本地磁盘中。消息保留时长通过配置项log.retention来进行控制,既可以设置全局层面的,同时也可以设计某个topic维度的。消息保留时长能否确保数据持久化不丢失,即便是consumer短暂性宕机或不可用,当其成功重启后,只要时间没有超过log.retention,消息依旧能够读取

总的消息的存储量,与topic/partition数量、消息存储速率、消息保留时长相关,一个Kafka的Broker通常在本地磁盘上存储了大量的数据,例如10TB,这种大量本地存储的现象给Kafka的维护带来了巨大挑战
Kafka作为一种长期的存储服务

Kafka的普及率越来越高,也逐渐成为了很多数据的入口。它会将数据持久化下来,因此允许用户进行一些非实时的消费操作。很多用户因为Kafka协议的简单以及消费者API的广泛采用,且允许用户将数据保留很长一段时间,这些特性都有助于Kafka日益成为了数据的source of data(SOT)

目前,Kafka一般会配置一个较短的保留时长(例如3天),然后更老的数据可以通过数据管道拷贝至更具弹缩能力的外部存储(例如HDFS)以便长期使用,结果就是客户端需要建立2种机制去读取数据,相对新的数据读取Kafka,老数据则读取HDFS

Kafka存储的提高,一般是依赖增加更多的Broker节点来实现的,但是这样同样也会导致新增了更多的内存+cpu,相对比可弹缩的外部存储来讲,这样无疑是增加了全局的开销,并且一个很多节点的集群同样增加了运维、部署的难度
Kafka本地存储以及维护的复杂性

当Kafka的一个broker坏掉了,将会用一个新的broker来替代,然后这个新节点必须从其他节点上拉取旧节点的全量数据。同样,当新添加一个broker来横向扩展集群存储时,集群的rebalance会为新节点分配分区,这同样需要复制大量的数据。恢复及rebalance的耗时与kafka broker上的数据量呈正相关。许多多broker的集群(例如100个broker),节点故障是非常常见的情况,在恢复过程中消耗了大量的时间,这使得运维操作变得非常困难

减少每个broker上的存储数据量能够减少recovery及rebalance时间,但是这样操作的话同样需要减少消息的保留时长,这样就使得Kafka可提供的消息回溯时间变得更少
Kafka上云

本地部署的Kafka一般都会使用多个具备硬件SKU的高容量磁盘,从而最大程度提高I/O的吞吐量。而在云上,具有类似SKU的本地磁盘,要么不可用,要么非常昂贵。如果Kafka能够使用容量较小的SKU作为本地存储,那么它就更适合上云
解决方案 - Kafka分层存储

Kafka数据主要以流式方式使用尾部读取来进行消费,提供读取的层,一般都是操作系统的Page Cache,而不是穿透到磁盘。而旧的数据一般是为了回溯或者是因为consumer故障后重启后读取的,而这种情况一般不太常见。

在分层存储方法中,Kafka集群配置有两层存储:本地和远程(local and remote)。本地存储层与当前的Kafka相同,使用Kafka Broker上的本地磁盘来存储日志段。而新的远端存储层则使用一些外部存储,例如HDFS或者S3来实现。不同的存储层使用不同的日志过期时间。当开启远程存储时,本地消息的保留时长将会从几天缩短至几小时,而远端存储的消息保留时长则可能会保留更长的时间,例如几周甚至几个月。当本地日志段发生了滚动 (译者:这里所谓的滚动rolled,可以简单理解为某个日志段写满1G了,即数据已经不会再发生变化了),它可能就会被拷贝至远端存储,当然包含日志段相关的索引文件。这样即便是延迟敏感的数据也能获得高效的消费,因为数据都是尾部读取,且数据都会高概率命中page cache。而那些读取历史消息,或者对消息进行回溯的场景,很有可能数据已经不在本地存储了,那么它们将会去远端存储上读取

此解决方案允许在Kafka集群扩容存储时,将不再依赖于内存和CPU,使Kafka成为一个长期存储的解决方案。同时也减少了每个broker上本地存储的数据量,从而减少了集群recovery及rebalance时需要复制的数据量。broker不需要恢复远程存储层中的日志段,也不存在惰性恢复,而是远程存储层直接提供服务。这样,增加消息保留时长就不需要再扩展Kafka集群的broker数量了,同时消息总体的保留时长还可以更长,不用像当前很多集群部署的策略,需要启动一个单独的管道,将数据从Kafka拷贝至外部存储了
Goals

通过将旧数据存储在外部存储(如HDFS或S3)中,实现了将Kafka的存储扩展到了集群之外,不过Kafka的内部的协议不能有太大的变动。对于那么没有启用分层存储功能的现有用户,Kafka各类行为及操作复杂性决不能改变
Non-Goals


  • 分层存储不能取代ETL管道任务。现有的ETL管道继续按原样消费Kafka的数据,尽管Kafka有更长的消息保留时长
  • 二级存储不适用于compact类型的topic。即便是将compact类型的topic的配置项remote.storage.enable设置为true,也不能将其类型由delete改为compact
  • 二级存储不支持JBOD特性
变更

高层设计

1.png

RemoteLogManager (RLM) 是一个新引入的组件:

  • 处理leader变更、topic partition删除等回调事件
  • 可插拔的存储管理器(即RemoteStorageManager)将处理segments的copy、read、delete事件,且其需要维护远端segments日志段的元数据(它需要知道哪些segments存储在了远端)

RemoteLogManager 是一个内部组件,不会向外暴露API
RemoteStorageManager 本身是一个接口,它定义了远端日志段及索引的生命周期。具体细节下文还会说明,我们将提供一个简单的RSM的实现来帮助大家更好的理解它。而诸如HDFS或者S3的实现应该放在他们产品的仓库中,Apache Kafka自身的仓库不会包含其具体的实现。这个设计与Kafka connnector保持一致
译者:其实这里本质上Kafka定义了一套多层存储的规范。突然想起一句话:普通的软件在编码,上流的软件在设计,顶级的软件在定义规范

RemoteLogMetadataManager 本身也是个接口,它同样定义了具有强一致语义的远端元数据的生命周期。它的默认实现是一个kafka系统内部的topic,用户如果需要使用其他远程存储介质来存储元数据的话,需要自己去扩展它
RemoteLogManager (RLM)

RLM为leader及follower启动了很多任务,具体解析可见下文

  • RLM Leader 职责



    • 它会不断地检查非active状态的LogSegments(这些LogSegments中最大的offset需要严格小于LSO,才能进行拷贝),然后将这些LogSegments及索引文件(offset/time/transaction/producer-snapshot)、leader epoch均拷贝至远端存储层
    • 提供从远端存储层查询旧数据的服务(当查询的数据在local log存储中没有时)
    • 即便是local存储已经不足(或存储的日志已经超时 ?这里存疑),也要先将日志段LogSegments拷贝至远端后,再删除



  • RLM Follower 职责



    • 通过访问RemoteLogMetdataManager来获取远端存储的log及index数据
    • 同时,它也会提供从远端存储层查询旧数据的服务


RLM提供了一个本地的有界缓存(可能是LRU淘汰策略)来存储远端的索引文件,这样可避免频繁的访问远端存储。它们存储在log dir目录下的remote-log-index-cache子目录,这些索引可以像local索引一样使用,用户可以通过设置配置项remote.log.index.file.cache.total.size.mb来设定此缓存的上限

在早期的设计中,还包含了通过远端存储的API拉取LogSegments元数据的章节,(译者:这应该是曾经讨论的某次中间版本)它在HDFS接入时,看起来一切运行的很好。依赖远端存储来维护元数据的问题之一是:整个分层存储是需要强一致性的,它不仅影响元数据,还影响Segments日志段数据本身。其次也要考虑远端存储中存储元数据的耗时,在S3中,frequent LIST APIs导致了巨大的开销
译者:主要是讲为什么要将元数据与日志数据分开存储的原因。这段可能读起来有点摸不着头脑,原因是咱们没有参与他们之前的讨论,之前的某个讨论版本是想将日志的元数据信息放入远程存储的,此处不用纠结

因此需要将远端的数据本身,与元数据进行分离,其对应的管理类分别为RemoteStorageManager、RemoteLogMetadataManager
本地及远端offset约束

以下是leader offset相关描述图
2.png

Lx = Local log start offset Lz = Local log end offset Ly = Last stable offset(LSO)
Ry = Remote log end offset Rx = Remote log start offset
Lz >= Ly >= Lx and Ly >= Ry >= Rx

<blockquote>
译者:这里不做赘述,关键一点是remote offset中的最大值,是需要
您需要登录后才可以回帖 登录 | 立即注册