HBase优化面试题

PreCreating Regions

问题 1 :预分区( PreCreating Reg ions )的好处是什么?

参考答案: HBase 预分区(Pre-Splitting)是在创建表时就提前将表的 RowKey 范围划分为多个 Region,而非依赖 HBase 默认的「单 Region 建表、数据达到阈值后自动拆分」机制,核心好处是从根源上解决单 Region 瓶颈、提升集群的读写性能和扩展性。

注意: 预分区的关键是RowKey 的拆分规则(比如按数字范围、字母范围、MD5 哈希前缀拆分),规则不合理会导致分区数据不均,白做预分区。

问题 2 :如何设定 Region 的预分区?

参考答案:

手动设定预分区

复制代码
hbase> create 'table1','info',SPLITS =>['10000','20000','30000','40000']


2

生成16进制序列预分区

复制代码
create 'table2','info',{NUMREGIONS => 15,SPLITALGO => 'HexStringSplit'}

create 'table3','info',SPLITS_FILE =>'splits.txt'

按照文件中设置的规则预分区

创建splits.txt文件内容如下:

复制代码
aaaa
bbbb
cccc
dddd

然后执行:

复制代码
create 'table3','info',SPLITS_FILE =>'splits.txt'

使用JavaAPI创建预分区

java 复制代码
//自定义算法,产生一系列Hash散列值存储在二维数组中
byte[][] splitKeys = 某个散列值函数
//创建HbaseAdmin实例
HBaseAdmin hAdmin = new
HBaseAdmin(HbaseConfiguration.create());
//创建HTableDescriptor实例
HTableDescriptor tableDesc = new
HTableDescriptor(tableName);
//通过HTableDescriptor实例和散列值二维数组创建
带有预分区的Hbase表
hAdmin.createTable(tableDesc, splitKeys);

Column Family****相关优化

问题1:请问在Column Family上有哪些优化的方案?

参考答案:

  1. 合理设置列族数量
  2. 设置查询缓存In Memory,创建表的时候,可以通过HColumnDescriptor.setInMemory(true)将表对应列族下的数据放到RegionServer的缓存中,保证在读取的时候被cache命中。用在读取比较频繁的列族上。
    3. 设置Cell保存数据的版本数Max Version,创建表的时候,可以通过HColumnDescriptor.setMaxVersions(int maxVersions)设置表中数据的最大版本,如果只需
    要保存最新版本的数据,那么可以设置setMaxVersions(1)。
    4. 设置数据的有效时间Time To Live,创建表的时候,可以通过HColumnDescriptor类对象调
    用setTimeToLive(int timeToLive)设置表中对应列族下数据的存储生命期,过期数据将自动被
    删除,例如如果只需要存储最近两天的数据,那么可以设置setTimeToLive(2 * 24 * 60 *
    60),单位秒。默认永久保存(TTL => 'FOREVER')

问题2:请详细说明如何合理设置列族数量?

**参考答案:**不要在一张表里定义太多的column family。目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,它邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O。

一个region由多个store组成,一个store对应一个CF(列族)

Row Key

HBase中row key用来检索表中的记录,支持以下三种方式:

  1. 通过单个row key访问:即按照某个row key键值进行get操作;
    2. 通过row key的range进行scan:即通过设置startRowKey和stopRowKey,在这个范围内进行
    扫描
  2. 全表扫描:即直接扫描整张表中所有行记录。

在HBase中, row key可以是任意字符串,最大长度64KB,实际应用中一般为10~100bytes,存为byte[]字节数组,一般设计成定长的。

row key是按照字典序存储,因此,设计row key时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。

举个例子:如果最近写入HBase表中的数据是最可能被访问的,可以考虑将时间戳作为row key的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE - timestamp作为row key,这样能保证新写入的数据在读取时可以被快速命中。

问题 1 :设计 rowkey 的主要目的是什么?

参考答案: 一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。

问题 2: 请问 rowkey 常用的设计方案有哪些?

参考答案:

生成随机数、 hash 、散列值

比如:

原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd

原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913

在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。

字符串反转

当 RowKey 以「连续递增 / 递减的字符串前缀」为主(如手机号、时间戳、自增 ID、固定前缀的业务号)时,通过反转字符串能彻底解决 HBase 的写入热点问题。

本质原因是:HBase 的 Region 是按RowKey 的字典序连续划分 的,若 RowKey 前缀连续,所有写入请求会集中在最后一个 Region (字典序的最大区间),形成写入热点 (单 Region 扛所有写入压力);而反转字符串后,原连续的前缀会变成分散的后缀,RowKey 的字典序分布会变得均匀,写入请求能分散到多个 Region,实现并行写入。

20500123000001转成1000032100502

20500123000002转成2000032100502

这样也可以在一定程度上散列逐步put进来的数据。

字符串拼接

20500123000001_e15a

20500613000001_a6b2

写表操作优化

问题 1 :写表操作相关的优化方案有哪些?

参考答案:

优先选择批量写。

通过调用HTable.put(Put)方法可以将一个指定的row key记录写入HBase,同样HBase提供了另一个方法:通过调用HTable.put(List)方法可以将指定的row key列表,批量写入多行记录,这样做的好处是批量执行,只需要一次网络I/O开销,这对于对数据实时性要求高,网络传输RTT高的情景下可能带来明显的性能提升。

如果无法使用批量写,只能使用put(put)方法,也可以通过调整HTable参数进行优化设置

1.Write Buffer

通过调用HTable.setWriteBufferSize(writeBufferSize)方法可以设置HTable客户端的写buffer大小,如果新设置的buffer小于当前写buffer中的数据时, buffer将会被flush到服务端。其中,writeBufferSize的单位是 byte字节数,可以根据实际写入数据量的多少来设置该值。默认的大小是2MB(即2097 152字节),这个大小比较适中,一般用户插入HBase中的数据都相当小,即每次插入的数据都远小于缓冲区的大小。如果需要存储交到的数据,通常需要考虑增大这个数值,从而允许客户端更高效地将一定数量的数据组成一组,通过一个RPC请求来执行。

2.Auto Flush

通过调用HTable.setAutoFlushTo(false)方法可以将HTable写客户端的自动flush关闭,这样可以批量写入数据到HBase,而不是有一条put就执行一次更新,只有当put填满客户端写缓存时,才实际向HBase服务端发起写请求。默认情况下auto flush是开启的。

3.WAL Flag

在HBae中,客户端向集群中的RegionServer提交数据时(Put/Delete操作),首先会先写WAL(Write Ahead Log)日志(即HLog ,一个RegionServer上的所有Region共享一个HLog),只有当WAL日志写成功后,再接着写MemStore,然后客户端被通知提交数据成功;如果写WAL日志失败,客户端则被通知提交失败。这样做的好处是可以做到RegionServer宕机后的数据恢复。因此,对于相对不太重要的数据,可以在 Put/Delete操作时,通过调用Put.setWriteToWAL(false)或Delete.setWriteToWAL(false)函数,放弃写WAL日志,从而提高数据写入的性能。值得注意的是:谨慎选择关闭WAL日志,因为这样的话,一旦RegionServer宕机, Put/Delete的数据将会无法根据WAL日志进行恢复。

读表操作优化

问题 1 :从 HBase 应用程序设计与开发的角度,总结几种常用 的读表操作相关的优化方案 ?

参考答案:

  1. 在单条查和批量查都可以用时优先选择批量读。通过调用HTable.get(Get)方法可以根据一个指定的row key获取一行记录,同样HBase提供了另一个方法:通过调用HTable.get(List)方法可以根据一个指定的row key列表,批量获取多行记录,这样做的好处是批量执行,只需要一次网络 I/O开销,这对于对数据实时性要求高而且网络传输RTT高的情景下可能带来明显的性能提升。

  2. scan时指定需要的列族与列描述符,可以减少网络传输数据量,否则默认scan操作会返回整行所有Column Family的数据。

  3. 通过scan取完数据后,记得要关闭ResultScanner,否则RegionServer可能会出现问题(对应的Server资源无法释放)。

  4. 优化服务器端BlockCache内存占比。

  5. 客户端缓存查询结果。

  6. HBase scanner一次从服务端抓取的数据条数,默认情况下一次一条。通过将其设置成一个合理的值,可以减少scan过程中next()的时间开销,代价是scanner需要通过客户端的内存来维持这些被cache的行记录。

有三个地方可以进行配置:

a. 在HBase的conf配置文件中通过hbase.client.scanner.caching进行配置;

b.通过调用HTable.setScannerCaching(int scannerCaching)进行配置;

c.通过调用scan.setCaching(int caching)进行配置。

三者的优先级从上到下越来越高。

问题 2 :简述使用客户端缓存查询结果后的查询流程?

参考答案:

对于频繁查询HBase的应用场景,可以考虑在应用程序中做缓存,当有新的查询请求时,首先在缓存中查找,如果存在则直接返回,不再查询HBase;否则对HBase发起读请求查询,然后在应用程序中将查询结果缓存起来。至于缓存的替换策略,可以考虑LRU (least recently used最近最少使用的)等常用的策略。

问题 3 :简述你对 BlockCache 的理解有哪些?

参考答案:

  1. HBase上Regionserver的内存分为两个部分, 一部分作为Memstore,主要用来写;另外一部分作为BlockCache,主要用于读。

  2. 写请求会先写入Memstore , Regionserver会给每个region提供一个Memstore,当Memstore满64MB以后,会启动 flush刷新到磁盘。当Memstore的总大小超过限制时(heapsize * hbase.regionserver.global.memstore.upperLimit * 0.9),会强行启动flush进程,从最大的Memstore开始flush直到低于限制。

  3. 读请求先到Memstore中查数据,查不到就到BlockCache中查,再查不到就会到磁盘上读,并把读的结果放入BlockCache。由于BlockCache采用的是LRU策略,因此BlockCache达到上限(heapsize * hfile.block.cache.size * 0.85)后,会启动淘汰机制,淘汰掉最老的一批数据。

  4. 一个Regionserver上有一个BlockCache和N个Memstore,它们的大小之和不能大于等于heapsize * 0.8,否则HBase不能启动。默认BlockCache为0.2,而Memstore为0.4。对于注重读响应时间的系统,可以将 BlockCache设大些,比如设置BlockCache=0.4,Memstore=0.39 ,以加大缓存的命中率。

相关推荐
PPPPickup2 小时前
easymall---管理后端商品属性管理
java
人道领域2 小时前
SSM框架从入门到入土(SpringFrameWork)
java·spring boot·tomcat
源力祁老师2 小时前
深入解析 Odoo 中 default_get 方法的功能
java·服务器·前端
团子的二进制世界2 小时前
Sentinel-服务保护(限流、熔断降级)
java·开发语言·sentinel·异常处理
NWU_白杨2 小时前
多线程安全与通信问题
java
sheji34162 小时前
【开题答辩全过程】以 工业车辆维修APP设计与实现为例,包含答辩的问题和答案
java
虫小宝2 小时前
淘客系统的容灾演练与恢复:Java Chaos Monkey模拟节点故障下的服务降级与快速切换实践
java·开发语言
yxm26336690812 小时前
【洛谷压缩技术续集题解】
java·开发语言·算法
键盘帽子2 小时前
多线程情况下长连接中的session并发问题
java·开发语言·spring boot·spring·spring cloud