1 Kudu的设计初衷
在介绍Kudu是什么之前,还是先简单的说一下现存系统针对结构化数据存储与查询的一些痛点问题,结构化数据的存储,通常包含如下两种方式:
- 静态数据通常以Parquet/Carbon/Avro形式直接存放在HDFS中,对于分析场景,这种存储通常是更加适合的。但无论以哪种方式存在于HDFS中,都难以支持单条记录级别的更新,随机读取也并不高效。
- 可变数据的存储通常选择HBase或者Cassandra,因为它们能够支持记录级别的高效随机读写。但这种存储却并不适合离线分析场景,因为它们在大批量数据获取时的性能较差(针对HBase而言,有两方面的主要原因:一是HFile本身的结构定义,它是按行组织数据的,这种格式针对大多数的分析场景,都会带来较大的IO消耗,因为可能会读取很多不必要的数据,相对而言Parquet格式针对分析场景就做了很多优化。 二是由于HBase本身的LSM-Tree架构决定的,HBase的读取路径中,不仅要考虑内存中的数据,同时要考虑HDFS中的一个或多个HFile,较之于直接从HDFS中读取文件而言,这种读取路径是过长的)。
可以看出,如上两种存储方式,都存在明显的优缺点:
- 直接存放于HDFS中,适合离线分析,却不利于记录级别的随机读写。
- 直接将数据存放于HBase/Cassandra中,适合记录级别的随机读写,对离线分析却不友好。
但在很多实际业务场景中,两种场景时常是并存的。我们的通常做法有如下几种:
- 数据存放于HBase中,对于分析任务,基于Spark/Hive On HBase进行,性能较差。
- 对于分析性能要求较高的,可以将数据在HDFS/Hive中多冗余存放一份,或者,将HBase中的数据定期的导出成Parquet/Carbon格式的数据。 明显这种方案对业务应用提出了较高的要求,而且容易导致在线数据与离线数据之间的一致性问题。
Kudu的设计,就是试图在OLAP与OLTP之间,寻求一个最佳的结合点,从而在一个系统的一份数据中,既能支持OLTP型实时读写能力又能支持OLAP型分析。另外一个初衷,在Cloudera发布的《Kudu: New Apache Hadoop Storage for Fast Analytics on Fast Data》一文中有提及,Kudu作为一个新的分布式存储系统期望有效提升CPU的使用率,而低CPU使用率恰是HBase/Cassandra等系统的最大问题。下面的章节中,主要从论文所揭示的内容来解读Kudu的设计原理。
2 Kudu的原理介绍
Kudu自身的架构,部分借鉴了Bigtable/HBase/Spanner的设计思想。论文的作者列表中,有几位是HBase社区的Committer/PBC成员,因此,在论文中也能很深刻的感受到HBase对Kudu设计的一些影响,因此,在本文的多个地方都有谈及Kudu与HBase在设计上的异同。
2.1 表与Schema
Kudu设计是面向结构化存储的,因此,Kudu的表,需要用户在建表时定义它的Schema信息,这些Schema信息包含:列定义(含类型),Primary Key定义(用户指定的若干个列的有序组合)。数据的唯一性,依赖于用户所提供的Primary Key中的Column组合的值的唯一性。 Kudu提供了Alter命令来增删列,但位于Primary Key中的列是不允许删除的。
Kudu当前并不支持二级索引。
2.2 API
Kudu提供了Java/C++两种语言的API(尽管也提供了Python API,但尚处于Experimental阶段)。通过这些API,可以进行如下一些操作: