Kudu 架构原理
1、kudu介绍
kudu 定位是 「Fast Analytics on Fast Data」,是一个既支持随机读写、又支持 OLAP 分析的大数据存储引擎。
原数据存储于HDFS或HBase都有优缺点:
-
直接存放于HDFS中,适合离线分析,却不利于记录级别的随机读写。
-
2、kudu原理架构
采用了Master-Slave形式的中心节点架构,管理节点被称作 Master Server,数据节点被称作Tablet Server(可对比理解HBase中的RegionServer角色)。
-
Mater Server:负责集群(TS)管理、元数据管理等功能
-
Tablet Server:负责数据存储,并提供数据读写服务
一个表的数据,被分割成1个或多个Tablet,Tablet被部署在Tablet Server来提供数据读写服务。 Kudu Master在Kudu集群中,发挥如下的一些作用:
-
用来存放一些表的Schema信息,且负责处理建表等请求。
-
跟踪管理集群中的所有的Tablet Server,并且在Tablet Server异常之后协调数据的重部署。
-
存放Tablet到Tablet Server的部署信息。
tablets 在 Kudu 里面被切分成更小的单元 RowSets:
MemRowSets可以对比理解成HBase中的MemStore, 而DiskRowSets可理解成HBase中的HFile。MemRowSets中的数据按照行试图进行存储,数据结构为B-Tree。MemRowSets中的数据被Flush到磁盘之后,形成DiskRowSets。
DiskRowSet中的数据按照Column进行组织,与Parquet类似。这是Kudu可支持一些分析性查询的基础。
一个DiskRowSet包含两部分数据:基础数据(Base Data),以及变更数据(Delta Stores)。更新/删除操作所生成的数据记录,被保存在变更数据部分。
Delta数据部分包含REDO与UNDO两部分:
-
REDO Delta Files包含了Base Data自上一次被Flush/Compaction之后的变更值。REDO Delta Files按照Timestamp顺序排列。
-
UNDO Delta Files包含了Base Data自上一次Flush/Compaction之前的变更值。这样才可以保障基于一个旧Timestamp的查询能够看到一个一致性视图。UNDO按照Timestamp倒序排列。
kudu client 与 服务端交互,先从 Master Server 获取元数据信息,然后去 Tablet Server 读写数据,如下图:
3、读写流程
3.1、写数据
当 Client 请求写数据时,先根据主键从 Mater Server 中获取要访问的目标 Tablets,然后到依次对应的 Tablet 获取数据。因为 KUDU 表存在主键约束,所以需要进行主键是否已经存在的判断,这里就涉及到之前说的索引结构对读写的优化了。一个 Tablet 中存在很多个 RowSets,为了提升性能,我们要尽可能地减少要扫描的 RowSets 数量。首先,我们先通过每个 RowSet 中记录的主键的(最大最小)范围,过滤掉一批不存在目标主键的 RowSets,然后在根据 RowSet 中的布隆过滤器,过滤掉确定不存在目标主键的 RowSets,最后再通过 RowSets 中的 B-树索引,精确定位目标主键是否存在。如果主键已经存在,则报错(主键重复),否则就进行写数据(写 MemRowSet)。
3.2、更新数据
定位到具体位置后,然后将变更写到对应的 delta store 中。
3.3、读数据
先根据要扫描数据的主键范围,定位到目标的 Tablets,然后读取 Tablets 中的 RowSets。在读取每个 RowSet 时,先根据主键过滤要 scan 范围,然后加载范围内的 base data,再找到对应的 delta stores,应用所有变更,最后 union 上 MenRowSet 中的内容,返回数据给 Client。
4、存储设计
列式存储
优势**
-
查询少量列时 IO 少,速度快
-
数据压缩比高
-
便于查询引擎性能优化:延迟物化、直接操作压缩数据、向量化执行
劣势
-
查询列太多时性能下降(KUDU 建议列数不超过 300 )
-
不适合 OLTP 场景
分区
与大多数大数据存储引擎类似,KUDU 对表进行横向分区,KUDU 表会被横向切分存储在多个 tablets 中。不过相比与其他存储引擎,KUDU 提供了更加丰富灵活的数据分区策略。
一般数据分区策略主要有两种,一种是 Range Partitioning,按照字段值范围进行分区,HBase 就采用了这种方式,如下图:
Range Partitioning 的优势是在数据进行批量读的时候,可以把大部分的读变成同一个 tablet 中的顺序读,能够提升数据读取的吞吐量。并且按照范围进行分区,我们可以很方便的进行分区扩展。其劣势是同一个范围内的数据写入都会落在单个 tablet 上,写的压力大,速度慢。
另一种分区策略是 Hash Partitioning,按照字段的 Hash 值进行分区,Cassandra 采用了这个方式,见下图:
与 Range Partitioning 相反,由于是 Hash 分区,数据的写入会被均匀的分散到各个 tablet 中,写入速度快。但是对于顺序读的场景这一策略就不太适用了,因为数据分散,一次顺序读需要将各个 tablet 中的数据分别读取并组合,吞吐量低。并且 Hash 分区无法应对分区扩展的情况。
各种分区策略的优劣对比见下图:
既然各分区策略各有优劣,能否将不同分区策略进行组合,取长补短呢?这也是 KUDU 的思路,KUDU 支持用户对一个表指定一个范围分区规则和多个 Hash 分区规则,如下图:
参考引用:
http://www.nosqlnotes.com/technotes/kudu-design/
https://zhuanlan.zhihu.com/p/26798353