备注:本文原为项目内分享(2017-12-18),部分内容来自于网络,多有借鉴之处

前言:

古人有言,欲修仙者,财侣法地缺一不可。

所谓侣,即同修、道友。


  修仙漫漫不归路,多少人在攀登高峰的时候,或失足,或饥寒,或懈怠,倒在路边。这个时候,假如有人扶你一把,给你半个馒头,也许你就有了前进的动力,这就是道侣。


    简而言之,共同学习,共同探讨,共同进步的同志。

科普中国-百科科学词条

      HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。

HBase的应用场景 hbase主要被应用于_使用场景


HBase的应用场景 hbase主要被应用于_hbase_02



列簇维度、时间维度(默认3个)在 Hbase 中,Row-key 加上 CF(列簇) 加上 Qulifier(列) 再加上一个时间戳才可以定位到一个单元格数据(Hbase 中每个单元格默认有 3 个时间戳的版本数据)查询命令:get 'ns_scpdm:tdm_fillup_suggest_order_d','003173091_7616_04_20171110_10127836_00360374250501' 

HBase的应用场景 hbase主要被应用于_基本概念_03


从技术上来说,Hbase 更像是"数据存储"而非"数据库"

     因此,HBase 缺少很多 RDBMS 特性,如列类型,二级索引,触发器和高级查询语言等。然而, HBase 也具有许多其他特征同时支持线性化和模块化扩充。最明显的方式,我们可以通过增加 Region Server 的数量扩展 HBase。并且 HBase 可以放在普通的服务器中,例如将集群从 5 个扩充到 10 个 Region Server 时,存储空间和处理容量都可以同时翻倍。当然 RDBMS 也能很好的扩充,但仅对一个点,尤其是对一个单独数据库服务器而言,为了更好的性能,往往需要特殊的硬件和存储设备(往往价格也非常昂贵)。


HBase 的工作流程

    无需过多了解
只是关注如何使用以及使用场景

首先,要确信有足够多数据,如果有上亿或上千亿行数据,HBase 才会是一个很好的备选。其次,需要确信业务上可以不依赖 RDBMS 的额外特性,例如,列数据类型, 二级索引,SQL 查询语言等。再而,需要确保有足够硬件。且不说 HBase,一般情况下当 HDFS 的集群小于 5 个数据节点时,也干不好什么事情 (HDFS 默认会将每一个 Block 数据备份 3 分),还要加上一个 NameNode。


其实rowkey设计准则一般就2条

     1、唯一性


   2、散列性(数据倾斜--热点)
   商品编码一般是反转就能散列,但是 如果有的商品编码就1条记录,有的商品编码有几百万条记录 那么这样数据还是倾斜掉   了。

   蛋疼,这个 就涉及到了HBASE的工作流程


为啥有那俩个设计原则呢?

     首先,一个 HBase 数据库是否高效,很大程度会和 Row-Key 的设计有关。因此,如何设计 Row-key 是使用 HBase 时,一个非常重要的话题。随着数据访问方式的不同,Row-Key 的设计也会有所不同。不过概括起来的宗旨只有一个,那就是尽可能选择一个 Row-Key,可以使你的数据均匀的分布在集群中。这也很容易理解,因为 HBase 是一个分布式环境,Client 会访问不同 Region Server 获取数据。如果数据排布均匀在不同的多个节点,那么在批量的 Client 便可以从不同的 Region Server 上获取数据,而不是瓶颈在某一个节点,性能自然会有所提升。对于具体的建议我们一般有几条:

     一切都是为了搞笑-高效:

当客户端需要频繁的写一张表,随机的 RowKey 会获得更好的性能。
当客户端需要频繁的读一张表,有序的 RowKey 则会获得更好的性能。

对于时间连续的数据(例如 log),有序的 RowKey 会很方便查询一段时间的数据(Scan 操作)。例如:key:20171201,20171202

场景、功能描述:

  数据库(包括其他一些关系型数据库)在单表记录数超过100w时就会变得很慢。解决方法是分表,或者迁移到专注于处理海量数据的NoSQL
a)HBase对数据操作的响应速度与当前表中的数据量无关,但是与数据的split以及本地缓存等配置项有很大关系。 比如rowKey的合理设计,使相关数据相邻存放;比如使用scan时setCatch(num)方法中num的取值。

b)HBase对数据操作的响应在毫秒级,满足我们前端显示的需要


HBase获得记录总数很困难,浏览所有数据倒好说,我可以在数据库中存一下当前数据库中记录的总数。如果满足条件的记录有1亿条,我总不能先遍历一边记个数啊……
听说在MapReduce层可以有办法完成总数的统计
因此分页比较坑
因此hbase就不适合分页,但总是有取巧的法子及其对应的应用场景
1、scan全查出来,自己手写分页
2、不计算总页数,利用pagefilter,startKey只保证上一页,下一页


案例:

      1、精确查询
         数据量:2亿条数据   平均日销:get     0.3秒
     rowkey:CommonUtil.convertStr(cmmdtyCode)+"_" + supplyPlant+"_" + plantType +"_"+lastDate
  2、模糊查询
                 OMS订单:scan
     rowkey:CommonUtil.convertStr(cmmdtyCode)+"_" + supplyPlant+"_" + plantType +"_"+lastDate+”_”+订单号,
     前缀一致,获得多条记录
    3、分页查询pagefilter  :分页效率比较低,应为每次都需要扫描前面的数据,直到扫描到所需要查的数据,但是查询下一页的时候可以直接利用上一页的rowkey来直接查出,查询总数效率特低,不建议使用。

             用过滤器的前提是:   你scan的数据范围 已经用 start 和end 限定的很小了,基于列的过滤都是没有索引的 性能很差   


结构图:

          

HBase的应用场景 hbase主要被应用于_数据_04

数据倾斜:

Hbase的表会被划分为1....n个Region,被托管在RegionServer中。Region二个重要的属性:Startkey与EndKey表示这个Region维护的rowkey的范围,当我们要读写数据时,如果rowkey落在某个start-end key范围内,那么就会定位到目标region并且读写到相关的数据。
    默认情况下,当我们通过hbaseAdmin指定TableDescriptor来创建一张表时,只有一个region正处于混沌时期,start-end key无边界,可谓海纳百川。所有的rowkey都写入到这个region里,然后数据越来越多,region的size越来越大时,大到一定的阀值,hbase就会将region一分为二,成为2个region,这个过程称为分裂(region-split)。
    如果我们就这样默认建表,表里不断的put数据,更严重的是我们的rowkey还是顺序增大的,是比较可怕的。存在的缺点比较明显:首先是热点写,我们总是向最大的start key所在的region写数据,因为我们的rowkey总是会比之前的大,并且hbase的是按升序方式排序的。所以写操作总是被定位到无上界的那个region中;其次,由于热点,我们总是往最大的start key的region写记录,之前分裂出来的region不会被写数据,有点打入冷宫的感觉,他们都处于半满状态,这样的分布也是不利的。
    如果在写比较频繁的场景下,数据增长太快,split的次数也会增多,由于split是比较耗费资源的,所以我们并不希望这种事情经常发生。
    在集群中为了得到更好的并行性,我们希望有好的load blance,让每个节点提供的请求都是均衡的,我们也不希望,region不要经常split,因为split会使server有一段时间的停顿,如何能做到呢?

    随机散列与预分区二者结合起来,是比较完美的。预分区一开始就预建好了一部分region,这些region都维护着自己的start-end keys,在配合上随机散列,写数据能均衡的命中这些预建的region,就能解决上面的那些缺点,大大提供性能。


解决思路-额外:

       提供两种思路:hash与partition