十五、HBase 宕机如何处理?
宕机分为 HMaster 宕机和 HRegisoner 宕机.
如果是 HRegisoner 宕机,HMaster 会将其所管理的 region 重新分布到其他活动的 RegionServer 上,由于数据和日志都持久在 HDFS 中,该操作不会导致数据丢失,所以数据的一致性和安全性是有保障的。
如果是 HMaster 宕机, HMaster 没有单点问题, HBase 中可以启动多个HMaster,通过 Zookeeper 的 Master Election 机制保证总有一个 Master 运行。即ZooKeeper 会保证总会有一个 HMaster 在对外提供服务。
十六、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,如果有则进行恢复
十七、hbase写数据 和 读数据过程
获取region存储位置信息
写数据和读数据一般都会获取hbase的region的位置信息。大概步骤为:
- 从zookeeper中获取.ROOT.表的位置信息,在zookeeper的存储位置为/hbase/root-region-server;
- 根据.ROOT.表中信息,获取.META.表的位置信息;
- META.表中存储的数据为每一个region存储位置;
向hbase表中插入数据
hbase中缓存分为两层:Memstore 和 BlockCache:
- 首先写入到 WAL文件 中,目的是为了数据不丢失;
- 再把数据插入到 Memstore缓存中,当 Memstore达到设置大小阈值时,会进行flush进程;
- flush过程中,需要获取每一个region存储的位置。
从hbase中读取数据
BlockCache 主要提供给读使用。读请求先到 Memtore中查数据,查不到就到 BlockCache 中查,再查不到就会到磁盘上读,并把读的结果放入 BlockCache 。
BlockCache 采用的算法为 LRU(最近最少使用算法),因此当 BlockCache 达到上限后,会启动淘汰机制,淘汰掉最老的一批数据。
一个 RegionServer 上有一个 BlockCache 和N个 Memstore,它们的大小之和不能大于等于 heapsize * 0.8,否则 hbase 不能启动。默认 BlockCache 为 0.2,而 Memstore 为 0.4。对于注重读响应时间的系统,应该将 BlockCache 设大些,比如设置BlockCache =0.4,Memstore=0.39。这会加大缓存命中率。
十八、HBase优化方法
优化手段主要有以下四个方面
1)减少调整
减少调整这个如何理解呢?HBase中有几个内容会动态调整,如region(分区)、HFile,所以通过一些方法来减少这些会带来I/O开销的调整。
Region
如果没有预建分区的话,那么随着region中条数的增加,region会进行分裂,这将增加I/O开销,所以解决方法就是根据你的RowKey设计来进行预建分区,减少region的动态分裂。
HFile
HFile是数据底层存储文件,在每个memstore进行刷新时会生成一个HFile,当HFile增加到一定程度时,会将属于一个region的HFile进行合并,这个步骤会带来开销但不可避免,但是合并后HFile大小如果大于设定的值,那么HFile会重新分裂。为了减少这样的无谓的I/O开销,建议估计项目数据量大小,给HFile设定一个合适的值。
2)减少启停
数据库事务机制就是为了更好地实现批量写入,较少数据库的开启关闭带来的开销,那么HBase中也存在频繁开启关闭带来的问题。
1、关闭Compaction,在闲时进行手动Compaction
因为HBase中存在Minor Compaction和Major Compaction,也就是对HFile进行合并,所谓合并就是I/O读写,大量的HFile进行肯定会带来I/O开销,甚至是I/O风暴,所以为了避免这种不受控制的意外发生,建议关闭自动Compaction,在闲时进行compaction
2、批量数据写入时采用BulkLoad
如果通过HBase-Shell或者JavaAPI的put来实现大量数据的写入,那么性能差是肯定并且还可能带来一些意想不到的问题,所以当需要写入大量离线数据时建议使用BulkLoad
3)减少数据量
虽然我们是在进行大数据开发,但是如果可以通过某些方式在保证数据准确性同时减少数据量,何乐而不为呢?
1、开启过滤,提高查询速度
开启BloomFilter,BloomFilter是列族级别的过滤,在生成一个StoreFile同时会生成一个MetaBlock,用于查询时过滤数据
2、使用压缩:一般推荐使用Snappy和LZO压缩
4)合理设计
在一张HBase表格中RowKey和ColumnFamily的设计是非常重要,好的设计能够提高性能和保证数据的准确性
1、RowKey设计:应该具备以下几个属性
- 散列性:散列性能够保证相同相似的rowkey聚合,相异的rowkey分散,有利于查询
- 简短性:rowkey作为key的一部分存储在HFile中,如果为了可读性将rowKey设计得过长,那么将会增加存储压力
- 唯一性:rowKey必须具备明显的区别性
- 业务性:举些例子
假如我的查询条件比较多,而且不是针对列的条件,那么rowKey的设计就应该支持多条件查询
如果我的查询要求是最近插入的数据优先,那么rowKey则可以采用叫上Long.Max-时间戳的方式,这样rowKey就是递减排列
2、列族的设计
列族的设计需要看应用场景
多列族设计的优劣
优势:
HBase中数据时按列进行存储的,那么查询某一列族的某一列时就不需要全盘扫描,只需要扫描某一列族,减少了读I/O;
其实多列族设计对减少的作用不是很明显,适用于读多写少的场景。
劣势:
降低了写的I/O性能。原因如下:数据写到store以后是先缓存在memstore中,同一个region中存在多个列族则存在多个store,每个store都一个memstore,当其实memstore进行flush时,属于同一个region 的 store 中的 memstore 都会进行 flush,增加I/O开销。
十九、为什么不建议在 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频繁的问题。
二十、Region 如何预建分区?
预分区的目的主要是在创建表的时候指定分区数,提前规划表有多个分区,以及每个分区的区间范围,这样在存储的时候 rowkey 按照分区的区间存储,可以避免 region 热点问题。
通常有两种方案:
方案 1:shell 方法
create 'tb_splits', {NAME => 'cf',VERSIONS=> 3},{SPLITS => ['10','20','30']}
方案 2: JAVA 程序控制
- 取样,先随机生成一定数量的 rowkey,将取样数据按升序排序放到一个集合里;
- 根据预分区的 region 个数,对整个集合平均分割,即是相关的 splitKeys;
- HBaseAdmin.createTable(HTableDescriptor tableDescriptor,byte[][]splitkeys)可以指定预分区的 splitKey,即是指定 region 间的 rowkey 临界值。
二十一、如何提高 HBase 客户端的读写性能?请举例说明(☆☆☆☆☆)
- 开启 bloomfilter 过滤器,开启 bloomfilter 比没开启要快 3、4 倍
- Hbase 对于内存有特别的需求,在硬件允许的情况下配足够多的内存给它
- 通过修改 hbase-env.sh 中的
export HBASE_HEAPSIZE=3000 #这里默认为 1000m
- 增大 RPC 数量
通过修改 hbase-site.xml 中的 hbase.regionserver.handler.count 属性,可以适当的放大RPC 数量,默认值为 10 有点小
二十一、直接将时间戳作为行健,在写入单个 region 时候会发生热点问题,为什么呢?(☆☆☆☆☆)
region 中的 rowkey 是有序存储,若时间比较集中。就会存储到一个 region 中,这样一个 region 的数据变多,其它的 region 数据很少,加载数据就会很慢,直到 region 分裂,此问题才会得到缓解。
二十二、请描述如何解决 HBase 中 region 太小和 region 太大带来的冲突?
Region 过大会发生多次compaction,将数据读一遍并重写一遍到 hdfs 上,占用io,region过小会造成多次 split,region 会下线,影响访问服务,最佳的解决方法是调整 hbase.hregion.max.filesize 为 256m。
二十三、解释一下布隆过滤器原理(☆☆☆☆☆)?
Bloom Filter是HBASE用来优化读性能的手段,我们经常会去判断一个元素是否在一个集合中,当数据量比较小的时候,我们可以用Java的HashSet,Java的HashSet是创建一个散列数组,把原来的元素以某种规则映射到散列数组中特定的位置。但如果我们需要判断的元素个数非常大,会导致散列数组非常大,这个时候Bloom Filter就可以发挥作用。问题引出来了,就是我们要用尽可能小的空间,在大数据场景下实现过滤。接下来我会从作用、算法原理、问题、公式推导、hbase应用来介绍Bloom Filter。
作用
Bloom Filter的作用就是过滤。Bloom Filter过滤掉的数据,一定不在集合中;未被过滤的数据可能在集合中,也可能不在。
算法流程
首先需要k个hash函数,每个函数可以把key散列成为1个整数
初始化一个长度为n比特的数组,每个比特位初始化为0
当某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位从0置为1,如果已经是1则不变。
判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。
下图展示了Bloom Filter的原理
二十四、HBase与传统关系型数据库(如MySQL)的区别
数据类型:没有数据类型,都是字节数组(有一个工具类Bytes,将java对象序列化为字节数组)。
数据操作:HBase只有很简单的插入、查询、删除、清空等操作,表和表之间是分离的,没有复杂的表和表之间的关系,而传统数据库通常有各式各样的函数和连接操作。
存储模式:Hbase适合于非结构化数据存储,基于列存储而不是行。
数据维护:HBase的更新操作不应该叫更新,它实际上是插入了新的数据,而传统数据库是替换修改
时间版本:Hbase数据写入cell时,还会附带时间戳,默认为数据写入时RegionServer的时间,但是也可以指定一个不同的时间。数据可以有多个版本。
可伸缩性:Hbase这类分布式数据库就是为了这个目的而开发出来的,所以它能够轻松增加或减少硬件的数量,并且对错误的兼容性比较高。而传统数据库通常需要增加中间层才能实现类似的功能
二十五、另外的一些面试题
1、读写性能对比(读快还是写快)
2、Hbase的设计有什么心得?
3、Hbase的操作是用的什么API还是什么工具?
4、你们hbase里面是存一些什么数据
5、知道spark怎么读hbase吗?
6、做过hbase的二级索引吗?
7、Hbase的PUT的一个过程
8、什么时候适合使用HBase(应用场景)
半结构化或非结构化数据: 对于数据结构字段不够确定或杂乱无章非常难按一个概念去进行抽取的数据适合用HBase,因为HBase支持动态添加列。 记录很稀疏: RDBMS的行有多少列是固定的。为null的列浪费了存储空间。而如上文提到的,HBase为null的Column不会被存储,这样既节省了空间又提高了读性能。 多版本号数据: 依据Row key和Column key定位到的Value能够有随意数量的版本号值,因此对于须要存储变动历史记录的数据,用HBase是很方便的。比方某个用户的Address变更,用户的Address变更记录也许也是具有研究意义的。 仅要求最终一致性: 对于数据存储事务的要求不像金融行业和财务系统这么高,只要保证最终一致性就行。(比如HBase+elasticsearch时,可能出现数据不一致) 高可用和海量数据以及很大的瞬间写入量: WAL解决高可用,支持PB级数据,put性能高 索引插入比查询操作更频繁的情况。比如,对于历史记录表和日志文件。(HBase的写操作更加高效) 业务场景简单: 不需要太多的关系型数据库特性,列入交叉列,交叉表,事务,连接等。burong