En 400-6655-581
5
返回列表
> 资源中心 > 技术干货 | 说说KUDU的小秘密

技术干货 | 说说KUDU的小秘密

2020-02-25浏览次数:1241

上一篇文章讨论了HDFS的架构,特点以及存储规划。本篇文章将谈一下Hadoop存储家族的二当家KUDU。我们之前也谈到KUDU有和HDFS一样的水平扩展能力以及近似HBase的高效读写能力,那么会为什么会这样呢,本文中将给出解答。本文将会从KUDU的架构和内部机制,KUDU数据存储方式,KUDU与HDFS和HBase的对比几方面进行讨论。


KUDU的架构和内部机制




KUDU是一个分布式主从架构的存储系统,这意味者它有Master-Slave的架构,不过实际上,它的Slave组件叫做Tablet Server,存储着KUDU中的数据。KUDU的架构图如下:



KUDU整体是高可用的,无论是Master还是Tablet Server都有多台,它们内部采用Raft选举机制来保障谁是Leader,谁是Follower。


对于KUDU Master来说,它主要存储Catalog Table, Tablet Server以及Tablets的元数据信息。Catalog Table存储KUDU中Table的Metadata信息。KUDU Master使用采用Raft机制,为保证选举的成功性,通常Master需要为奇数个,一般是3个,在集群规模比较大时可设置为5个。


对于Tablet Server, 它主要存储Tablets以及向外部Client提供服务。


Tablet的不同副本会存储在不同的Tablet Server上,它们也通过Raft机制保障谁是Leader,谁是Follower。对于一个特定的Tablet, 只有Leader可以被写入,而Follower只能被读取。这样大大提升了读的效率。然而当数据写入过大时,如果有Leader Tablet所在的Tablet Server宕机,那将会造成大量的写失败,而在Raft机制中,Leader只允许提交当前时间片的数据,因为当新的Leader选举产生后,之前写失败的数据也不会再次写入,只能继续写当前时间片以后的新数据。这也是为什么Tablet Server节点宕机后,有可能造成数据一致性的问题。


KUDU数据存储方式




那么对于一个特定的数据表, KUDU里是怎么存储的呢?参见下图:




对于一个表,KUDU中会将其若干个Tablet, 每个Tablet又包含Metadata以及RowSet。其中Metadata存放Tablets的元数据信息,RowSet存储具体的数据。


RowSet是把Tablet切片成更小的单元。RowSet分为两种,一种在内存里,叫MemRowSet,一种flush落地到磁盘上,叫DiskRowSet。


这两种RowSet有些区别,首先,一个表只有一个MemRowSet,但是会有很多个DiskRowSet。当MemRowSet达到指定大小时(一般是32M),才会刷新到磁盘上形成DiskRowSet。因为32M的大小并不大,所以不会造成HBase中Major Compaction的性能问题。

另外,MemRowSet中数据是行式存储,实现形式是B+tree,它的存储样式为:



而DiskRowSet为列式存储,它的存储样式为:



对于每一个DiskRowSet,它包含六个部分:BloomFile,AdhocIndex,UndoFile,RedoFile,BaseData,DeltaMem。


BloomFile是根据主键生成的一个Bloom Filter,用于模糊定位数据是否在DiskRowSet存在;

AdhocIndex则是主键的索引,用于定位主键在DiskRowSet的偏移量;

BaseData是上次Flush到磁盘的数据;

RedoFile是上次Flush到磁盘以后发生的数据变化;

UndoFile是上次Flush到磁盘之前的数据;

DeltaMem则是RedoFile生成之前的在内存和磁盘交互时的存储格式。


DiskRowSet在磁盘上具体存储为一个个的CFile文件, 需要注意的是,DiskRowSet这六部分并不是存在一个CFile中,而是独立在多个CFile中的,每一部分都会形成单独的CFile。


但实际上,无论是在KUDU Master还是KUDU Tablet Server上,我们见到实际存储的都是都是.metadata文件和.data文件,像这种:



CFile文件在哪?和.data还有.metadata文件有什么关系?他们的关系像这样:



.metadata文件记录的是一个DiskRowSet中几部分对应CFile的位置以及映射关系,而大量的CFile又被Container合并写到一个.data文件中,因此对于一个DiskRowSet的正常读写,.metadata文件和.data文件缺一不可。


KUDU与HDFS以及HBase的对比




对于HDFS来说,无论读还是写,实际操作的是底层一个个数据文件,由于设计之初并不对文件中的内容做要求,因此只支持整个数据文件的新增,删除或者向其中追加新的数据。而无法实现单条数据的更新和删除,因为HDFS根本没有办法定位这条数据在哪里,而即便定位了,也需要把整个数据文件删掉再重建才能把操作完成,这个代价太过昂贵。而如果是离线分析,HDFS倒是很有优势,虽然它不知道某条数据在哪里,但是它知道分析用到的整张表在哪里存储并进行快速定位。


对于HBase来说,它底层仍然依赖于HDFS的文件块存储,但是它需要实现快速数据快速插入,更新和删除。那它怎么实现呢?和KUDU一样,HBase借用了内存来进行处理,在内存中有MemStore,所有写入HBase的数据都变成一个Key-Value的键值对,当然这个Key不只是一个字段,而是Rowkey+Column Family+Column Qualifier+Timestamp+Type的组成,而Value是Column Qualifier所对应的值。当MemStore到达一定大小后,会Flush到磁盘行程HFile,而HFile对应一个个HDFS的BLOCK文件,MemStore以及HFile中要求Key必须是高度有序的,因此可以快速定位数据,HBase对表的所有的插入和更新都转换成对HDFS的HFile文件的创建。这样一来数据更新和删除的问题解决了,但是要做离线分析就复杂了,因为除了Key以外的其他数据无法定位,而且将HDFS数据文件经过一次转换,在最差情况下可能需要SCAN全表才能找到分析需要的数据。


KUDU的数据处理流程和HBase有些类似,但是为了满足更高要求的数据一致性以及数据分析能力,KUDU的数据写入过程比HBase更加复杂,因此KUDU的随机读写效率是要比HBase差一些的。但是它又一些新的特性比HBase更优秀,例如:


● KUDU的数据分区方式多样化,而HBase单一化;

● KUDU底层采用本地文件系统,而HBase底层采用HDFS;

● KUDU本身就有Catalog Table的机制,因此和Impala集成时运作效率很高,而HBase这点基本上望尘莫及;

● KUDU的Compaction产生的IO量非常小,不会产生性能问题,而HBase大表的Major Compaction很容易诱发性能问题。


KUDU与HDFS相比,它虽然实现了数据的快速更新,删除等需求,但是它也有以下不足的地方


● KUDU的稳定性较差,节点故障或者磁盘损坏都会导致数据一致性风险;

● KUDU Compaction的文件小但是数量多,因此系统的最大打开文件数限制需要设置的比较大;

● KUDU运行时需要较多的内存。


KUDU目前最新版本已经发展到1.11.1。除上述情况外,仍然存在一些使用上的限制:


◆ 表创建后,主键不能修改;

◆ 主键列大小不能大于16K,且必须在非主键列之前;

◆ KUDU中的表最大只能支持300列;

◆ 不能使用Alter Table改变现有列的类型和属性;

◆ 副本数在建表时指定,后续无法修改;

◆ 表名和列名必须为有效的UTF-8字符串,最大256字符,且不支持其他编码类型;

◆ 删除部分数据不会立刻释放存储空间,必须等待KUDU内部执行Compaction后才会释放,但如果删除整张表,存储空间会立即释放。


总之,HDFS,HBase, KUDU都是优秀的Hadoop技术组件,各有优势也都还存在不完美之处。具体使用什么组件存储数据最合适,还是需要根据业务场景来确定。