四万字硬刚 Kudu | Kudu 基础原理实践小总结

Kudu 简介

Hadoop 生态系统发展到现在,存储层主要由 HDFS 和 HBase 两个系统把持着,一直没有太大突破。在追求高吞吐的批处理场景下,我们选用 HDFS,在追求低延迟,有随机读写需求的场景下,我们选用 HBase,那么是否存在一种系统,能结合两个系统优点,同时支持高吞吐率和低延迟呢?

有人尝试修改 HBase 内核构造这样的系统,即保留 HBase 的数据模型,而将其底层存储部分改为纯列式存储(目前 HBase 只能算是列簇式存储引擎),但这种修改难度较大。Kudu 的出现解决了这一难题。

Kudu 是 Cloudera 开源的列式存储引擎,具有以下几个特点:

  • C++语言开发,Kudu 的 API 可以使用 Java 和 C++

  • 高效处理类 OLAP 负载

  • 与 MapReduce,Spark 以及 Hadoop 生态系统中其他组件进行友好集成

  • 可与 Cloudera Impala 集成,替代目前 Impala 常用的 HDFS+Parquet 组合

  • 灵活的一致性模型

  • 顺序写和随机写并存的场景下,仍能达到良好的性能

  • 高可用,使用 Raft 协议保证数据高可靠存储

  • 结构化数据模型

Kudu 的出现,有望解决目前 Hadoop 生态系统难以解决的一大类问题,比如:流式实时计算结果的更新。

时间序列相关应用,具体要求有:

  • 查询海量历史数据

  • 查询个体数据,并要求快速返回

  • 预测模型中,周期性更新模型,并根据历史数据快速做出决策

使用场景

  1. 实时数据更新

  2. 时间序列相关的应用(例如 APM),海量历史数据查询(数据顺序扫描),必须非常快地返回关于单个实体的细粒度查询(随机读)。

  3. 实时预测模型的应用(机器学习),支持根据所有历史数据周期地更新模型。

Kudu 基本架构

Kudu 是典型的主从架构。一个 Kudu 集群由主节点即 Master 和若干个从节点即 Tablet Server 组成。Master 负责管理集群的元数据(类似于 HBase Master),Tablet Server 负责数据存储(类似 HBase 的 RegionServer)。在生产环境,一般部署多个 Master 实现高可用(奇数个、典型的是 3 个),Tablet Server 一般也是奇数个。

基础概念:

开发语言:C++

Columnar Data Store(列式数据存储)

Read Efficiency(高效读取)

对于分析查询,允许读取单个列或该列的一部分同时忽略其他列

  • Data Compression(数据压缩)

由于给定的列只包含一种类型的数据,基于模式的压缩比压缩混合数据类型(在基于行的解决案中使用)时更有效几个数量级。结合从列读取数据的效率,压缩允许您在从磁盘读取更少的块时完成查询

  • Table(表)

一张 table 是数据存储在 Kudu 的位置。表具有 schema 和全局有序的 primary key(主键)。table 被分成很多段,也就是称为 tablets。

  • Tablet(段)

一个 tablet 是一张 table 连续的 segment,与其它数据存储引擎或关系型数据库的 partition(分区)相似。给定的 tablet 冗余到多个 tablet 服务器上,并且在任何给定的时间点,其中一个副本被认为是 leader tablet。任何副本都可以对读取进行服务,并且写入时需要在为 tablet 服务的一组 tablet server 之间达成一致性。

一张表分成多个 tablet,分布在不同的 tablet server 中,最大并行化操作 Tablet 在 Kudu 中被切分为更小的单元,叫做 RowSets,RowSets 分为两种 MemRowSets 和 DiskRowSet,MemRowSets 每生成 32M,就溢写到磁盘中,也就是 DiskRowSet

  • Tablet Server

一个 tablet server 存储 tablet 和为 tablet 向 client 提供服务。对于给定的 tablet,一个 tablet server 充当 leader,其他 tablet server 充当该 tablet 的 follower 副本。只有 leader 服务写请求,然而 leader 或 followers 为每个服务提供读请求。leader 使用 Raft Consensus Algorithm 来进行选举 。一个 tablet server 可以服务多个 tablets,并且一个 tablet 可以被多个 tablet servers 服务着。

  • Master

该 master 保持跟踪所有的 tablets,tablet servers,Catalog Table 和其它与集群相关的 metadata。在给定的时间点,只能有一个起作用的 master(也就是 leader)。如果当前的 leader 消失,则选举出一个新的 master,使用 Raft Consensus Algorithm 来进行选举。

master 还协调客户端的 metadata operations(元数据操作)。例如,当创建新表时,客户端内部将请求发送给 master。master 将新表的元数据写入 catalog table,并协调在 tablet server 上创建 tablet 的过程。

所有 master 的数据都存储在一个 tablet 中,可以复制到所有其他候选的 master。tablet server 以设定的间隔向 master 发出心跳(默认值为每秒一次)。master 是以文件的形式存储在磁盘中,所以说,第一次初始化集群。需要设定好

  • Raft Consensus Algorithm

Kudu 使用 Raft consensus algorithm 作为确保常规 tablet 和 master 数据的容错性和一致性的手段。通过 Raft,tablet 的多个副本选举出 leader,它负责接受以及复制到 follower 副本的写入。一旦写入的数据在大多数副本中持久化后,就会向客户确认。给定的一组 N 副本(通常为 3 或 5 个)能够接受最多(N - 1)/2 错误的副本的写入。

  • Catalog Table(目录表)

catalog table 是 Kudu 的 metadata(元数据中)的中心位置。它存储有关 tables 和 tablets 的信息。该 catalog table(目录表)可能不会被直接读取或写入。相反,它只能通过客户端 API 中公开的元数据操作访问。catalog table 存储两类元数据。

  • Tables

table schemas, locations, and states(表结构,位置和状态)

  • Tablets

现有 tablet 的列表,每个 tablet 的副本所在哪些 tablet server,tablet 的当前状态以及开始和结束的 keys(键)。

注意:

  1. 建表的时候要求所有的 tserver 节点都活着

  2. 根据 raft 机制,允许(replication 的副本数-)/ 2 宕掉,集群还会正常运行,否则会报错找不到 ip:7050(7050 是 rpc 的通信端口号),需要注意一个问题,第一次运行的时候要保证集群处于正常状态下,也就是所有的服务都启动,如果运行过程中,允许(replication 的副本数-)/ 2 宕掉

  3. 读操作,只要有一台活着的情况下,就可以运行

上图显示了一个具有三个 master 和多个 tablet server 的 Kudu 集群,每个服务器都支持多个 tablet。它说明了如何使用 Raft 共识来允许 master 和 tablet server 的 leader 和 follow。此外,tablet server 可以成为某些 tablet 的 leader,也可以是其他 tablet follower。leader 以金色显示,而 follower 则显示为蓝色。

测试:7个tablet serverssd硬盘,5分钟manul flush到kudu 1000万数据

总结:

  1. KUDU 分区数必须预先预定。

  2. 在内存中对每个 Tablet 分区维护一个 MemRowSet 来管理最新更新的数据,默认是 1G 刷新一次或者是 2 分钟。后 Flush 到磁盘上形成 DiskRowSet,多个 DiskRowSet 在适当的时候进行归并处理。

  3. 和 HBase 采用的 LSM(LogStructured Merge,很难对数据进行特殊编码,所以处理效率不高)方案不同的是,Kudu 对同一行的数据更新记录的合并工作,不是在查询的时候发生的(HBase 会将多条更新记录先后 Flush 到不同的 Storefile 中,所以读取时需要扫描多个文件,比较 rowkey,比较版本等,然后进行更新操作),而是在更新的时候进行,在 Kudu 中一行数据只会存在于一个 DiskRowSet 中,避免读操作时的比较合并工作。那 Kudu 是怎么做到的呢?对于列式存储的数据文件,要原地变更一行数据是很困难的,所以在 Kudu 中,对于 Flush 到磁盘上的 DiskRowSet(DRS)数据,实际上是分两种形式存在的,一种是 Base 的数据,按列式存储格式存在,一旦生成,就不再修改,另一种是 Delta 文件,存储 Base 数据中有变更的数据,一个 Base 文件可以对应多个 Delta 文件,这种方式意味着,插入数据时相比 HBase,需要额外走一次检索流程来判定对应主键的数据是否已经存在。因此,Kudu 是牺牲了写性能来换取读取性能的提升。

  4. 更新、删除操作需要记录到特殊的数据结构里,保存在内存中的 DeltaMemStore 或磁盘上的 DeltaFIle 里面。DeltaMemStore 是 B-Tree 实现的,因此速度快,而且可修改。磁盘上的 DeltaFIle 是二进制的列式的块,和 base 数据一样都是不可修改的。因此当数据频繁删改的时候,磁盘上会有大量的 DeltaFiles 文件,Kudu 借鉴了 Hbase 的方式,会定期对这些文件进行合并。

  1. 既然存在 Delta 数据,也就意味着数据查询时需要同时检索 Base 文件和 Delta 文件,这看起来和 HBase 的方案似乎又走到一起去了,不同的地方在于,Kudu 的 Delta 文件与 Base 文件不同,不是按 Key 排序的,而是按被更新的行在 Base 文件中的位移来检索的,号称这样做,在定位 Delta 内容的时候,不需要进行字符串比较工作,因此能大大加快定位速度,但是无论如何,Delta 文件的存在对检索速度的影响巨大。因此 Delta 文件的数量会需要控制,需要及时的和 Base 数据进行合并。由于 Base 文件是列式存储的,所以 Delta 文件合并时,可以有选择性的进行,比如只把变化频繁的列进行合并,变化很少的列保留在 Delta 文件中暂不合并,这样做也能减少不必要的 IO 开销。

      2.除了 Delta 文件合并,DRS 自身也会需要合并,为了保障检索延迟的可预测性(这一点是 HBase 的痛点之一,比如分区发生 Major Compaction 时,读写性能会受到很大影响),Kudu 的 compaction 策略和 HBase 相比,有很大不同,kudu 的 DRS 数据文件的 compaction,本质上不是为了减少文件数量,实际上 Kudu DRS 默认是以 32MB 为单位进行拆分的,DRS 的 compaction 并不减少文件数量,而是对内容进行排序重组,减少不同 DRS 之间 key 的 overlap(重复),进而在检索的时候减少需要参与检索的 DRS 的数量。

原理

table 与 schema

kudu 设计是面向结构化存储,因此 kudu 需要用户在建表时定义它的 schema 信息,这些 schema 信息包含:列定义(含类型),Primary Key 定义(用户指定的若干个列的有序组合)数据的唯一性,依赖于用户所提供的 Primary Key 中的 Column 组合的值的唯一性。Kudu 提供了 Alter 命令来增删列,但位于 Primary Key 中的列是不允许删除的。

从用户角度来看,kudu 是一种存储结构化数据表的存储系统,一个 kudu 集群中可以定义任意数量 table,每个 table 都需要定义好 schema,每个 table 的列数是确定的,每一列都需要名字和类型,表中可以把一列或者多列定义为主键,kudu 更像关系型数据库,但是不支持二级索引。

Kudu 存储模型

Kudu 的底层数据文件的存储,未采用 HDFS 这样的较高抽象层次的分布式文件系统,而是自行开发了一套可基于 Table/Tablet/Replica 视图级别的底层存储系统主要是

1.快速的列式查询

2.快速的随机更新

3.更为稳定的查询性能保障

 

一张 table 会分成若干个 tablet,每个 tablet 包括 MetaData 元信息及若干个 RowSet。RowSet 包含一个 MemRowSet 及若干个 DiskRowSet,DiskRowSet 中包含一个 BloomFile、AdhocIndex、BaseData、DeltaMem 及若干个 RedoFile 和 UndoFile( UndoFile 一般情况下只有一个 )

RowSet 组成:

MemRowSet

用于新数据insert及已在MemRowSet中的数据的更新,一个MemRowSet写满后会将数据刷到磁盘形成若干个DiskRowSet。默认是1G或者或者120S

DiskRowSet

用于老数据的变更,后台定期对DiskRowSet做compaction,以删除没用的数据及合并历史数据,减少查询过程中的IO开销。

BloomFile

根据一个DiskRowSet中的key生成一个bloom filter,用于快速模糊定位某个key是否在DiskRowSet中。

AdhocIndex

是主键的索引,用于定位key在DiskRowSet中的具体哪个偏移位置

BaseData

是MemRowSet flush下来的数据,按列存储,按主键有序。

UndoFile

是基于BaseData之前时间的历史数据,通过在BaseData上apply UndoFile中的记录,可以获得历史数据。

RedoFile

是基于BaseData之后时间的变更记录,通过在BaseData上apply RedoFile中的记录,可获得较新的数据。

DeltaMem

用于DiskRowSet中数据的变更,先写到内存中,写满后flush到磁盘形成RedoFile

MemRowSets 与 DiskRowSets 的区别:

Kudu

 

HBase

 

对比可知,MemRowSets 中数据 Flush 磁盘后,形成 DiskRowSets,DiskRowSets 中数据 32M 大小为单位,按序划分一个个 DiskRowSet,DiskRowSet 中的数据按照 Column 进行组织,类比 Parquet,这是 Kudu 可支持一些分析性查询的基础,每一个 Column 存储在一个相邻的数据区域,而这个数据区域进一步细分为一个个小 Page 单元,与 hbase 的 File 中 Block 类似,对于每个 Column Page 可以采用一些 Encoding 算法,以及通用的 Compression 算法.

对于数据的更新和删除,Kudu 与 hbase 蕾西,通过增加一条新记录来描述数据更新和删除,虽然对于 DiskRowSet 不可修改,Kudu 将 DiskRowSet 划分两个部分,BaseData,DeltaStores,BaseData 负责存储基础数据,DeltaStore 负责存储 BaseData 中变更数据

 

数据从 MemRowSet 刷到磁盘后就形成了一份 DiskRowSet(只包含 base data),每份 DiskRowSet 在内存中都会有一个对应的 DeltaMemStore,负责记录此 DiskRowSet 后续的数据变更映射到每个 row_offset 对应的数据变更。

DeltaMemStore 数据增长到一定程度后转化成二进制文件存储到磁盘,形成一个 DeltaFile,随着 base data 对应数据的不断变更,DeltaFile 逐渐增长。下图是 DeltaFile 生成过程的示意图(更新、删除)。DeltaMemStore 内部维护一个 B-树索引.

 

Delta 数据部分包含 REDO 与 UNDO 两部分:这里的 REDO 与 UNDO 与关系型数据库中的 REDO 与 UNDO 日志类似(在关系型数据库中,REDO 日志记录了更新后的数据,可以用来恢复尚未写入 DataFile 的已成功事务更新的数据。而 UNDO 日志用来记录事务更新之前的数据,可以用来在事务失败时进行回滚),但也存在一些细节上的差异:

  • REDO Delta Files 包含了 Base Data 自上一次被 Flush/Compaction 之后的变更值。REDO Delta Files 按照 Timestamp 顺序排列。

  • UNDO Delta Files 包含了 Base Data 自上一次 Flush/Compaction 之前的变更值。这样才可以保障基于一个旧 Timestamp 的查询能够看到一个一致性视图。UNDO 按照 Timestamp 倒序排列。

tablet 发现过程

Kudu 客户端无论在执行写入还是读操作,先从 master 获取 tablet 位置信息,这个过程为 tablet 发现。当创建 Kudu 客户端时,其会从主服务器上获取 tablet 位置信息,然后直接与服务于该 tablet 的服务器进行交谈,为了优化读取和写入路径,客户顿将保留该信息的本地缓存,防止每一个请求都要查询 tablet 位置信息,随着时间推移,并且当写入被发送不再是 tablet 的 leader 服务器时,被拒绝,然后客户顿通过查询主服务器发现新领导者位置来更新缓存。

Kudu 目标:

按照 cloudera 的想法,kudu 的出现是为了解决,hbase,parquet 不能兼顾分析和更新的需求,所以需要一个新的存储引擎可以同时支持高吞吐的分析应用以及少量更新的应用。cloudera 的设计目标是:

  • Strong performance for both scan and random access to help customers simplify complex hybrid architectures

在扫描和随机访问两种场景下都有很强的性能,帮助客户简化混合架构。

  • High CPU efficiency in order to maximize the return on investment that our customers are making in modern processors

高 cpu 利用率

  • High IO efficiency in order to leverage modern persistent storage

高 io 效率充分利用现代存储

  • The ability to update data in place, to avoid extraneous

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值