1、HBase
是什么?
Hbase
一个分布式的基于列式存储的数据库,基于Hadoop
的hdfs
存储,zookeeper
进行管理;Hbase
适合存储半结构化或非结构化数据,对于数据结构字段不够确定或者杂乱无章很难按一个概念去抽取的数据;Hbase
为null
的记录不会被存储;- 基于的表包含
rowkey
,时间戳,和列族。新写入数据时,时间戳更新,同时可以查询到以前的版本; Hbase
是主从架构。hmaster
作为主节点,hregionserver
作为从节点。
2、HBase
的特点
- 大: 一个表可以有数十亿行,上百万列;
- 无模式: 每行都有一个可排序的主键和任意多的列,列可以根据需要动态的增加,同一张表中不同的行可以有截然不同的列;
- 面向列: 面向列(族)的存储和权限控制,列(族)独立检索;
- 稀疏: 空(
null
)列并不占用存储空间,表可以设计的非常稀疏; - 数据多版本: 每个单元中的数据可以有多个版本,默认情况下版本号自动分配,是单元格插入时的时间戳;
- 数据类型单一:
Hbase
中的数据都是字符串,没有类型。
3、HBase
和 Hive
的区别?
HBase | Hive | |
类型 | 列式数据库 | 数据仓库 |
内部机制 | 数据库引擎 | MapReduce |
增删查改 | 都支持 | 只支持导入和查询 |
Schema | 只需要预先定义列族,不需要具体到列,列可以动态修改 | 需要预先定义表格 |
应用场景 | 实时 | 离线处理 |
特点 | 以K-V 形式存储 | 类SQL |
Hive
和 Hbase
是两种基于 Hadoop
的不同技术–Hive
是一种类 SQL
的引擎,并且运行 MapReduce
任务,Hbase
是一种在 Hadoop
之上的NoSQL
的Key/value
数据库。当然,这两种工具是可以同时使用的。就像用 Google 来搜索,用 FaceBook
进行社交一样,Hive
可以用来进行统计查询,Hbase
可以用来进行实时查询,数据也可以从 Hive
写到 Hbase
,设置再从 Hbase
写回 Hive
。
4、HBase
适用于怎样的情景?
- 半结构化或非结构化数据
- 记录非常稀疏
- 多版本数据
- 超大数据量
5、HBase
的 rowKey
的设计原则?
-
RowKey
长度规则Rowkey
是一个二进制码流,Rowkey
的长度被很多开发者建议说设计在 10~100 个字节,不过建议是越短越好,不要超过 16 个字节。 原因如下:- 数据的持久化文件
HFile
中是按照KeyValue
存储的,如果Rowkey
过长比如 100个字节,1000 万列数据光Rowkey
就要占用 100*1000 万=10 亿个字节,将近 1G 数据,这会极大影响HFile
的存储效率; MemStore
将缓存部分数据到内存,如果Rowkey
字段过长内存的有效利用率会降低,系统将无法缓存更多的数据,这会降低检索效率。因此Rowkey
的字节长度越短越好;- 目前操作系统是都是 64 位系统,内存 8 字节对齐。控制在 16 个字节,8 字节的整数倍利用操作系统的最佳特性。
- 数据的持久化文件
-
Rowkey
散列规则如果
Rowkey
是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将Rowkey
的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个Regionserver
实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个RegionServer
上堆积的热点现象,这样在做数据检索的时候负载将会集中在个别RegionServer
,降低查询效率。 -
Rowkey
唯一规则必须在设计上保证其唯一性。
6、HBase
中 scan
和get
的功能以及实现的异同?
- 按指定
Rowkey
获取唯一一条记录,get
方法(org.apache.hadoop.hbase.client.Get
)Get
的方法处理分两种:设置了ClosestRowBefore
和没有设置ClosestRowBefore
的rowlock
。主要是用来保证行的事务性,即每个get
是以一个row
来标记的。一个row
中可以有很多family
和column
; - 按指定的条件获取一批记录,
scan
方法(org.apache.Hadoop.hbase.client.Scan
)实现条件查询功能使用的就是scan
方式。
7、简述 HBase
中 compact
用途是什么,什么时候触发,分为哪两种,有什么区别,有哪些相关配置参数?
在 HBase
中每当有 memstore
数据 flush
到磁盘之后,就形成一个 storefile
,当 storeFile
的数量达到一定程度后,就需要将 storefile
文件来进行 compaction
操作。Compact
的作用:
-
合并文件
-
清除过期,多余版本的数据
-
提高读写数据的效率
HBase
中实现了两种compaction
的方式:minor and major
。 这两种 compaction
方式的区别是:
Minor
操作只用来做部分文件的合并操作以及包括minVersion=0
并且设置ttl
的过期版本清理,不做任何删除数据、多版本数据的清理工作;Major
操作是对Region
** 下的HStore
下的所有StoreFile
执行合并操作**,最终的结果是整理合并出一个文件。
8、HBase
优化?
- 高可用: 在
HBase
中Hmaster
负责监控RegionServer
的生命周期,均衡RegionServer
的负载,如果Hmaster
挂掉了,那么整个HBase
集群将陷入不健康的状态,并且此时的工作状态并不会维持太久。所以HBase
支持对Hmaster
的高可用配置。 - 预分区: 每一个
region
维护着startRow
与endRowKey
,如果加入的数据符合某个region
维护的rowKey
范围,则该数据交给这个region
维护。那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,以提高HBase
性能。 - RowKey 设计: 一条数据的唯一标识就是
rowkey
,那么这条数据存储于哪个分区,取决于rowkey
处于哪个一个预分区的区间内,设计rowkey
的主要目的 ,就是让 数据均匀的分布于所有的region
中,在一定程度上防止数据倾斜。接下来我们就谈一谈rowkey
常用的设计方案 - 内存优化:
HBase
操作过程中需要大量的内存开销,毕竟Table
是可以缓存在内存中的,一般会分配整个可用内存的 70%给HBase
的 Java 堆。但是不建议分配非常大的堆内存,因为GC
过程持续太久会导致RegionServer
处于长期不可用状态,一般 16~48G 内存就可以了,如果因为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死。
9、HRegionServer
宕机如何处理?
ZooKeeper
会监控HRegionServer
的上下线情况,当ZK
发现某个HRegionServer
宕机之后会通知HMaster
进行失效备援;- 该
HRegionServer
会停止对外提供服务,就是它所负责的region
暂时停止对外提供服务; HMaster
会将该HRegionServer
所负责的region
转移到其他HRegionServer
上,并且会对HRegionServer
上存在memstore
中还未持久化到磁盘中的数据进行恢复;- 这个恢复的工作是由
WAL
重播来完成,这个过程如下:WAL
实际上就是一个文件,存在/hbase/WAL/
对应RegionServer
路径下。- 宕机发生时,读取该
RegionServer
所对应的路径下的WAL
文件,然后根据不同的region
切分成不同的临时文件recover.edits
。 - 当
region
被分配到新的RegionServer
中,RegionServer
读取region
时会进行是否存在recover.edits
,如果有则进行恢复。
10、HBase
读写流程
10.1、读流程
创建连接同写流程。
- 创建
Table
对象发送get
请求。 - 优先访问
Block Cache
,查找是否之前读取过,并且可以读取HFile
的索引信息和布隆过滤器。 - 不管读缓存中是否已经有数据了(可能已经过期了),都需要再次读取写缓存和
store
中的文件。 - 最终将所有读取到的数据合并版本,按照
get
的要求返回即可。
10.2、写流程
写流程顺序正如 API
编写顺序,首先创建 HBase
的重量级连接:
- 首先访问
zookeeper
,获取hbase:meta
表位于哪个Region Server
; - 访问对应的
Region Server
,获取hbase:meta
表,将其缓存到连接中,作为连接属性MetaCache
,由于Meta
表格具有一定的数据量,导致了创建连接比较慢; - 之后使用创建的连接获取
Table
,这是一个轻量级的连接,只有在第一次创建的时候会检查表格是否存在访问RegionServer
,之后在获取Table
时不会访问RegionServer
; - 调用
Table
的put
方法写入数据,此时还需要解析RowKey
,对照缓存的MetaCache
,查看具体写入的位置有哪个RegionServer
; - 将数据顺序写入(追加)到
WAL
,此处写入是直接落盘的,并设置专门的线程控制WAL
预写日志的滚动(类似Flume
); - 根据写入命令的
RowKey
和ColumnFamily
查看具体写入到哪个MemStory
,并且在MemStory
中排序; - 向客户端发送
ack
; - 等达到
MemStore
的刷写时机后,将数据刷写到对应的store
中。
11、如何提高 HBase
客户端的读写性能?
- 开启
bloomfilter
过滤器,开启bloomfilter
比没开启要快 3、4 倍; Hbase
对于内存有特别的需求,在硬件允许的情况下配足够多的内存给它;- 通过修改
hbase-env.sh
中的export HBASE_HEAPSIZE=3000
这里默认为 1000m
- 增大
RPC
数量,通过修改hbase-site.xml
中的hbase.regionserver.handler.count
属性,可以适当的放大RPC
数量,默认值为 10 有点小。
12、直接将时间戳作为行健,在写入单个 region
时候会发生热点问题,为什么呢?
region
中的 rowkey
是有序存储,若时间比较集中。就会存储到一个 rregion
中,这样一个 region
的数据变多,其它的 region
数据很少,加载数据就会很慢,直到 region
分裂,此问题才会得到缓解。
请描述如何解决 HBase
中 region
太小和 region
太大带来的冲突?
Region
过大会发生多次compaction
,将数据读一遍并重写一遍到 hdfs
上,占用io
,region
过小会造成多次 split
, region
会下线,影响访问服务,最佳的解决方法是调整hbase.hregion.max.filesize
为 256m。
13、hbase如何导入数据?
-
通过
HBase API
进行批量写入数据; -
使用
Sqoop
工具批量导数到HBase集群; -
使用
MapReduce
批量导入; -
HBase BulkLoad
的方式。
14、HBase
的存储结构?
Hbase
中的每张表都通过行键 (rowkey
) 按照一定的范围被分割成多个子表(HRegion
),默认一个 HRegion
超过 256M 就要被分割成两个,由 HRegionServer
管理,管理哪些 HRegion
由 Hmaster
分配。 HRegion
存取一个子表时,会创建一个 HRegion
对象,然后对表的每个列族 (Column Family
) 创建一个 store
实例, 每个 store
都会有 0个或多个StoreFile
与之对应,每个 StoreFile
都会对应一个 HFile
, HFile
就是实际的存储文件,因此,一个 HRegion
还拥有一个 MemStore
实例。
15、解释下 HBase
实时查询的原理
实时查询,可以认为是从内存中查询,一般响应时间在 1 秒内。HBase
的机制是数据先写入到内存中,当数据量达到一定的量(如 128M),再写入磁盘中, 在内存中,是不进行数据的更新或合并操作的,只增加数据,这使得用户的写操作只要进入内存中就可以立即返回,保证了 HBase I/O
的高性能。
16、HBase
优化方案
17、为什么不建议在 HBase
中使用过多的列族?
在Hbase
的表中,每个列族对应 Region
中的一个**Store
,Region
**的大小达到阈值时会分裂,因此如果表中有多个列族,则可能出现以下现象:
一个Region
中有多个Store
,如果每个CF
的数据量分布不均匀时,比如CF1
为100万,CF2
为1万,则Region
分裂时导致CF2
在每个Region
中的数据量太少,查询CF2
时会横跨多个Region
导致效率降低。
如果每个CF
的数据分布均匀,比如CF1
有50万,CF2
有50万,CF3
有50万,则Region
分裂时导致每个CF
在Region
的数据量偏少,查询某个CF
时会导致横跨多个Region
的概率增大。
多个CF
代表有多个Store
,也就是说有多个MemStore(2MB)
,也就导致内存的消耗量增大,使用效率下降。
Region
中的 缓存刷新和压缩是基本操作,即一个CF
出现缓存刷新或压缩操作,其它CF
也会同时做一样的操作,当列族太多时就会导致IO
频繁的问题。