HBase基本特点
在Hadoop生态圈中一个比较典型的NoSQL数据库就是HBase,从字面意思上来看就是Hadoop Database,Hadoop生态圈的数据库,可以提供这种OLTP的操作
- HBase – Hadoop Database:是一个 高可靠 、 高性能 、面向列 、可伸缩 的NoSQL数据库(Key-Value类型)高可靠:指的是HBase集群支持多个主节点,多个从节点,集群可靠性比较高,并且HBase的数据是存储在HDFS上的,数据可靠性也比较高。
- 高性能:指的是HBase可以存储上亿或者十亿级别的数据,实现毫秒级别查询。
- 面向列:指的是HBase数据的存储方式,是按照列存储的。
- 可伸缩:指的是HBase集群可以方便的添加或者删除一个节点。
- HBase使用 HDFS 作为其文件存储系统。
- HBase支持对海量数据的增删改查。
列式存储概念
在基于行式存储的数据库中, 数据是按照行数据为基础逻辑存储单元进行存储的, 一行中的数据在存储介质中以连续存储形式存在。列式存储是相对于行式存储来说的,在基于列式存储 的数据库中,数据是 按照列为基础逻辑存储单元 进行存储的,一列中的数据在存储介质中以连续存储形式存在。
列式存储优势
行式数据库在做一些列分析时,必须将所有列的信息全部读取出来,而列式数据库由于其是按列存取,因此只需在特定列做I/O即可完成查询与分析,效率节省90%。列式数据库在每列上还有专门的列压缩算法进一步提高数据库性能,这是行式数据库不具备的。
- Row-based(Row-based store):行式存储。
- Column-based (Cloumn-based store):列式存储。
应用场景
- 半结构化或非结构化数据
- 记录非常稀疏,HBase中值为null的列不会被存储,这样既节省了空间又提高了读性能
- 多版本数据,HBase中某一个列的值可以有任意数量的版本值,因此对于需要存储历史记录的数据,用HBase就非常方便了
- 海量数据
HBase在淘宝的应用
- 数据量变得越来越多,事实上现在淘宝几乎任何一个与用户相关的在线业务的数据量都在亿级别,每日系统调用次数从亿到百亿都有,且历史数据不能轻易删除。这需要有一个海量分布式文件系统,能对TB级甚至PB级别的数据提供在线服务
- 数据量的增长很快且不一定能准确预计,大多数应用系统从上线起在一段时间内数据量都呈很快的上升趋势,因此从成本的角度考虑对系统水平扩展能力有比较强烈的需求,且不希望存在单点制约
- 只需要简单的k-v读取,没有复杂的join等需求。但对系统的并发能力以及吞吐量、响应延时有非常高的需求,并且希望系统能够保持强一致性
- 通常系统的写入非常频繁,尤其是大量系统依赖于实时的日志分析
- 希望能够快速读取批量数据
- Schema(表结构信息)灵活多变,可能经常更新列属性或新增列
- 希望能够方便使用,有良好且语义清晰的java接口
HBase在腾讯的应用
- 高可靠性。HBase是运行在Hadoop上的NoSQL数据库,它的数据由HDFS做了数据冗余,具有高可靠性。
- 同时TDW(腾讯分布式数据仓库)五年的稳定运行,8800台的集群规模,证明了其服务于海量数据的能力。
- 高并发读写。使用日志文件(HLOG)和内存存储来将随机写转换成顺序写,保证稳定的数据插入速率;读写分离,这两种操作没有冲突。
- 优雅的伸缩性。HBase服务能力可以随服务器的增长而线性增长;HBase中表的数据表按Key 值范围自动分片,散布于不同的机器上,实现自动负载均衡;支持百亿行×百万列×上万个版本。
- 低延迟。数据按列存储,数据即索引。
- 低成本。历史数据不能轻易删除,数据量变得越来越多,尤其是对于日志类存储,写多读少。而HBase可构建在廉价的PC上,此外,HBase支持较多的压缩算法。
优缺点总结
优点:
- 支持海量存储
- 适合记录稀疏
- 支持多版本
- 适合结构化和半结构化数据
- 高可靠、高性能、动态列
缺点:
- 不支持SQL化分析
- 不擅长组合条件查询
- 不适合大范围扫描查询
HBase逻辑存储模型名词解释
- 命名空间(Namespace):命名空间类似于MySQL中的Database。
- 表(Table):表类似于MySQL中的Table。
- 行(Row):行类似于MySQL中的行。
- 行键(Rowkey):行键类似于MySQL中的主键。在MySQL中,主键不是必须的。在HBase中,行键在每一行中是必须存在的。HBase号称上亿条数据可以实现毫秒级查询,其实是需要根据Rowkey查询的,如果涉及其它列的组合查询,查询效率也一般。
- 列族(ColumnFamily):列族在MySQL中没有对应的概念。在HBase中,列族是一批列的集合,在创建表的时候,列族必须定义。
- 列(Column):列类似于在MySQL中的列。在HBase中创建表的时候,列不需要提前定义,也不能提前定义,后期在向表中添加数据的时候,动态指定列。
- 时间戳(Timestamp ):默认插入值的时候会带有时间戳,是HBase自带的,不需要在表定义的时候指定。时间戳和值是一 一对应的,时间戳的类型是 64 位整型。时间戳可以由 HBase (在数据写入时)自动赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由用户显式赋值,针对某个列,不同版本的数据按照时间戳倒序排序,即最新的数据排在最前面。HBase 在查询的时候,默认返回列中最新版本的数据。
- 数据类型( DataType ):MySQL中,数据类型多种多样,常见的有int、varchar、date、datetime等等。在HBase中,数据类型只有一种,就是byte[](字节数组),不管是什么数据类型,在HBase中存储的时候统一都会转化为byte[]。
逻辑模型详解
这个图的意思表示在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
想要达到图中这个数据效果,需要对表执行以下这些步骤:
- 第一次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为27,此时这一列的值会对应的产生一个时间戳 T1,表示数据的产生时间
注意:这里面的时间戳定义为T1只是为了看起来清晰,实际上时间戳的值就是我们平时接触到的毫秒级时间戳:1628582473928。
- 第二次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为28,此时这一列的值会对应的产生一个时间戳 T2
- 第三次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为29,此时这一列的值会对应的产生一个时间戳 T3
- 第四次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c2中的car列,值为有车,此时这一列的值会对应的产生一个时间戳 T4
- 第五次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c1中的age列,值为30,此时这一列的值会对应的产生一个时间戳 T5
- 第六次向HBase表中添加数据,指定RowKey 为隔壁老王,指定列族c2中的house列,值为有房,此时这一列的值会对应的产生一个时间戳 T6
- 第七次向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)降序排序。