HBase 热点问题——rowkey散列和预分区设计
热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他region,由于主机无法服务其他region的请求,造成资源浪费。设计良好的数据访问模式以使集群被充分,均衡的利用。
数据倾斜:Hbase可以被划分为多个Region,但是默认创建时只有一个Region分布在集群的一个节点上,数据一开始时都集中在这个Region,也就是集中在这一个节点上,就算region存储达到临界值时被划分,数据也是存储在少数节点上。这就是数据倾斜
随机散列与预分区二者结合起来,是比较完美的。预分区一开始就预建好了一部分region,这些region都维护着自己的start-end keys,在配合上随机散列,写数据能均衡的命中这些预建的region,就能解决上面的那些缺点,大大提供性能。
1. 预分区
1.1 HBase的预分区概述
默认分区:
HBase表被创建时,只有1个Region,当一个Region过大达到默认的阀值时(默认10GB大小),HBase中该Region将会进行split,分裂为2个Region,以此类推。
缺点:
表在进行split的时候,会耗费大量的资源,频繁的分区对HBase的性能有巨大的影响。所以,HBase提供了预分区功能,即用户可以在创建表的时候对表按照一定的规则分区。
2. HBase预分区的作用
避免HBase经常split,产生不必要的资源消耗,提高HBase的性能
3. HBase预分区的方法
- HBase Shell
create 'user1',{NAME=>'f'},{NAME=>'d'},SPLITS=>['0|','1|','3|','4|']
create 'user1', 'f', SPLITS => ['1|', '2|', '3|', '4|']
- HBase Shell(通过读取split文件)
create 'user2',{NAME=>'f'},{NAME=>'d'},SPLITS_FILE=>'/data/hbaseSplit.txt'
hbaseSplit.txt内容
> cat hbaseSplit.txt
|
|
|
|
- HBase Java API
object HbaseUtil { def main(args: Array[String]): Unit = {
val conf = HBaseConfiguration.create()
conf.set("hbase.zookeeper.quorum","192.168.1.11,192.168.1.12,192.168.1.13")
conf.set("hbase.zookeeper.property.clientPort", "")
conf.set("zookeeper.znode.parent", "/hbase")
conf.set("hbase.master", "192.168.1.11:16010")
val connection = ConnectionFactory.createConnection(conf)
val admin = connection.getAdmin
val colFamily = List("info", "desc")
val tableName = "user3"
val splitKeys = Array(
Bytes.toBytes("0|"),
Bytes.toBytes("1|"),
Bytes.toBytes("2|"),
Bytes.toBytes("3|"),
Bytes.toBytes("4|")
) if (admin.tableExists(TableName.valueOf(tableName))) { println("表已存在!")
} else { val descriptor = new HTableDescriptor(TableName.valueOf(tableName))
colFamily.foreach(x => descriptor.addFamily(new HColumnDescriptor(x)))
admin.createTable(descriptor, splitKeys)
}
admin.close()
connection.close()
}
}
2.随机散列
1. 固定散列值
- HBase Shell
create 'user1',{NAME=>'f'},{NAME=>'d'},SPLITS=>['0|','1|','3|','4|','5|','6|','7|','8|','9|']
说明:固定值散列,后面添加"|",因为|编码值最大
2. 哈希(散列)
Hbase自带了两种pre-split的算法,分别是 HexStringSplit 和 UniformSplit 。
- HexStringSplit
如果我们的row key是十六进制的字符串作为前缀的,称之为HexStringSplit就比较适合用HexStringSplit,作为pre-split的算法。例如,我们使用HexHash(prefix)作为row key的前缀,其中Hexhash为最终得到十六进制字符串的hash算法,我们通常手动指定SPLITS来指定预分区,我们也可以用我们自己的split算法。
create 'test',{NAME=>'f',COMPRESSION=>'SNAPPY'},{NUMREGIONS => , SPLITALGO => 'HexStringSplit'}
put时可以使用
MD5Hash.getMD5AsHex(Bytes.toBytes(str));
UniformSplit
如果我们的row key使用byte来作为前缀,称之为UniformSplit,如果某个hbase的表查询只是以随机查询为主,可以用UniformSplit的方式进行,它是按照原始byte值(从0x00~0xFF)右边以00填充。以这种方式分区的表在插入的时候需要对rowkey进行一个技巧性的改造, 比如原来的rowkey为rawStr,则需要对其取hashCode,然后进行按照比特位反转后放在最初rowkey串的前面。可以充分利用Bytes这个工具类来做。
create 'test', { NAME => 'f', TTL => , DATA_BLOCK_ENCODING => 'PREFIX' }, {NUMREGIONS => , SPLITALGO => 'UniformSplit'}
使用SPLITALGO => 'UniformSplit'方式来建表是没有指定startKey和endKey的,也就是说采用这种方式建表就是基于ancil的256个值的范围来平均切分10个预分区的(由于anscil一共256个值,因此采用这种方式做预分区建表最多支持256个预分区,不过在写入数据后,256预分区可以再内部做二次切分),采用这种做法导致在Scan查询的时候就需要开256个Scan线程取扫描数据并返回最终的结果,好处就是统一了整个rowkey的范围,取名UniformSplit大概也是这个意思。
put数据时,可以充分利用Bytes这个工具类
byte[] rowKey = Bytes.add(Bytes.toBytes(Integer.reverse(Integer.valueOf(Integer.valueOf(i).hashCode()))), Bytes.toBytes(i));
3.强制split
HBase 允许客户端强制执行split,在hbase shell中执行以下命令:
split 'forced_table', 'b'
其中:forced_table 为要split的table , ‘b’ 为split 点
HBase 热点问题——rowkey散列和预分区设计的更多相关文章
- rowkey散列和预分区设计解决hbase热点问题(数据倾斜)
Hbase的表会被划分为1....n个Region,被托管在RegionServer中.Region二个重要的属性:Startkey与EndKey表示这个Region维护的rowkey的范围,当我们要 ...
- HBase Rowkey的散列与预分区设计
转自:http://www.cnblogs.com/bdifn/p/3801737.html 问题导读:1.如何防止热点?2.如何预分区?扩展:为什么会产生热点存储? HBase中,表会被划分为1.. ...
- 理解Hbase RowKey的字典排序;HBase Rowkey的散列与预分区设计
HBase是三维有序存储的,是指rowkey(行键),column key(column family和qualifier)和TimeStamp(时间戳)这个三个维度是依照ASCII码表排序的. HB ...
- HBase(九)HBase表以及Rowkey的设计
一 命名空间 1 命名空间的结构 1) Table:表,所有的表都是命名空间的成员,即表必属于某个命名空间,如果没有指定, 则在 default 默认的命名空间中. 2) RegionServer g ...
- 散列(Hash)表入门
一.概述 以 Key-Value 的形式进行数据存取的映射(map)结构 简单理解:用最基本的向量(数组)作为底层物理存储结构,通过适当的散列函数在词条的关键码与向量单元的秩(下标)之间建立映射关系 ...
- 关于Hbase的预分区,解决热点问题
Hbase默认建表是只有一个分区的,开始的时候所有的数据都会查询这个分区,当这个分区达到一定大小的时候,就会进行做split操作: 因此为了确保regionserver的稳定和高效,应该尽量避免reg ...
- Hbase 表的Rowkey设计避免数据热点
一.案例分析 常见避免数据热点问题的处理方式有:加盐.哈希.反转等方法结合预分区使用. 由于目前原数据第一字段为时间戳形式,第二字段为电话号码,直接存储容易引起热点问题,通过加随机列.组合时间戳.字段 ...
- 大数据量场景下storm自定义分组与Hbase预分区完美结合大幅度节省内存空间
前言:在系统中向hbase中插入数据时,常常通过设置region的预分区来防止大数据量插入的热点问题,提高数据插入的效率,同时可以减少当数据猛增时由于Region split带来的资源消耗.大量的预分 ...
- storm自定义分组与Hbase预分区结合节省内存消耗
Hbas预分区 在系统中向hbase中插入数据时,常常通过设置region的预分区来防止大数据量插入的热点问题,提高数据插入的效率,同时可以减少当数据猛增时由于Region split带来的资源消耗. ...
随机推荐
- js比较日期时间的大小
var myDate = new Date(); var timed = myDate.toLocaleDateString(); var oDate1 = new Date(item.express ...
- python学习第三天-元组、列表及字典
元组 # 元组() 关键字:tuple# 元组的值一旦确定,不可更改,包括增.删.改都不行# 1.元组只有一个数据时,加逗号在后面,不然就不是元组类型的数据tuple_1 = ("hello ...
- Java8 Stream流API常用操作
Java版本现在已经发布到JDK13了,目前公司还是用的JDK8,还是有必要了解一些JDK8的新特性的,例如优雅判空的Optional类,操作集合的Stream流,函数式编程等等;这里就按操作例举一些 ...
- 使用TortoiseGit合并分支
1.切换到主分支 2.右击选择merge, 选择被合并的分支
- C++ 浅析调试,内存重叠查看
这里举个例子查看内存, 环境为:vs 2017 测试为strcpy[因为测试老api,需要在 预处理中 添加 _CRT_SECURE_NO_WARNINGS ] 测试问题:内存溢出 源码: #incl ...
- PHP实现笛卡尔积算法
概念 在数学中,两个集合X和Y的笛卡儿积(Cartesian product),又称直积,表示为 X × Y.设A.B是任意两个集合,在集合A中任意取一个元素x,在集合B中任意取一个元素y,组成一个有 ...
- java基础学习笔记二(接口、super、this)
一.super 和 this的用法 主要解释一下引用构造函数的用法 super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句) this(参数):调用本类中另一种形式的构造函数(应 ...
- comet4j js中写法
<script type="text/javascript" src="${ctxStatic}/common/js/comet4j.js">< ...
- Service系统服务(四):搭建单区域DNS服务器、特殊DNS解析、配置DNS子域授权、搭建并测试缓存DNS
一.搭建单区域DNS服务器 目标: 本例要求要求为DNS区域tedu.cn搭建一台DNS服务器,以便用户能通过域名的方式访问网站.测试阶段主要提供以下正向记录: svr7.tedu.cn ---> ...
- 接口测试——postman安装
http://www.jianshu.com/p/dd0db1b13cfc postman的视频终于过审了,https://ke.qq.com/course/229839#tuin=1eb87ef,大 ...