写点什么

大数据 -145 Apache Kudu 架构与实战:RowSet、分区与 Raft 全面解析

作者:武子康
  • 2025-11-07
    山东
  • 本文字数:3832 字

    阅读完需:约 13 分钟

大数据-145 Apache Kudu 架构与实战:RowSet、分区与 Raft 全面解析

TL;DR

  • 场景:在实时/近实时数仓中,需要低延迟写入 + 列式分析并行读。

  • 结论:Kudu 以 RowSet 设计、Range/Hash 复合分区与 Raft 副本,兼顾吞吐与一致性。

  • 产出:对比与架构要点梳理、常见故障速查与修复路径。



Kudu 对比

Kudu 和 HBase、HDFS 之间的对比:


Kudu 的架构

与 HDFS 和 HBase 相似,Kudu 使用单个 Master 节点,用来管理集群的元数据,并且使用任意数量的 TabletServer 节点用来存储实际数据,可以部署多个 Master 节点来提高容错性。

Master


  • 高可用与容错机制:Kudu 的高可用和容错能力基于其副本管理机制。每个 Tablet 都有多个副本,副本之间通过 Raft 协议进行同步:

  • Leader 选举:如果某个 Tablet 的 Leader 副本发生故障,系统会自动选举一个新的 Leader 来接管读写操作,确保服务不间断。副本恢复:当某个 Tablet Server 节点发生故障,Master 节点会将失效的副本重新分配到其他健康的 Tablet Server 上,并同步数据。

Master

Kudu 的 Master 节点负责整个集群的元数据管理和服务协调,它承担着如下的功能:


  • 作为 Catalog Manager,Master 节点管理集群中所有 Tablet 和 Schema 及一些其他的元数据。

  • 作为 Cluster Coordinate,Master 节点追踪着所有 Server 节点是否存活,并且当 Server 节点挂掉后协调数据重新分布。

  • 作为 TabletDirectory,Master 跟踪每个 Tablet 的位置。

Catalog Manager

Kudu 的 Master 节点会持有一个单 Tablet 的 Table-CatalogTable,但是用户是不能直接访问的,Master 将内部的 Catalog 信息写入 Tablet,并且将整个 Catalog 的信息缓存到内存中。随着现在商用服务器上的内存越来越大,并且元数据信息占用空间其实并不大,所以 Master 不容易存在性能瓶颈,CatalogTable 保存了所有 Tablet 的 Schema 的版本与 Table 的状态(创建、运行、删除等等)。

Cluster Coordination

Kudu 集群中的每个 Tablet Server 都需要配置 Master 的主机名列表,在集群启动时,TabletServer 会向 Master 注册,并发送所有 Tablet 信息。TabletServer 第一次向 Master 发送信息时会发送所有 Tablet 的全量信息,后续每次发送则只会发送增量信息,仅包含新创建、删除或修改 Tablet 的信息,作为 ClusterCoordination,Master 只是集群状态的观察者。对于 TabletServer 中 Tablet 的副本位置、Raft 配置和 Schema 版本等信息的控制和修改由 TabletServer 自身完成。Master 只要下达命令,TabletServer 执行成功后会自动上报处理的结果。

Tablet Directory

因为 Master 上缓存了集群的元数据,所以 Client 读写数据的时候,肯定是要通过 Master 才能获取到 Tablet 的位置灯信息,但是如果每次读写都要通过 Master 节点的话,那 Master 就会成为这个集群的瓶颈,所以 Client 会在本地缓存一份它需要访问的 Tablet 的位置信息,这样就不用每次都从 Master 读取了。因为 Tablet 的信息也可能会发生改变(比如掉线或者宕机),所以当 Tablet 的值发生变化的时候,Client 会收到通知,然后再从 Master 重新拉取一份新的。

Table

在数据存储方面,Kudu 选择完全由自己实现,而没有借助于已有的开源方案,Tablet 存储主要想实现的目标为:


  • 快速的列扫描

  • 低延迟的随机读写

  • 一致性的性能

RowSets

在 Apache Kudu 的存储架构中,Tablet 被进一步细分为更小的存储单元,称为 RowSets。这些 RowSets 根据存储介质的不同分为两种类型:


  1. MemRowSets:

  2. 完全驻留在内存中的数据结构

  3. 采用基于 B 树的实现方式

  4. 主要负责存储最新插入的数据

  5. 使用高效的并发控制机制支持高吞吐量写入

  6. DiskRowSets:

  7. 混合使用内存和磁盘的存储结构

  8. 由 MemRowSet 经过 Flush 操作转化而来

  9. 采用列式存储格式(CFile)保存在磁盘上

  10. 包含 Bloom Filter 和主键索引等辅助结构


存储管理机制具有以下特点:


  • 数据唯一性保证:任何未被逻辑删除的行数据都严格只存在于一个 RowSet 中

  • MemRowSet 生命周期:

  • 每个 Tablet 始终只维护一个活跃的 MemRowSet

  • 后台的 Flush 线程会按照配置的时间间隔(默认 1 秒)或大小阈值触发数据持久化

  • Flush 完成后,系统会原子性地创建新的空 MemRowSet 继续接收新数据


Flush 操作的关键特性:


  • 非阻塞式设计:采用 Copy-on-Write 技术确保 Flush 过程中不影响客户端读写

  • 并行处理:一个大 MemRowSet 会被拆分成多个 DiskRowSet 以提高并行度

  • 数据转换:原始行数据会被转换为列式存储格式,并生成相应的索引结构


这种架构设计使得 Kudu 能够:


  • 实现高达每秒数万行的写入吞吐

  • 保持毫秒级的查询延迟

  • 支持在线的 Schema 变更

  • 提供持续稳定的性能表现

MemRowSets

MemRowSets 是一个可以被并发访问并进行优化的 B-Tree,主要是基于 MassTree 来设计的,但存在几点不同:


  • Kudu 并不支持直接删除操作,由于使用了 MVCC,所以在 Kudu 中删除操作其实是插入一条标志着删除的数据,这样就可以推迟删除操作。

  • 类似删除操作,Kudu 也不支持原地更新操作

  • 将 Tree 的 Leaf 链接起来,就像 B+Tree,这一步关键的操作可以明显的提升 Scan 操作的性能。

  • 没有实现字典树(trie 树),而是只用了单个 Tree,因为 Kudu 并不适用于极高的随机读写的场景。与 Kudu 中其他模块中的数据结构不同,MemRowSet 中的数据使用行存储,因为数据都在内存中,所以性能也是可以接受的,而且 Kudu 在 MemRowSet 中的数据结构进行了一定的优化。

DiskRowSet

当 MemRowSet 被 Flush 到磁盘后,就变成了 DiskRowSet,当 MemRowSet 被 Flush 硬盘的时候,每 32M 就会形成一个新的 DiskRowSet,这主要是为了保证每个 DiskRowSet 不会太大,便于后续的增量 Compaction 操作。Kudu 通过将数据氛围 BaseData 和 DeltaData,来实现数据的更新操作。Kudu 会将数据按列存储,数据被切分多个 Page,并使用 B-Tree 进行索引。除了用户写入数据,Kudu 还会将主键索引存入一个列中,并且提供布隆过滤器来进行高效的查找。

Compaction

为了提供查询性能,Kudu 会定期进行 Compaction 操作,合并 DeltaData 与 BaseData,对标记了删除的数据进行删除,并且会合并一些 DiskRowSet。

分区

选择分区策略需要理解数据模型和标的预期工作负载:


  • 对于写量大的工作负载,重要的是要设计分区,使写分散在各个 Tablet 上,以避免单个 Tablet 超载。

  • 对于涉及许多短扫描的工作负载(其中联系远程服务器的开销占主导地位),如果扫描的所有数据都位于同一块 Tablet 上,则可以提高性能。


理解这些基本的权衡是设计有效分区模式的核心。没有默认分在创建表时,Kudu 不提供默认的分区策略。建议预期具有繁重读写工作负载的新表至少拥有与 Tablet 服务器相同的 Tablet。和需要分布式存储系统一样,Kudu 的 Tablet 是水平分区的,BigTable 只提供了 Range 分区,Cassandra 只提供 Hash 分区,而 Kudu 同时提供了这两种分区方式,使分区较为灵活。当用户创建了一个 Table 时,可以同时指定 Table 的 PartitionSchema,PartitionSchema 会将 primary key 映射为 Partition key。一个 PartitionSchema 包括 0 到多个 Hash-Partitioning 规则和一个 Range-Partitioning 规则,通过灵活的组合各种 Partition 规则,用户可以创造适用于自己业务场景分区方式。


Kudu 支持两种分区策略:范围分区(Range Partitioning) 和 哈希分区(Hash Partitioning)。

范围分区

范围分区基于主键范围划分 Tablet。用户可以通过设置分区键的范围,手动或自动地将数据分布到不同的 Tablet 上。例如,按时间戳划分数据表可以将不同时间段的数据分配到不同的分区。

哈希分区

哈希分区通过对主键进行哈希运算,将数据均匀分布到不同的 Tablet 中。哈希分区适用于那些查询中没有明显范围条件的场景,如主键查询或随机访问场景。

查询与写入流程

写入流程

  • 客户端将数据写入 Tablet Server 时,首先被写入到 MemRowSet 中。

  • MemRowSet 达到一定容量后,数据会通过后台线程刷入磁盘(DiskRowSet)。

  • 刷盘过程中,Tablet Server 会将数据同步到其他副本,以保证数据的一致性。

查询流程

  • 客户端查询数据时,查询请求首先发送到 Master 节点,Master 节点根据请求的主键范围定位到相应的 Tablet Server。

  • Tablet Server 从磁盘中的 DiskRowSet 中读取对应列的数据,返回给客户端。

  • 如果查询只涉及部分列,Kudu 只读取涉及的列数据,利用列式存储的优势提高查询效率。

Tablet 和 Raft 共识协议

Kudu 的数据被切分为多个 Tablet,每个 Tablet 是表的一部分,类似于水平分片(Horizontal Partitioning)。每个 Tablet 通过主键范围进行划分,确保数据均匀分布在不同的 Tablet Server 上。


为了保证数据的可靠性和一致性,Kudu 使用了 Raft 共识协议 来进行副本管理。每个 Tablet 通常有多个副本(默认是三个),这些副本通过

Raft 协议保证

  • 数据一致性:在任意时刻,只有一个副本可以作为主副本(Leader),其他副本为跟随者(Follower)。所有的写入操作必须先写入 Leader,然后通过 Raft 协议同步到 Follower,确保数据一致性。

  • 故障容错:如果 Leader 副本发生故障,系统会自动通过 Raft 协议选举一个新的 Leader,保证系统的高可用性。

错误速查

其他系列

🚀 AI 篇持续更新中(长期更新)

AI 炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用 AI 工具指南!AI-调查研究-108-具身智能 机器人模型训练全流程详解:从预训练到强化学习与人类反馈🔗 AI模块直达链接

💻 Java 篇持续更新中(长期更新)

Java-154 深入浅出 MongoDB 用 Java 访问 MongoDB 数据库 从环境搭建到 CRUD 完整示例 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务正在更新!深入浅出助你打牢基础!🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300 篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解🔗 大数据模块直达链接

发布于: 13 小时前阅读数: 7
用户头像

武子康

关注

永远好奇 无限进步 2019-04-14 加入

Hi, I'm Zikang,好奇心驱动的探索者 | INTJ / INFJ 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-145 Apache Kudu 架构与实战:RowSet、分区与 Raft 全面解析_Java_武子康_InfoQ写作社区