部门分享——HBase

今天部门分享了HBase。发一下自己的稿子

本次分享的开始,想要旧事重提一下,Google被誉为大数据领域的“三驾马车”的那三篇论文:
第一篇是:The google file system
第二篇是:MapReduce:Simplified Data Processing on Large Clusters
第三篇是:2006年发表的 BigTable:A Distributed Storage System for Structured Data. 它介绍了很多BigTable的设计原理,但其实这些原理大多都能在HBase中找到影子。

尽管有微小异同,例如压缩算法,时间戳单位等,但是,HBase实现了BigTable的储存架构。

本次分享会,我会从HBased 的一些特性讲起,并且明确什么样的使用场景和数据场景适用HBase。再简述一下架构与API。最后讲一下实际项目中遇到过的坑。至于如何安装和配置这些就不提了,这个网上都能查到。

为什么想要讲这么多适用场景与特性,因为我觉得,首先我们得明白一个组件、技术的使用场景,那么等到需求到来的时候,我们才能够及时、准确地挑选组件,我觉得这点很重要。最后等到实践场景中,真正需要用这个组件的时候,再进行针对性地熟练与学习,也来得及的。
部门分享——HBase
要想知道 HBase 的用途,就需要看一看其在 Apache 的 Hadoop 生态系统中的位置,可以看到 HBase 是构建在 HDFS 之上的,这是由于 HBase 内部管理的文件全部都是存储在 HDFS 当中的。同时,MapReduce 这个计算框架在 HBase 之上又提供了高性能的计算能力来处理海量数据。

1.HBase简介
前面提到过,HBase是按照BigTable模型实现的,是一个稀疏的、分布式的、持久化的、多维的映射。
部门分享——HBase
那么HBase的特点又有那些呢?
作为大数据组件,它的特点第一就是容量大:
那传统关系型数据库为例,关系型数据库的单表一般不会超过五百万,一旦超过则需要要做分表分库。列数也不会超过30列。
但Hbase单表,就可以有百亿行、百万列。有用数据矩阵,横向,和纵向两个维度。所支持的数据量级也非常具有弹性

面向列:
面向列的存储和权限控制,可以动态增加列。这样的话读的效率也会很高
稀疏性:
为空的列并不占用存储空间,表可以设计的非常稀疏。不必像关系型数据库那样需要预先知道所有列名,然后再进行默认值填充
多版本:
Hbase的每一个列的数据存储有多个Version,也就是timestamp。举个栗子,假如你要存一个人的住址列信息,可能由于搬家,有多个版本变更,所以该列就可以有多个version

拓展性:
底层依赖HDFS,当磁盘空间不足的时候,只需要动态增加datanode,就可以了
高可靠性:
1.WAL机制,保证数据写入的时候不会因为集群异常而导致写入数据丢失
2.Replication机制,保证了在集群出现严重的问题时候,数据不会发生丢失或者损坏
而且Hbase底层使用HDFS,本身也有备份。

读写高性能:
底层的LSM数据结构,RowKey有序排列,这些,架构上的独特设计,使得Hbase写入性能非常高。
而Region切分、主键索引、缓存机制使得Hbase在海量数据下具备一定的随机读取性能,该性能针对Rowkey的查询能够到达毫秒级别

HBase中的基本概念;

HBase中最基本的单位是列。一列或者多列形成一行,并且由唯一的行键(Rowkey)来确定储存。而一个表中包括了若干行,其中每列可能有多个版本,在每一个单元格(cell)中储存了不同的值。
部门分享——HBase
部门分享——HBase

HBase与关系型数据库区别
为什么单拎出来关系型数据库与HBase对比再讲HBase的特性呢,是因为我们中的绝大部分人都用过关系型数据库。那这么比较地讲解,更能更加直观地体现HBase的特点。
部门分享——HBase
HBase与传统的关系数据库的区别主要体现在以下几个方面:
1、数据类型:关系数据库采用关系模型,具有丰富的数据类型和存储方式。大家都建过Mysql表,会设置char varchar dateTime啊等等数据类型。但HBase则采用了更加简单的数据模型,它把数据存储为未经解释的字符串。
2、数据操作:关系数据库会涉及join操作连表查询。HBase操作则不存在复杂的表与表之间的关系。(当然HBase连表操作可以考虑 菲尼克斯Phoenix,但是我们之前也尝试过,效率较很低。如果条件允许,也可以考虑重新迁移一张大表)
3、存储模式:关系数据库是基于行模式存储的。HBase是基于列存储的,
4、数据索引:关系数据库可以有主键、可以有联合主键,也可以再增添索引。HBase只有一个索引——行键。
5、数据维护:在关系数据库中,更新操作会用最新的当前值去替换记录中原来的旧值。而在HBase中执行更新操作时,并不会删除数据旧的版本,而是生成一个新的版本,旧有的版本数据仍然保留。
6、可伸缩性:HBase这类分布式数据库能够轻易地通过在集群中增加或者减少硬件数量来实现性能的伸缩。而关系型数据库很难实现。

1.2 Hbases适用场景
部门分享——HBase
对象存储:不少的头条类、新闻类的的新闻、网页、图片存储在HBase之中

推荐画像:用户画像这种,比较大的稀疏的矩阵。比如蚂蚁的推荐画像、风控系统就是构建在HBase之上

时空数据:主要是轨迹、气象网格之类,滴滴打车的轨迹数据主要存在HBase之中,另外在技术所有大一点的数据量的车联网企业,数据都是存在HBase之中

消息/订单:在银行领域,不少的订单查询底层的存储,另外不少通信、消息同步的应用构建在HBase之上

1.3 Hbases使用场景

Ali-HBase

Ali-HBase作为阿里巴巴的基础存储设施,全面服务于淘宝、天猫、蚂蚁金服、菜鸟、阿里云、高德、优酷等各个领域,满足业务对于大数据分布式存储的基本需求。

我们可以看一下,ali的架构图
部门分享——HBase
滴滴中也充分使用了HBase,滴滴的HBase中主要储存了以下几种数据:

统计结果、报表类数据:主要是运营、运力情况、收入等结果,通常需要配合Phoenix 进行 SQL 查询。数据量较小,对查询的灵活性要求高,延迟要求一般。

原始事实类数据:如订单、司机乘客的 GPS 轨迹、日志等,主要用作在线和离线的数据供给。数据量大,对一致性和可用性要求高,延迟敏感,实时写入,单点或批量查询。

中间结果数据:算法计算过程中的中间数据
线上系统的备份数据:
部门分享——HBase

2.HBase 系统架构
部门分享——HBase
这个就简单说一下吧。HBase底层依赖HDFS,通过DFS Cilent进行HDFS操作。HMaster负责把HRegion分配给HRegionServer,每一个HRegionServer可以包含多个HRegion,多个HRegion共享HLog,HLog用来做灾难恢复。每一个HRegion由一个或多个Store组成,一个Store对应表的一个列族

3.HBase API 特性
部门分享——HBase
API中
CRUD:put方法 get方法 删除方法
扫描:主要是ResultScanner那个类
过滤器下面会稍细讲。
计数器:计数器用来做实时统计,incr方法,返回这个计数器的值

踩过的坑:部门分享——HBase

1.HBase配置
自己在服务器上面装HBase练习,需要注意一下这些内容:

由于HBase是Java编写的,所以至少需要支持当前Java运行时环境。而region服务器的内存主要是服务于内部数据结构,例如memstore和块缓存,因此必须要安装64位操作系统,并使用大于4GB的内存空间。
为了减少对网络I/O的需求,加快处理速度,Hbase大多是与Hadoop安装在同一台服务器的。那么在同一台服务器上运行Hadoop与HBase时,至少会有三个Java进程:(NameNode,TaskTracker,RegionServer)在运行。并且在执行MapReduce作业时,进程数还会激增。因此我们需要保证一定数量的内存、磁盘和CPU资源。

2.Rowkey设计
前面也提到了,HBase只有一个索引——行键。那么Rowkey的设计就成为HBase建表最有技巧的地方之一。
部门分享——HBase
2.1Rowkey设计原则
四大原则:
长度原则、唯一原则、排序原则,散列原则。

长度原则
RowKey本质上是一个二进制码的流,可以是任意字符串,最大长度为64kb,实际应用中一般为10-100byte,以byte[]数组形式保存,一般设计成定长。官方建议是越短越好,最好不要超过16个字节(不过实际应用中我们也是超过了)。

唯一原则
由于RowKey用来唯一标识一行记录,所以必须在设计上保证RowKey的唯一性。

如果向HBase中同一张表插入相同RowKey的数据,则原先存在的数据会被新的数据给覆盖掉

排序原则
HBase会把RowKey按照ASCII码进行自然有序排序,所以反过来在设计RowKey的时候可以根据这个特点来设计完美的RowKey。排序原则就是指利用这个特性。

散列原则
设计出的RowKey需要能够均匀的分布到各个RegionServer上。比如设计RowKey的时候,当Rowkey 是按时间戳的方式递增,就不要将时间放在二进制码的前面,可以将 Rowkey 的高位作为散列字段,由程序循环生成,可以在低位放时间字段,这样就可以提高数据均衡分布在每个Regionserver实现负载均衡的几率。

2.2避免热点现象

在实际操作中,由于RowKey在数据分布上不均匀,可能会导致大量请求访问HBase集群的一个或少数几个节点,造成少数RegionServer的读写请求过多,负载过大,而其他RegionServer负载却很小,这样就造成热点现象。

下一页
3.filter与startRow、stopRow部分键扫描

3.1Filter
比较过滤器:
1.HBase 内置以下7种比较运算符
2.比较器有以下子类可以使用
部门分享——HBase

实际应用中,Rowkey如果是由多个字段由减号、下划线拼接而成。那么此时使用Filter需要注意部分重复的问题,比如部分匹配Rowkey中的版本号,如果使用SubstringComparator FIlter匹配1.0版本号。如果单纯匹配“1.0”这个subString。那么1.0.1,或者0.1.0版本由于都包含1.0这个subString,因此都可能被扫进去。
所以正确的比较器使用是:
如果版本号处于rowkey头尾,可以使用正则比较器,匹配以减号/下划线+1.0来结尾的rowkey。如果位于中间,则可以使用子串比较器,匹配:减号/下划线+1.0+减号/下划线

专用过滤器:
单列值过滤器 行/列前缀过滤器 分页过滤器 时间戳过滤器等等,功能很多。

3.2startRow、stopRow
部门分享——HBase
在scan过程中,可以根据Rowkey设置scan的开始行startRow、结束行stopRow。HBase会将自己的元素按照key的ASCII码排序。

举个例子,如果有以下Rowkey:
5193:1
5193:2
5194:1
51939:1
51942:1

用以下代码进行排序
Scan scan = new Scan();
scan.setStartRow(“5193:”);
scan.setStopRow(“5194:”);

想要取出5193:—5194:中的元素(5193开头的元素),也就是
5193:1
5193:2
51939:1

但是,其实很容易被误取了,上面scan实际查询得到的结果如下:
5193:1
5193:2
51942:1

原因是:与hbase内的scan的方式有关,hbase会将自己的元素按照key的ASCII码排序,
其实也就是说,我们会看见排列的方式如下:
51939:1
5193:1
5193:2
51942:1
5194:1

因此设置startRow、stopRow的时候需要比照ASCII码排序,并且注意scan是包括startRow那一行,但不包含stopRow那一行的

推荐书籍:
《HBase权威指南》

分享后思考:面试常见问题:为什么不建议在Hbase中使用过多列族?