一、什么是Hbase

在前面我们学习过了Hive,一句话概括Hive就是一个数据仓库,更像一个传统意义上的SQL数据库,主要用作数据仓库数据分析,更加强调离线的数据分析,为公司各个业务部门提供数据支撑。但是在我们大数据的处理过程中,不光需要进行OLAP的操作,在有些情况下,也经常需要对数据进行记录级别的更新、删除等操作,也就是OLTP(联机事务处理)的操作,这是Hive所办不到的,那么这个时候就不能用Hive来为我们处理OLTP的业务了,因为Hive不支持事务,那我们使用Oracle总可以吧,当然对于一定范围内的数据是OK,没有问题的,但是当数据量达到亿级别,甚至更高的时候,Oracle的性能也会下降的非常厉害,几乎就瘫掉了。

比如有这么一个例子:公司原来的业务系统使用的是Oracle,目前数据量大约10亿条,处理响应非常慢。为了平缓的迁移到大数据平台,那么决定使用hive替换oracle,这种方案怎么样? 这个方案不怎么样。

我们都知道Oracle是关系型数据库,强调的是事务,更适合OLTP的应用场景。而Hive是数据仓库,更强调的是在大数据基础上的强大的查询和分析能力,更适合于OLAP的应用场景,显然是无法来帮我们完成业务需求的。 既然传统的SQL无法解决我们的这种需求,那么就需要另辟蹊径了——NoSQL(Not only SQL),使用NoSQL数据库来满足我们的业务需求,在Hadoop生态圈中一个比较典型的NoSQL数据库就是HBase,从字面意思上来看就是Hadoop Database,Hadoop生态圈的数据库,可以提供这种OLTP的操作,解决我们刚才提出的问题。

那么,HBase到底是一个怎么样的NoSQL数据库呢?我们来看一下。

1、HBase – Hadoop Database:是一个 高可靠 、 高性能 、面向列 、可伸缩 的NoSQL数据库(Key-Value类型)

高可靠:指的是HBase集群支持多个主节点,多个从节点,集群可靠性比较高,并且HBase的数据是存储在HDFS上的,数据可靠性也比较高。

高性能:指的是HBase可以存储上亿或者十亿级别的数据,实现毫秒级别查询。

面向列:指的是HBase数据的存储方式,是按照列存储的。

可伸缩:指的是HBase集群可以方便的添加或者删除一个节点。

2、HBase使用 HDFS 作为其文件存储系统。 HBase数据库的数据是存储在HDFS上面的。

3、HBase支持对海量数据的增删改查。 这里大家可能会有一个疑问,HDFS是不支持修改删除的,为什么HBase也是基于HDFS存储数据的,却可以支持修改删除呢?

这是因为HBase自己封装了一个中间层,在中间层针对删除的数据会做一个特殊标记,这样在查询的时候就会过滤掉已经标记为删除状态的数据,这样间接支持了删除功能。

二、列存储简介

传统的关系型数据库,如MySQL、Oracle等采用 行存储 的方式来存储数据 先来解释一下行存储的概念。

咱们在MySQL中使用的select… where…语句,select后面的字段表示从行中查询哪些字段,where是过滤查询哪些行的。 MySQL存储的时候都是按行存储的,对于关系型数据库而言,按行存储查询起来效率是比较高的。

绝大多数传统意义上的RDBMS都采用行存储的方式来存储数据,基于此一般都适合SQL查询,并且适合一次性查询出所有列、适合范围查询的情况。

缺点是不适合查询少量字段的情况。就算是你只需要查询某一个列的数据,底层也需要读取这一行中所有列的数据,最后只过滤出来你需要的某个列,这是由它的底层数据结构而定的。

在基于行式存储的数据库中, 数据是 按照行数据为基础逻辑存储单元 进行存储的, 一行中的数据在存储介质中以连续存储形式存在。

列式存储是相对于行式存储来说的,在基于列式存储 的数据库中,数据是 按照列为基础逻辑存储单元 进行存储的,一列中的数据在存储介质中以连续存储形式存在。

三、列式存储的优点

行式数据库在做一些列分析时,必须将所有列的信息全部读取出来,而列式数据库由于其是按列存取,因此只需在特定列做I/O即可完成查询与分析,效率节省90%。

列式数据库在每列上还有专门的列压缩算法进一步提高数据库性能,这是行式数据库不具备的。

Row-based(Row-based store):行式存储。

Column-based (Cloumn-based store):列式存储。

从这个图里面可以看出来:

行式存储数据库中的数据在底层存储的时候,每一行的数据作为一个基础逻辑存储单元进行存储。

列式存储数据库中的数据在底层存储的时候,每一列的数据作为一个基础逻辑存储单元进行存储。

四、HBase典型应用场景

1、半结构化或非结构化数据

对于数据结构字段不够确定或杂乱无章,很难按一个概念去进行抽取的数据适合用HBase进行存储。

比如文章的tag(标签)信息,会不断的增加、删除。 解释:每个文章的标签信息是不一样的,并且标签也会经常变化,用户可能随时对文章的标签信息进行修改。

如果使用MySQL存储,可以选择把文章的所有标签信息通过逗号分割拼接成一个字符串存储到一个字段里面,这样存储的时候方便了,但是使用的时候比较麻烦,每次都需要解析这个字符串进行处理。

当然也可以选择在MySQL中将每一个标签都存储到一个独立的字段中,这样使用起来比较方便,但是这样表结构就需要经常变化了,可能会存在某一篇文章有10个标签信息(需要10个标签字段),另一篇文章只有1个标签信息的情况(只需要1个标签字段),这样表结构中至少需要增加10个标签字段,这样就会存在字段冗余的情况,额外浪费存储空间。

2、记录非常稀疏

RDBMS(关系型数据库)的每一行有多少列是固定的,值为null的列浪费了存储空间。

HBase中值为null的列不会被存储,这样既节省了空间又提高了读性能。

3、多版本数据

HBase中某一个列的值可以有任意数量的版本值,因此对于需要存储历史记录的数据,用HBase就非常方便了。

解释:Mysql上如果想要保存一个数据的多个历史版本数据的话只能存储多行记录,而HBase只需要针对某个列存储多个历史版本即可,通过时间戳可以定位历史版本的数据。

4、超大数据量

当数据量越来越大,RDBMS数据库撑不住了,就出现了读写分离策略,通过一个Master专门负责写操作,多个Slave负责读操作,服务器成本倍增。 随着压力增加,Master撑不住了,这时就要分库了,把关联不大的数据分开存储,一些join查询不能用了,需要借助中间层。

随着数据量的进一步增加,一个表的记录越来越大,查询就变得很慢,于是又得搞分表,比如按ID取模分成多个表以减少单个表的记录数。

经历过这些事的人都知道过程是多么的折腾。采用HBase就简单了,只需要加机器即可,HBase会自动水平切分扩展,跟Hadoop的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性能(MapReduce)。

五、HBase应用案例

淘宝在2011年之前所有的后端持久化存储基本上都是在MySQL上进行的,MySQL由于开源,并且生态系统良好,本身拥有分库分表等多种解决方案,因此很长一段时间内都可以满足淘宝大量业务的需求。

但是由于业务的多样化发展,有越来越多的业务系统的需求开始发生了变化。一般来说有以下几类变化:

1、数据量变得越来越多,事实上现在淘宝几乎任何一个与用户相关的在线业务的数据量都在亿级别,每日系统调用次数从亿到百亿都有,且历史数据不能轻易删除。这需要有一个海量分布式文件系统,能对TB级甚至PB级别的数据提供在线服务

2、数据量的增长很快且不一定能准确预计,大多数应用系统从上线起在一段时间内数据量都呈很快的上升趋势,因此从成本的角度考虑对系统水平扩展能力有比较强烈的需求,且不希望存在单点制约

3、只需要简单的k-v读取,没有复杂的join等需求。但对系统的并发能力以及吞吐量、响应延时有非常高的需求,并且希望系统能够保持强一致性

4、通常系统的写入非常频繁,尤其是大量系统依赖于实时的日志分析

5、希望能够快速读取批量数据

6、Schema(表结构信息)灵活多变,可能经常更新列属性或新增列

7、希望能够方便使用,有良好且语义清晰的java接口

腾讯产品与技术的发展迅速,几乎任何一个与用户相关的在线业务的数据量都在亿级别,每日系统调用次数从亿到百亿,对海量数据的高效插入和快速读取变得越来越重要。

而传统关系型数据库模式固定、强调参照完整性、数据的逻辑与物理形式相对独立等,比较适用于中小规模的数据,但对于数据的规模和并发读写方面进行大规模扩展时,RDBMS性能会大大降低,分布式更为困难。 腾讯为什么会选择HBase?

1、高可靠性。 HBase是运行在Hadoop上的NoSQL数据库,它的数据由HDFS做了数据冗余,具有高可靠性。

2、同时TDW (腾讯分布式数据仓库)五年的稳定运行,8800台的集群规模,证明了其服务于海量数据的能力。

3、高并发读写。 使用日志文件(HLOG)和内存存储来将随机写转换成顺序写,保证稳定的数据插入速率;读写分离,这两种操作没有冲突。

4、优雅的伸缩性。 HBase服务能力可以随服务器的增长而线性增长;HBase中表的数据表按Key 值范围自动分片,散布于不同的机器上,实现自动负载均衡;支持百亿行×百万列×上万个版本。

5、低延迟。 数据按列存储,数据即索引。

6、低成本。 历史数据不能轻易删除,数据量变得越来越多,尤其是对于日志类存储,写多读少。而HBase可构建在廉价的PC上,此外,HBase支持较多的压缩算法。

六、HBase的优缺点总结

1、HBase的优点:

支持动态列:支持随时动态增加或者减少列。例如:第一条数据有10列,第二条数据可以有100列,互相不影响,也不需要修改表结构。

2、HBase的缺点:

不支持SQL数据分析:HBase属于NoSQL数据库,所以不支持常见的SQL语法。

不擅长多条件组合查询:HBase中根据多个列进行组合条件查询相当于全表扫描,所以效率不高。

不适合大范围扫描查询:大范围扫描效率不高,数据量过大时容易导致扫描超时或者失败。

七、HBase逻辑存储模型之名词解释

1、命名空间(Namespace): 命名空间类似于MySQL中的Database。

2、表(Table): 表类似于MySQL中的Table。

3、行(Row):行类似于MySQL中的行。

4、行键(Rowkey): 行键类似于MySQL中的主键。 在MySQL中,主键不是必须的。在HBase中,行键在每一行中是必须存在的。 HBase号称上亿条数据可以实现毫秒级查询,其实是需要根据Rowkey查询的,如果涉及其它列的组合查询,查询效率也一般。

5、列族(ColumnFamily): 列族在MySQL中没有对应的概念。在HBase中,列族是一批列的集合,在创建表的时候,列族必须定义。

6、列(Column): 列类似于在MySQL中的列。在HBase中创建表的时候,列不需要提前定义,也不能提前定义,后期在向表中添加数据的时候,动态指定列。

7、时间戳(Timestamp ): 默认插入值的时候会带有时间戳,是HBase自带的,不需要在表定义的时候指定。 时间戳和值是一 一对应的,时间戳的类型是 64 位整型。时间戳可以由 HBase (在数据写入时)自动赋值,此时时间戳是精确到毫秒的当前系统时间。 时间戳也可以由用户显式赋值,针对某个列,不同版本的数据按照时间戳倒序排序,即最新的数据排在最前面。 HBase 在查询的时候,默认返回列中最新版本的数据。

8、数据类型( DataType ): MySQL中,数据类型多种多样,常见的有int、varchar、date、datetime等等。 在HBase中,数据类型只有一种,就是byte[](字节数组),不管是什么数据类型,在HBase中存储的时候统一都会转化为byte[]。

什么是逻辑存储模型呢?简单来说就是我们操作HBase的时候能够直观看到的一些东西。

这个图的意思表示在HBase中有一张表,表里面有2个列族,c1和c2 目前这个表里面有1条数据,这条数据的RowKey是 隔壁老王

其中列族c1里面只有1列,是age,列族c2里面有2列,car和house

针对列族c1中的age列的值而言,有4个历史版本:T1,T2,T3,T5。

想要定位某一列的值,流程是这样的:HBase Table --> RowKey --> ColumnFamily --> Column --> TimeStamp

想要达到图中这个数据效果,需要对表执行以下这些步骤:

1、第一次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为27,此时这一列的值会对应的产生一个时间戳 T1,表示数据的产生时间

注意:这里面的时间戳定义为T1只是为了看起来清晰,实际上时间戳的值就是我们平时接触到的毫秒级时间戳:1628582473928。

2、第二次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为28,此时这一列的值会对应的产生一个时间戳 T2

3、第三次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为29,此时这一列的值会对应的产生一个时间戳 T3

4、第四次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c2中的car列,值为有车,此时这一列的值会对应的产生一个时间戳 T4

5、第五次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为30,此时这一列的值会对应的产生一个时间戳 T5

6、第六次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c2中的house列,值为有房,此时这一列的值会对应的产生一个时间戳 T6

7、第七次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c2中的car列,值为没车(老王把车卖了),此时这一列的值会对应的产生一个时间戳 T7。

经过这7步之后,数据就可以达到和图中一样的效果了。

HBase是 三维(三个维度) 有序存储的,是指Rowkey,Column key(Column Family和Column)和 TimeStamp 这三个维度是依照ASCII码表排序的。

先按Rowkey升序排序。Rowkey相同则按Column key升序排序。Rowkey、Column key相同则按Timestamp降序排序

如下图所示:

这个图里面表示对HBase的表t1进行全表扫描,在扫描的时候会返回同一个列的最多2个历史版本数据(VERSIONS=>2)。

图中执行scan ‘t1’,{VERSION=>2}(全表扫描) 命令之后,最终返回了3条数据,Rowkey是:stu001,stu002,stu003。

针对第1条数据stu001,它里面一共有3列:age,name、math。列族有2个:info和level。age和name属于info列族,math属于level列族。

这里的info:age显示了两次是因为age字段存储了2个历史版本的数据。

最终从这个图里面是可以看出来HBase的三维有序存储特性的。

首先按照Rowkey(stu001,stu002,stu003)升序排序,相同Rowkey(stu001)内按照Column key(info:age,info:name,level:math)升序排序,

针对相同的Column key(info:age),则按照数据对应的Timestamp(1800690940131,1800690940039)降序排序。

查看原文