kudu从0到1

背景:

在KUDU之前,大数据主要以两种方式存储:

  • 静态数据:以HDFS引擎作为存储引擎,适用于高吞吐量的离线大数据分析场景。这类存储的局限性是数据无法进行随机的读写。

  • 动态数据:以HBase、Cassandra作为存储引擎,适用于大数据随机读写场景。这类存储的局限性是批量读取吞吐量远不如HDFS,不适用于批量数据分析的场景。

从上面分析可知,这两种数据再存储方式上完全不同,进而导致使用场景完全不同,但在真实场景中,边界可能没有那么清晰,面对既需要随机读写、又需要批量分析的大数据场景。该如何选择呢?一个常见的方案是:

 

从上图可以看出,KUDU是一个这种的产品,在HDFS和HBase这两个偏科生中平衡了随机读写和批量分析的性能。从KUDU的诞生可以说明一个问题:底层的技术发展很多时候都是上层业务推动的,脱离业务的技术很可能是“空中楼阁”

 

数据模型

KUDU的数据模型与传统的关系型数据库类似,一个KUDU集群由多个表组成,每个表由多个字段组成,一个表必须指定一个由若干个(>=1)字段组成的主键

 

KUDU表中每个字段是强类型的,而不是HBase那样所有字段都认为是bytes。这样做的好处是可以对不同类型的数据进行不同的编码,节省空间。同时,因为KUDU的使用场景是OLAP分析,有一个数据类型对下游的分析工具也更加优化。

 

核心API

KUDU的对外API主要分为写跟读两部分。其中写包括:Insert、Update、Delete,所有写操作都必须制定主键;读KUDU对外只体用了Scan操作,Scan时用户可以指定一个或多个过滤器,用于过滤数据。

(数据库中有read和scan操作。read:从数据库中读一条记录。 scan:在数据库中执行范围查询,结果返回一个记录集。)

 

一致性模型

跟大多数关系型数据库一样,KUDU也是通过MVCC(Multi-Version Concurrency Control)来实现内部的事务隔离。

 

整体架构

KUDU中存在两个角色

Master Server: 负责集群管理、元数据管理等功能

Tablet Server: 负责数据存储,并提供数据读写服务。

为了实现分区容错性,跟其他大数据产品一样,对于每个角色,在KUDU中都可以设置特定数据(3-5)的副本。各副本间通过Raft协议保证数据一致性。

 

KUDU Client与服务端交互时,先从Master Server获取元数据信息,然后去Tablet Server读写数据:

 

 

存储实现:

与其他大数据存储引擎类似,KUDU 的存储也是通过 LSM 树(Log-Structured Merge Tree)来实现的。KUDU 的最小存储单元是 RowSets,KUDU 中存在两种 RowSets:MemRowSetsDiskRowSets,数据先写内存中的 MemRowSetMemRowSet 满了后刷到磁盘成为一个 DiskRowSetDiskRowSet 一经写入,就无法修改了。见下图:

 

 

 

  • 如何应对数据变更?

  • 如何优化读写性能以满足 OLAP 场景?

     

    应对数据变更

    首先上面我们讲了,DiskRowSet 是不可修改了,那么 KUDU 要如何应对数据的更新呢?在 KUDU 中,把 DiskRowSet 分为了两部分:*base data**delta stores*。base data 负责存储基础数据,delta stores负责存储 base data 中的变更数据。整个数据更新方案如下:

  •  

    如上图所示,数据从MeMRowSet刷到磁盘后就形成了一份DiskRowSet(只包含base data),每份DiskRowSet在内存中都会有一个对应的DeltaMemStore,负责记录此DiskRowSet后续的数据变更(更新、删除)。DeltaMemStore数据增长到一定程度后转化成为二进制文件存储到磁盘中,形成一个DeltaFile,随着base data对应数据的不断变更,DeltaFile逐渐增长。

     

    优化读写性能

    首先我们从KUDU的DiskRowSet数据结构上分析:

  •  

  • 从上图可知,在具体的数据(列数据、变更记录)上,KUDU都做了B-树索引,以提高随机读写的性能。

    • 主键范围索引:记录本DiskRowSet中主键的范围,用于粗粒度过滤一些主键范围。

    • 布隆过滤器:通过主键的布隆过滤器来实现不存在数据的过滤

    • 主键索引:要精确定位一个主键是否存在,以及具体在DiskRowSet中的位置(即:row_offset),通过以B-树为数据结构的主键索引来快速查找。

    随着时间的推移,KUDU中的小文件会越来越多,主要包括各个DiskRowSet中的base data, 还有每个base data对应的若干份DeltaFile。小文件的增多会影响KUDU的性能,特别是DeltaFile中还有很多重复的数据。为了提高性能,KUDU会进行定期Compaction,compaction主要包括两部分:

    • DeltaFile compaction: 过多的DeltaFile影响读性能,定期将DeltaFile合并回base data可以提升性能。

    • DiskRowSet compaction: 除了DeltaFile,定期将DiskRowSet合并也能提升性能,一个原因是合并时我们可以将被删除的数据彻底的删除,而且可以减少同样key范围内数据的文件数,提升索引的效率。

    当用户的查询存在列的过滤条件时,KUDU还可以在查询时进行 延迟物化来提升性能,举例说明:

  •  

    用户的SQL是这样的:

    select * from tb where sex=‘男’ and age >20

    KUDU中数据查询过程是这样的:

    1、扫描sex列,过滤出要查询的行[1,3]

    2、扫码age列,过滤出要查询的行[3,4]

    3、过滤条件相交,得到3

    4、真正读取id=3行所对应的列信息,组装

    数据写过程

  •  

  • 如上图,当 Client 请求写数据时,先根据主键从 Mater Server 中获取要访问的目标 Tablets,然后到依次对应的 Tablet 获取数据。因为 KUDU 表存在主键约束,所以需要进行主键是否已经存在的判断,这里就涉及到之前说的索引结构对读写的优化了。一个 Tablet 中存在很多个 RowSets,为了提升性能,我们要尽可能地减少要扫描的 RowSets 数量。首先,我们先通过每个 RowSet 中记录的主键的(最大最小)范围,过滤掉一批不存在目标主键的 RowSets,然后在根据 RowSet 中的布隆过滤器,过滤掉确定不存在目标主键的 RowSets,最后再通过 RowSets 中的 B-树索引,精确定位目标主键是否存在。如果主键已经存在,则报错(主键重复),否则就进行写数据(写 MemRowSet)。

    数据更新过程

     

     

  •  

  • 数据更新的核心是定位到待更新数据的位置,这块与写入的时候类似,就不展开了,等定位到具体位置后,然后将变更写到对应的 delta store 中。

     

    数据读过程

  • 如上图, 数据读取过程大致如下:先根据要扫描数据的主键范围,定位到目标的Tablets,然后读取Tablets中的RowSets。在读取每个RowSet时,先根据主键过滤要scan范围,然后加载范围内的base data,再找到对应的delta stores, 应用所有变更,最后union上MemRowSet中的内容,返回数据给Client。

  •  

    应用案例

    在使用KUDU前,小米的架构是这样的:

  •  

  •  

    一部分源系统数据是通过Scribe(日志聚合系统)吧数据写到HDFS,另一部分源系统数据直接写入HBase。然后通过Hive/MR/Spark作业把两部分数据合并,给离线数仓和OLAP分析。

    在使用KUDU后,架构简化成了:

  •  

    从上图我们可以看到,所有的数据存储都集中到KUDU一个上,减少了整体的架构复杂度,同时,也大大提升了实时性。

     

    参考:

    https://kudu.apache.org/

    https://www.jianshu.com/p/93c602b637a4

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值