欢迎访问网易云社区,了解更多网易技术产品运营经验。
html
背景java
Cloudera在2016年发布了新型的分布式存储系统——kudu,kudu目前也是apache下面的开源项目。Hadoop生态圈中的技术繁多,HDFS做为底层数据存储的地位一直很牢固。而HBase做为Google BigTable的开源产品,一直也是Hadoop生态圈中的核心组件,其数据存储的底层采用了HDFS,主要解决的是在超大数据集场景下的随机读写和更新的问题。Kudu的设计有参考HBase的结构,也可以实现HBase擅长的快速的随机读写、更新功能。那么同为分布式存储系统,HBase和Kudu两者有何差别?二者的定位是否相同?咱们经过分析HBase与Kudu总体结构和存储结构等方面对二者的差别进行比较。
总体结构Hbase的总体结构算法
HBase的主要组件包括Master,zookeeper服务,RegionServer,HDFS。
(1)Master:用来管理与监控全部的HRegionServer,也是管理HBase元数据的模块。
(2)zookeeper:做为分布式协调服务,用于保存meta表的位置,master的位置,存储RS当前的工做状态。
(3)RegionServer:负责维护Master分配的region,region对应着表中一段区间内的内容,直接接受客户端传来的读写请求。
(4)HDFS:负责最终将写入的数据持久化,并经过多副本复制实现数据的高可靠性。
Kudu的总体结构sql
Kudu的主要组件包括TServer和TMaster。数据库
(1) TServer:负责管理Tablet,tablet是负责一张表中某块内容的读写,接收其余TServer中leader tablet传来的同步信息。
(2) TMaster:集群中的管理节点,用于管理tablet的基本信息,表的信息,并监听TServer的状态。多个TMaster之间经过Raft 协议实现数据同步和高可用。
主要区别
Kudu结构看上去跟HBase差异并不大,主要的区别包括:
(1)Kudu将HBase中zookeeper的功能放进了TMaster内,Kudu中TMaster的功能比HBase中的Master任务要多一些。
(2)Hbase将数据持久化这部分的功能交给了Hadoop中的HDFS,最终组织的数据存储在HDFS上。Kudu本身将存储模块集成在本身的结构中,内部的数据存储模块经过Raft协议来保证leader Tablet和replica Tablet内数据的强一致性,和数据的高可靠性。为何不像HBase同样,利用HDFS来实现数据存储,笔者猜想多是由于HDFS读小文件时的时延太大,因此Kudu本身从新完成了底层的数据存储模块,并将其集成在TServer中。
数据存储方式
apache
HBase
HBase是一款Nosql数据库,典型的KV系统,没有固定的schema模式,建表时只需指定一个或多个列族名便可,一个列族下面能够增长任意个列限定名。一个列限定名表明了实际中的一列,HBase将同一个列族下面的全部列存储在一块儿,因此HBase是一种面向列族式的数据库。
缓存
HBase将每一个列族中的数据分别存储,一个列族中的每行数据中,将rowkey\列族名、列名、timestamp组成最终存取的key值, 另 外 为 了 支 持 修 改 , 删 除 ,增 加 了 一 个 表 征 该 行 数 据 是 否 删 除 的 标 记 。 在 同 一 个 列 族 中 的 所 有 数 据 , 按照rowkey:columnfamily:columnQulifier:timestamp组成的key值大小进行升序排列,其中 rowkey 、 columnfamily 、columnQulifier 采用的是字典顺序,其值越大,Key越大,而timestamp是值越大,Key越小。HBase经过按照列族分开存储,相对于行式存储可以实现更高的压缩比,这也是其比较重要的一个特性。
HBase对一行数据进行更新时,HBase也是至关于插入一行新数据,在读数据时HBase按照timestamp的大小获得通过更新过的最新数据。分布式
Kudu
Kudu是一种彻底的列式存储引擎,表中的每一列数据都是存放在一块儿,列与列之间都是分开的。
oop
为了可以保存一部分历史数据,并实现MVCC,Kudu将数据分为三个部分。一个部分叫作base data,是当前的数据;第二个部分叫作UNDO records,存储的是从插入数据时到造成base data所进行的全部修改操做,修改操做以必定形式进行组织,实现快速查看历史数据;第三个部分是REDO records,存储的是还未merge到当前数据中的更新操做。下图中表示的是在Kudu中插入一条数据、更新数据两个操做的作法,固然作法不惟一,不惟一的缘由是Kudu能够选择先不将更新操做合并到base data中。性能
差别分析
(1)HBase是面向列族式的存储,每一个列族都是分别存放的,HBase表设计时,不多使用设计多个列族,大多状况下是一个列族。这个时候的HBase的存储结构已经与行式存储无太大差异了。而Kudu,实现的是一个真正的面向列的存储方式,表中的每一列都是单独存放的;因此HBase与Kudu的差别主要在于相似于行式存储的列族式存储方式与典型的面向列式的存储方式的差别;
(2) HBase是一款NoSQL类型的数据库,对表的设计主要在于rowkey与列族的设计,列的类型能够不指定,由于HBase在实际存储中都会将全部的value字段转换成二进制的字节流。由于不须要指定类型,因此在插入数据的时候能够任意指定列名(列限定名),这样至关于能够在建表以后动态改变表的结构。Kudu由于选择了列式存储,为了更好的提升列式存储的效果,Kudu要求在建表时指定每一列的类型,这样的作法是为了根据每一列的类型设置合适的编码方式,实现更高的数据压缩比,进而下降数据读入时的IO压力;
(3) HBase对每个cell数据中加入了timestamp字段,这样可以实现记录同一rowkey和列名的多版本数据,另外HBase将数据更新操做、删除操做也是做为一条数据写入,经过timestamp来标记更新时间,type来区分数据是插入、更新仍是删除。HBase写入或者更新数据时能够指定timestamp,这样的设置能够完成某些特定的操做;
(4) 相对于HBase容许多版本的数据存在,Kudu为了提升批量读取数据时的效率,要求设计表时提供一列或者多列组成一个主键,主键惟一,不容许多个相同主键的数据存在。这样的设置下,Kudu不能像HBase同样将更新操做直接转换成插入一条新版本的数据,Kudu的选择是将写入的数据,更新操做分开存储;
(5)固然还有一些其余的行式存储与列式存储之间在不一样应用场景下的性能差别。
HBase
HBase做为一种很是典型的LSM结构的分布式存储系统,是Google bigtable的apache开源版本。通过近10年的发展,HBase 已经成为了一个成熟的项目,在处理OLTP型的应用如消息日志,历史订单等应用较适用。在HBase中真正接受客户端读写请求的RegionServer的结构以下图所示:
关于HBase的几个关键点:
(1)在HBase中,充当写入缓存的这个结构叫作Memstore,另外会将写入操做顺序写入HLOG(WAL)中以保证数据不丢失;
(2)为了提升读的性能,HBase在内存中设置了blockcache,blockcache采用LRU策略将最近使用的数据块放在内存中;
(3)做为分布式存储系统,为保证数据不由于集群中机器出现故障而致使数据丢失,HBase将实际数据存放在HDFS上,包括storefile与HLOG。HBase与HDFS低耦合,HBase做为HDFS的客户端,向HDFS读写数据。
1. HBase写过程
(1)客户端经过客户端上保存的RS信息缓存或者经过访问zk获得须要读写的region所在的RS信息;
(2)RS接受客户端写入请求,先将写入的操做写入WAL,而后写入Memstore,这时HBase向客户端确认写入成功;
(3)HBase在必定状况下将Memstore中的数据flush成storefile(多是Memstore大小达到必定阈值或者region占用的内存超过必定阈值或者手动flush之类的),storefile以HFile的形式存放在HDFS上;
(4)HBase会按照必定的合并策略对HDFS上的storefile进行合并操做,减小storefile的数量。
2. Hbase读过程
HBase读数据的过程比较麻烦,缘由包括:
(1)HBase采用了LSM-tree的多组件算法做为数据组织方式,这种算法会致使一个region中有多个storefile;
(2)HBase中采用了非原地更新的方式,将更新操做和删除操做转换成插入一条新数据的形式,虽然这样可以较快的实现更新与删除,可是将致使知足指定rowkey,列族、列名要求的数据有多个,而且可能分布在不一样的storefile中;
(3)HBase中容许设置插入和删除数据行的timestamp属性,这样致使按顺序落盘的storefile内数据的timestamp可能不是递增的。
下面介绍从HBase中读取一条指定(rowkey,column family,column)的记录:
(1)读过程与HBase客户端写过程第一步同样,先尝试获取须要读的region所在的RS相关信息;
( 2 ) RS 接收读请求, 由于HBase中支持多版本数据( 容许存在rowkey、列族名、列名相同的数据, 不一样版本的数据经过
timestamp进行区分),另外更新与删除数据都是经过插入一条新数据实现的。因此要准确的读到数据,须要找到全部可能存储有该条数据的位置,包括在内存中未flush的memstore,已经flush到HDFS上的storefile,因此须要在1 memstore +N storefile中查找;
(3)在找到的全部数据中经过判断timestamp值获得最终的数据。
Kudu
(1)Kudu中的Tablet是负责表中一块内容的读写工做,Tablet由一个或多个Rowset组成。其中有一个Rowset处于内存中,叫作Memrowset,Memrowset主要负责处理新的数据写入请求。DiskRowSet是MemRowset达到必定程序刷入磁盘后生成的,实质上是由一个CFile(Base Data)、多个DeltaFile(UNDO records &REDO records)和位于内存的DeltaMemStore组成。Base data、UNDO records、和REDO records都是不可修改的,DeltaMemStore达到必定大小后会将数据刷入磁盘生成新的REDO records。Kudu后台会有一个相似HBase的compaction线程按照必定的compaction 策略对tablet进行合并处理:
a. 将多个DeltaFile(REDO records)合并成一个大的DeltaFile;
b. 将多个REDO reccords文件与Base data进行合并,并生成新的 UNDO records;
c. 将多个DiskRowset之间进行合并,减小DiskRowset的数量。
(2)Kudu将最终的数据存储在本地磁盘上,为了保证数据可靠性,Kudu为一个tablet设置了多个副本(通常为3或5个)。因此一个tablet会由多个TServer负责维护,其中有个副本称为leader tablet,写入的请求只能经过leader tablet来处理,副本之间经过Raft协议保证其余副本与leader tablet的强一致性。
1. Kudu写过程
Kudu与HBase不一样,Kudu将写入操做分为两种,一种是插入一条新数据,一种是对一条已插入数据的更新。Kudu插入一条新数据:
(1)客户端链接TMaster获取表的相关信息,包括分区信息,表中全部tablet的信息;
(2)客户端找到负责处理读写请求的tablet所负责维护的TServer。Kudu接受客户端的请求,检查请求是否符合要求(表结构);
(3) Kudu在Tablet中的全部rowset(memrowset,diskrowset)中进行查找,看是否存在与待插入数据相同主键的数据,若是存在就返回错误,不然继续;
(4) Kudu在MemRowset中写入一行新数据,在MemRowset数据达到必定大小时,MemRowset将数据落盘,并生成一个diskrowset用于持久化数据,还生成一个memrowset继续接收新数据的请求。
Kudu对原有数据的更新
(1)客户端链接TMaster获取表的相关信息,包括分区信息,表中全部tablet的信息;
(2)Kudu接受请求,检查请求是否符合要求;
(3)由于待更新数据可能位于memrowset中,也可能已经flush到磁盘上,造成diskrowset。所以根据待更新数据所处位置不一样,kudu有不一样的作法:
a. 当待更新数据位于memrowset 时, 找到待更新数据所在行, 而后将更新操做记录在所在行中一个mutation链表中;在memrowset将数据落盘时,Kudu会将更新合并到base data,并生成UNDO records用于查看历史版本的数据和MVCC,UNDO records实际上也是以DeltaFile的形式存放;
b. 当待更新数据位于DiskRowset 时, 找到待更新数据所在的DiskRowset , 每一个DiskRowset 都会在内存中设置一个DeltaMemStore,将更新操做记录在DeltaMemStore中,在DeltaMemStore达到必定大小时,flush在磁盘,造成Delta并存在方DeltaFile中。
实际上Kudu提交更新时会使用Raft协议将更新同步到其余replica上去,固然若是在memrowset和diskrowset中都没有找到这条数据,那么返回错误给客户端;另外当DiskRowset中的deltafile太多时,Kudu会采用必定的策略对一组deltafile进行合并。
(1)客户端链接TMaster获取表的相关信息,包括分区信息,表中全部tablet的信息;
(2) 客户端找到须要读取的数据的tablet所在的TServer,Kudu接受读请求,并记录timestamp信息,若是没有显式指定,那么表示使用当前时间;
(3) Kudu找到待读数据的全部相关信息, 当目标数据处于memrowset时, 根据读取操做中包含的timestamp 信息将该 timestamp前提交的更新操做合并到base data中,这个更新操做记录在该行数据对应的mutation链表中;
(4) 当读取的目标数据位于diskrowset中,在全部DeltaFile中找到全部目标数据相关的UNDO record和REDO records,REDO records可能位于多个DeltaFile中,根据读操做中包含的timestamp信息判断是否须要将base data进行回滚或者利用REDO records将base data进行合并更新。
1.写过程
(1)HBase写的时候,不论是新插入一条数据仍是更新数据,都看成插入一条新数据来进行;而Kudu将插入新数据与更新操做分 别看待;
(2)Kudu表结构中必须设置一个惟一键,插入数据的时候必须判断一些该数据的主键是否惟一,因此插入的时候其实有一个读的 过程;而HBase没有太多限制,待插入数据将直接写进memstore;
(3)HBase实现数据可靠性是经过将落盘的数据写入HDFS来实现,而Kudu是经过将数据写入和更新操做同步在其余副本上实现 数据可靠性。
结合以上几点,能够看出Kudu在写的性能上相对HBase有必定的劣势。
2. 读过程
(1)在HBase中,读取的数据可能有多个版本,因此须要结合多个storefile进行查询;Kudu数据只可能存在于一个DiskRowset或 者MemRowset中,可是由于可能存在还未合并进原数据的更新,因此Kudu也须要结合多个DeltaFile进行查询;
(2)HBase写入或者更新时能够指定timestamp,致使storefile之间timestamp范围的规律性下降,增长了实际查询storefile的数 量;Kudu不容许人为指定写入或者更新时的timestamp值,DeltaFile之间timestamp连续,能够更快的找到须要的DeltaFile;
(3)HBase经过timestamp值能够直接取出数据;而Kudu实现多版本是经过保留UNDO records(已经合并过的操做)和REDO records(未合并过的操做)完成的,在一些状况下Kudu须要将base data结合UNDO records进行回滚或者结合REDO records进 行合并而后才能获得真正所须要的数据。
结合以上三点能够得出,不论是HBase仍是Kudu,在读取一条数据时都须要从多个文件中搜寻相关信息。相对于HBase,Kudu选 择将插入数据和更新操做分开,一条数据只可能存在于一个DiskRowset或者memRowset中,只须要搜寻到一个rowset中存在指 定数据就不用继续往下找了,用户不能设置更新和插入时的timestamp值,减小了在rowset中DeltaFile的读取数量。这样在scan 的状况下能够结合列式存储的优势实现较高的读性能,特别是在更新数量较少的状况下可以有效提升scan性能。
另外,本文在描述HBase读写过程当中没有考虑读写中使用的优化技术如Bloomfilter、timestamp range等。其实Kudu中也有使用 相似的优化技术来提升读写性能,本文只是简单的分析,所以就再也不详细讨论读写过程。若有须要了解HBase的详细读写过程,
3. 其它差别
HBase:使用的java,内存的释放经过GC来完成,在内存比较紧张时可能引起full GC进而致使服务不稳定;
Kudu:核心模块用的C++来实现,没有full gc的风险。
本文主要简单介绍了一下Kudu,并在总体结构、数据存储结构和读写过程等方面上对HBase和Kudu这两款分布式存储系统进行大 体上的比较。Kudu经过要求完整的表结构设置,主键的设定,以列式存储做为数据在磁盘上的组织方式,更新和数据分开等技巧, 使得Kudu可以实现像HBase同样实现数据的随机读写以外,在HBase不太擅长的批量数据扫描(scan)具备较好的性能。而批量 读数据正是olap型应用所关注的重点,正如Kudu官网主页上描述的,Kudu实现的是既能够实现数据的快速插入与实时更新,也能够实现数据的快速分析。Kudu的定位不是取代HBase,而是以下降写的性能为代价,提升了批量读的性能,使其可以实现快速在线分析。
想要了解网易大数据,请戳这里网易大数据|专业的私有化大数据平台
相关文章:
【推荐】 如何成为一名获客专家?
【推荐】 Persistent and Transient Data Structures in Clojure