Hbase深入理解
1. Memstore
- 转载:https://www.cnblogs.com/shitouer/archive/2013/02/05/configuring-hbase-memstore-what-you-should-know.html- 当RegionServer(RS)收到写请求的时候(write request),RS会将请求转至相应的Region。每一个Region都存储着一些列(a set of rows)。根据其列族的不同,将这些列数据存储在相应的列族中(Column Family,简写CF)。不同的CFs中的数据存储在各自的HStore中,HStore由一个Memstore及一系列HFile组成。Memstore位于RS的主内存中,而HFiles被写入到HDFS中。当RS处理写请求的时候,数据首先写入到Memstore,然后当到达一定的阀值的时候,Memstore中的数据会被刷到HFile中。
用到Memstore最主要的原因是:
1. 由于HDFS上的文件不可修改,为了让数据顺序存储从而提高读取效率,HBase使用了LSM树结构来存储数据。数据会先在Memstore中整理成LSM树,最后再刷写到HFile上。
2. 优化数据的存储。比如一个数据添加后就马上删除了,这样在刷写的时候就可以直接不把这个数据写到HDFS上。
早期HDFS上的所有文件都是只能写入不能修改的。后来加入了追加(append)特性,实现了数据可以增加,但是必须是顺序增加,还是不能修改之前的数据。而HBase是一个随机读写的数据库。MemStore会在数据最终刷写到HDFS上之前对文件进行排序处理,这样随机
写入的数据就变成了顺序存储的数据,可以提高读取效率。所以MemStore是实现LSM树存储的必须设计组件。在LSM树的实现方式中,有一个必经的步骤,那就是在数据存储之前先对数据进行排序。而LSM树也是保证HBase能稳定地提供高性能的读能力的基本算法。LSM树是Google
BigTable和HBase的基本存储算法,它是传统关系型数据库的B+树的改进。算法的关注重心是“如何在频繁的数据改动下保持系统读取速度的稳定性”,算法的核心在于尽量保证数据是顺序存储到磁盘上的,并且会有频率地对数据进行整理,确保其顺序性。而顺序性就可以最大程度保证数据的读取性能稳定。
原文链接:https://blog.csdn.net/f1550804/article/details/88382936
-
作为一个内存级缓存,缓存最近增加数据。一种显而易见的场合是,新插入数据总是比老数据频繁使用。
-
在持久化写入之前,在内存中对Rows/Cells可以做某些优化。比如,当数据的version被设为1的时候,对于某些CF的一些数据,Memstore缓存了数个对该Cell的更新,在写入HFile的时候,仅需要保存一个最新的版本就好了,其他的都可以直接抛弃。
-
有一点需要特别注意:每一次Memstore的flush,会为每一个CF创建一个新的HFile。 在读方面相对来说就会简单一些:HBase首先检查请求的数据是否在Memstore,不在的话就到HFile中查找,最终返回merged的一个结果给用户。
2.HBase数据模型与KeyValue格式解析
- 转载https://www.cnblogs.com/yhxx511/p/9571053.html
HBase的数据模型是一个松散表结构,所谓松散,包含两个方面的含义
没有schema:没有一个地方定义了一行应该包括哪些列,这些列都是什么类型。这个信息通常只有用户自己知道。
稀疏:每行的列都可以完全不同,行与行之间的列在HBase层面没有任何关联
所以,我们说HBase是schema-free的,可以任意添加列。这些能力的基础就是KeyValue的设计。
KeyValue对使用者而言是一个六元组,即(rowkey, family, qualifier, timestamp, type, value)。在1.x版本之后,添加了tags支持,变成了7元组,即(rowkey, family, qualifier, timestamp, type, value, tags)。但其设计思想是没有变的,即key-value的方式进行存储,从业务逻辑上看,key就是rowkey;value除了值本身,还包含了value的一些描述信息,即family、qualifier、timestamp和type。
所以,KeyValue本身在可以独立的描述一行中的一列数据。因为带上了列名信息,所以,不需要事先定义好一行有哪些列(schema)。也因为如此,一行中可以存在任意的列,每行的列都可以完全不同。这个能力相比传统的RDBMS而言无疑是非常强大的,目前诸多的NoSQL系统几乎都提供这种schema-free的能力。这个能力比较常见的应用可以是:
从容应对业务模型变化:设计数据库的人都知道,业务需求变了,表设计也要跟着变,经常要添加列。而HBase这种模型,不存在“添加列”这个操作,直接写新列就好了。
列名本身也可以存储信息:因为列名本身与列值绑定在一起了,我们可以利用列名来存储信息,比如
时序场景,可以用列名作为数据的时间
图数据库场景,可以用列名来描述“边”
天下没有免费的午餐,在获得上述强大能力的同时,要付出的代价也是巨大的,即数据冗余,包括:
rowkey重复存储:一行由多个具有相同rowkey的KeyValue组成
family,qualifier重复存储
如果表是直接从RDBMS迁移过来的,每行都有相同的列,那无疑列名的重复会额外占用很多空间,尤其是一行中列较多的时候。这也是为什么在表设计时,要选取尽可能短小的family名字和列名。另外,rowkey的重复也有同样的问题。我们有一些技术可以有效的解决这些问题。
DIFF压缩:解决rowkey重复存储的问题,在一行中列较多时效果非常明显,这里不展开。
列名映射:通常列名都是一些比较长的单词或者短语,每列的列名不同,对DIFF压缩不友好。所以,可以将易读的列名映射为二进制的短列名(如short类型),HBase层面实际存储的是1,2,3这样的列名,而业务层通过一套列名映射机制在读写数据的时候进行列名转换。用时间换空间。具体可以参考Phoenix的Column Name Econding(PHOENIX-1598)。
3. StoreFile Compaction
由于Hbase依赖HDFS存储,HDFS只支持追加写。所以,当新增一个单元格的时候,HBase在HDFS上新增一条数据。当修改一个单元格的时候,HBase在HDFS又新增一条数据,只是版本号比之前那个大(或者自定义)。当删除一个单元格的时候,HBase还是新增一条数据!只是这条数据没有value,类型为DELETE,也称为墓碑标记(Tombstone)
HBase每间隔一段时间都会进行一次合并(Compaction),合并的对象为HFile文件。合并分为两种
minor compaction和major compaction。
在HBase进行major compaction的时候,它会把多个HFile合并成1个HFile,在这个过程中,一旦检测到有被打上墓碑标记的记录,在合并的过程中就忽略这条记录。这样在新产生的HFile中,就没有这条记录了,自然也就相当于被真正地删除了
由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile Compaction。
Compaction分为两种,分别是Minor Compaction和Major Compaction。Minor Compaction会将临近的若干个较小的HFile合并成一个较大的HFile,但不会清理过期和删除的数据。Major Compaction会将一个Store下的所有的HFile合并成一个大HFile,并且会清理掉过期和删除的数据。
4. HDFS只支持文件append操作, 而依赖HDFS的HBase如何完成数据的增删改查
转载:https://www.cnblogs.com/hadoop-dev/p/6347379.html?utm_source=itdadao&utm_medium=referral
1. HDFS的文件append功能
早期版本的HDFS不支持任何的文件更新操作,一旦一个文件创建、写完数据、并关闭之后,这个文件就再也不能被改变了。为什么这么设计?是为了与MapReduce完美配合,MapReduce的工作模式是接受一系列输入文件,经过map和reduce处理,直接产生一系列输出文件,而不是在原来的输入文件上做原位更新。为什么这么做?因为直接输出新文件比原位更新一个旧文件高效的多。
在HDFS上,一个文件一直到它的close方法成功执行之后才会存在,才能被其他的client端所看见。如果某个client端在写文件时或者在close文件时失败了,那么这个文件就不会存在,就好像这个文件从来没写过,唯一恢复这个文件的方法,就是从头到尾重新再写一遍。
Hadoop1.x版本一直都不支持文件的append功能,一直到Hadoop 2.x版本,append 功能才被添加到Hadoop Core中,允许向HDFS文件中追加写数据。为此,HDFS Core 也作出了一些重大的改变,以支持这一操作。append功能添加到HDFS经历了一番曲折和一段很长的时间(具体可以参考http://blog.cloudera.com/blog/2009/07/file-appends-in-hdfs/和 https://issues.apache.org/jira/browse/HADOOP-8230)。
2. HBase 如何完成数据更新和删除操作
HBase依赖于HDFS来存储数据。HBase作为数据库,必须提供对HBase表中数据的增删改查,而HDFS的文件只支持append操作、不支持删除和更新操作,那么HBase如何依赖HDFS完成更新以及删除操作呢??。
2.1 更新操作
HBase表中的数据当存放到HDFS中时,在HDFS看来,已经可以简单的理解成key-value对,其中key可以理解成是由:rowkey+column family+column qualifier+timestamp+type 组成。HBase 对新增的数据以及要更新的数据(理解成key-value对),都直接先写入MemStore结构中,MemStore是完全的内存结构,且是key有序的。当MemStore达到一定大小后,该MemStore一次性从内存flush到HDFS中(磁盘中),生成一个HFile文件,HFile文件同样是key有序的,并且是持久化的位于HDFS系统中的。通过这种机制,HBase对表的所有的插入和更新都转换成对HDFS的HFile文件的创建。
你可能会迅速的想到,那查询怎么办?
是的,这种方式解决了插入和更新的问题,而查询就变得相对麻烦。而这也正是HBase设计之初的想法:以查询性能的下降来换取更新性能的提升。
事实上查询是如下来完成的。
每当MemStore结构flush到HDFS上时,就会产生一个新的HFile文件,随着时间的推移,会产生一连串的HFile文件,这些HFile文件产生的先后顺序非常的重要,可以想象成他们按创建时间排成一个队列,最近产生的在最前面,较早产生的在最后面。当HBase执行查询操作时(可以理解为给出key,要找到value),首先查询内存中的MemStroe结构,如果命中,就返回结果,因为MemStore中的数据永远是最新的,如果不命中,就从前到后遍历之前产生的HFile文件队列,在每个HFile文件中查找key,看是否命中,如果命中即可返回(最新的数据排在最前面),如果不命中一直查找下去,直到所有HFile文件被搜索完结束。
由此可见,查询操作最坏情况下可能要遍历所有HFile文件,最好情况下在内存中MemStore即可命中,这也是为什么HBase查询性能波动大的原因。当然HBase也不会真的很傻的去遍历每个HFile文件中的内容,这个性能是无法忍受的,它采取了一些优化的措施:1、引入bloomfilter,对HFile中的key进行hash,当查询时,对查询key先过bloomfilter,看查询key是否可能在该HFile中,如果可能在,则进入第2步,不在则直接跳过该HFile;2、还记得吗?HFile是key有序的(具体实现是类SSTable结构),在有序的key上查找就有各种优化技术了,而不是单纯的遍历了。
通过以上机制,HBase很好的解决了插入和更新、以及查找的问题,但是问题还没有结束。细心的朋友很可能已经看出来,上述过程中,HFile文件一直在产生,HFile文件组成的列表一直在增大,而计算机资源是有限的,并且查询的性能也依赖HFile队列的长度,因此我们还需要一种合并HFile文件的机制,以保持适度的HFile文件个数。HBase中实现这种机制采用的是LSM树(一种NOSQL系统广泛使用的结构),LSM能够将多个内部key有序的小HFile文件合并生成一个大的HFile文件,当新的大的HFile文件生成后,HBase就能够删除原有的一系列旧的小的HFile文件,从而保持HFile队列不至于过长,查询操作也不至于查询过多的HFile文件。在LSM合并HFile的时候,HBase还会做很重要的两件事:1、将更新过的数据的旧版本的数据删除掉,只留下最新的版本;2、将标有删除标记(下面一节会讲到)的数据删除掉。
2.2 删除操作
有了以上机制,HBase完成删除操作非常的简单,对将要删除的key-value对进行打标,通常是对key进行打标,将key中的type字段打标成“删除”标记,并将打标后的数据append到MemStore中,MemStore再flush到HFile中,HFile合并时,检查这个标记,所有带有“删除”标记的记录将被删除而不会合并到新的HFile中,这样HBase就完成了数据的删除操作。
2.3 HBase 的WAL
HBase的WAL(Write-Ahead-Log)机制是必须的,一个RegionServer通常与一个HLog一一对应,数据写入Region之前先写HLog能够保障数据的安全。 HLog使用Hadoop的SequenceFile存储日志,而HLog是一直连续不断追加写文件的,它强烈依赖SequenceFile的append功能。事实上正是HLog对append功能的强烈需求,或多或少推动了HDFS在最近的版本中添加了文件追加功能。