Hbase默认建表是只有一个分区的,开始的时候所有的数据都会查询这个分区,当这个分区达到一定大小的时候,就会进行做split操作;

因此为了确保regionserver的稳定和高效,应该尽量避免region分裂和热点的问题;

那么有的同学在做预分区的时候,可能是按照:

1):

通过Hbase提供的api:
bin/hbase org.apache.hadoop.hbase.util.RegionSplitter demo1 HexStringSplit -c 10 -f info 默认建表是没有开启Bloomfilter和压缩参数的,这里为了提供读性能,建议开启Bloomfilter,同时使用压缩SNAPPY,进入hbase shell,首先需要disable 'poidb',然后使用使用 alter 'poidb',{NAME => 'info',BLOOMFILTER => 'ROWCOL',COMPRESSION => 'SNAPPY',VERSIONS => '1'} -C 多少个分区
-f 列族

2):

通过指定create命令

3):

没做任何修饰的代码操作

package com.dongfeng.code.tools.writeDb

import com.dongfeng.code.tools.GlobalConfigUtils
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{HBaseConfiguration, HColumnDescriptor, HTableDescriptor, TableName}
import org.apache.hadoop.hbase.client.{Admin, Connection, ConnectionFactory}
import org.apache.hadoop.hbase.util.Bytes /**
* Created by angel
*/
object WriteToHbaseDB {
private val config: Configuration = HBaseConfiguration.create()
config.set("hbase.zookeeper.quorum" , GlobalConfigUtils.hbaseQuorem)
config.set("hbase.master" , GlobalConfigUtils.hbaseMaster)
config.set("hbase.zookeeper.property.clientPort" , GlobalConfigUtils.clientPort)
config.set("hbase.rpc.timeout" , GlobalConfigUtils.rpcTimeout)
config.set("hbase.client.operator.timeout" , GlobalConfigUtils.operatorTimeout)
//def scannTimeout = conf.getString("c")
config.set("hbase.client.scanner.timeout.period" , GlobalConfigUtils.scannTimeout)
private val conn: Connection = ConnectionFactory.createConnection(config)
private val admin: Admin = conn.getAdmin
//创建表
def createTable(tableName:TableName, columnFamily:String) = { val hTableDescriptor = new HTableDescriptor(tableName)
val hColumnDescriptor = new HColumnDescriptor(columnFamily)
hTableDescriptor.addFamily(hColumnDescriptor)
//如果表不存在则创建表
if(!admin.tableExists(tableName)){
var splitKeys: List[Array[Byte]] = List(
Bytes.toBytes("40000") ,
Bytes.toBytes("80000") ,
Bytes.toBytes("120000") ,
Bytes.toBytes("160000")
)
// for (x <- 1 to 5) {
// if(x<10){
// splitKeys = splitKeys.+:(Bytes.toBytes(x.toString))
// }else{
// splitKeys = splitKeys.+:(Bytes.toBytes(x.toString))
// }
// }
try{
//创建表
admin.createTable(hTableDescriptor, splitKeys.toArray)
}finally {
admin.close()
}
}
} def main(args: Array[String]): Unit = {
createTable(TableName.valueOf("demo3") , "info")
}
}

其实上面的这些操作,会无形中限制我们的rowkey的最初设计,既要考虑高效的字典排列方式,还要考虑热点问题。往往稍微有点偏差,就会出现大部分的数据都往一个region中跑,显然不合理

因此,我觉得至少在我的业务中是需要进行rowkey的加盐或者MD5操作的,达到rowkey的散列

我这里进行MD5加密处理

package com.df.tools

import java.util.concurrent.atomic.AtomicInteger

import com.df.Contant.GlobalConfigUtils
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase._
import org.apache.hadoop.hbase.client._
import org.apache.hadoop.hbase.io.compress.Compression.Algorithm
import org.apache.hadoop.hbase.protobuf.ProtobufUtil
import org.apache.hadoop.hbase.util.{Base64, Bytes, MD5Hash}
import org.apache.hadoop.hbase.util.RegionSplitter.HexStringSplit /**
* Created by angel
*/
object HbaseTools {
private val config: Configuration = HBaseConfiguration.create()
config.set("hbase.zookeeper.quorum" , GlobalConfigUtils.hbaseQuorem)
config.set("hbase.master" , GlobalConfigUtils.hbaseMaster)
config.set("hbase.zookeeper.property.clientPort" , GlobalConfigUtils.clientPort)
config.set("hbase.rpc.timeout" , GlobalConfigUtils.rpcTimeout)
config.set("hbase.client.operator.timeout" , GlobalConfigUtils.operatorTimeout)
config.set("hbase.client.scanner.timeout.period" , GlobalConfigUtils.scannTimeout)
private val conn: Connection = ConnectionFactory.createConnection(config)
private val admin: Admin = conn.getAdmin
val atomic = new AtomicInteger(0)
var resultAtomic = 0
/**
* @return 构建表的连接
* */
def Init(tableName: String , columnFamily:String):Table = {
val hTableDescriptor = new HTableDescriptor(TableName.valueOf(tableName))
val hColumnDescriptor = new HColumnDescriptor(columnFamily)
hTableDescriptor.addFamily(hColumnDescriptor)
if(!admin.tableExists(TableName.valueOf(tableName))){
// admin.createTable(hTableDescriptor)
createHTable(conn , tableName , 10 , Array(columnFamily)) }
conn.getTable(TableName.valueOf(tableName))
} // 对指定的列构造rowKey,采用Hash前缀拼接业务主键的方法
def rowKeyWithHashPrefix(column: String*): Array[Byte] = {
val rkString = column.mkString("")
val hash_prefix = getHashCode(rkString)
val rowKey = Bytes.add(Bytes.toBytes(hash_prefix), Bytes.toBytes(rkString))
rowKey
} // 对指定的列构造rowKey, 采用Md5 前缀拼接业务主键方法,主要目的是建表时采用MD5 前缀进行预分区
def rowKeyWithMD5Prefix(separator:String,length: Int,column: String*): Array[Byte] = {
val columns = column.mkString(separator) var md5_prefix = MD5Hash.getMD5AsHex(Bytes.toBytes(columns))
if (length < 8){
md5_prefix = md5_prefix.substring(0, 8)
}else if (length >= 8 || length <= 32){
md5_prefix = md5_prefix.substring(0, length)
}
val row = Array(md5_prefix,columns)
val rowKey = Bytes.toBytes(row.mkString(separator))
rowKey
} // 对指定的列构造RowKey,采用MD5方法
def rowKeyByMD5(column: String*): Array[Byte] = {
val rkString = column.mkString("")
val md5 = MD5Hash.getMD5AsHex(Bytes.toBytes(rkString))
val rowKey = Bytes.toBytes(md5)
rowKey
}
// 直接拼接业务主键构造rowKey
def rowKey(column:String*):Array[Byte] = Bytes.toBytes(column.mkString("")) // Hash 前缀的方法:指定列拼接之后与最大的Short值做 & 运算
// 目的是预分区,尽量保证数据均匀分布
private def getHashCode(field: String): Short ={
(field.hashCode() & 0x7FFF).toShort
} /**
* @param tablename 表名
* @param regionNum 预分区数量
* @param columns 列簇数组
*/
def createHTable(connection: Connection, tablename: String,regionNum: Int, columns: Array[String]): Unit = { val nameSpace = "df"
val hexsplit: HexStringSplit = new HexStringSplit()
// 预先构建分区,指定分区的start key
val splitkeys: Array[Array[Byte]] = hexsplit.split(regionNum) val admin = connection.getAdmin val tableName = TableName.valueOf(tablename) if (!admin.tableExists(tableName)) {
val tableDescriptor = new HTableDescriptor(tableName) if (columns != null) {
columns.foreach(c => {
val hcd = new HColumnDescriptor(c.getBytes()) //设置列簇
hcd.setMaxVersions(1)
hcd.setCompressionType(Algorithm.SNAPPY) //设定数据存储的压缩类型.默认无压缩(NONE)
tableDescriptor.addFamily(hcd)
})
}
admin.createTable(tableDescriptor,splitkeys)
} } /**
* @param tableName
* @param key
* @param columnFamily
* @param column
* @param data 要落地的数据
* */
def putData(tableName: String , key:String , columnFamily:String , column:String , data:String):Int = {
val table: Table = Init(tableName , columnFamily)
try{
val rowkey = HbaseTools.rowKeyByMD5(key)
val put: Put = new Put(rowkey)
put.addColumn(Bytes.toBytes(columnFamily) ,Bytes.toBytes(column.toString) , Bytes.toBytes(data.toString))
table.put(put)
resultAtomic = atomic.incrementAndGet()
}catch{
case e:Exception => e.printStackTrace()
resultAtomic = atomic.decrementAndGet()
}finally {
table.close()
}
resultAtomic
} /**
* @param mapData 要插入的数据[列明 , 值]
* */ def putMapData(tableName: String , columnFamily:String, key:String , mapData:Map[String , String]):Int = {
val table: Table = Init(tableName , columnFamily)
try{
//TODO rowKeyWithMD5Prefix
val rowkey = HbaseTools.rowKeyByMD5(key)
val put: Put = new Put(rowkey)
if(mapData.size > 0){
for((k , v) <- mapData){
put.addColumn(Bytes.toBytes(columnFamily) ,Bytes.toBytes(k.toString) , Bytes.toBytes(v.toString))
}
}
table.put(put)
resultAtomic = atomic.incrementAndGet()
}catch{
case e:Exception => e.printStackTrace()
resultAtomic = atomic.decrementAndGet()
}finally {
table.close()
}
resultAtomic
} def deleteData(tableName: String , rowKey:String , columnFamily:String):Int ={
val table: Table = Init(tableName , columnFamily)
try{
val delete = new Delete(Bytes.toBytes(rowKey))
table.delete(delete)
resultAtomic = atomic.decrementAndGet()
}catch{
case e:Exception => e.printStackTrace()
resultAtomic = atomic.decrementAndGet()
}finally {
table.close()
}
resultAtomic
} def convertScanToString(scan: Scan):String={
val proto = ProtobufUtil.toScan(scan)
return Base64.encodeBytes(proto.toByteArray)
}
}

关于Hbase的预分区,解决热点问题的更多相关文章

  1. HBase表预分区

    在创建Hbase表的时候默认一张表只有一个region,所有的put操作都会往这一个region中填充数据,当这个一个region过大时就会进行split.如果在创建HBase的时候就进行预分区则会减 ...

  2. HBase表预分区与压缩

    1.建立HBase预分区表.sql语句如下: create 'buyer_calllogs_info_ts', 'record', {SPLITS_FILE => 'hbase_calllogs ...

  3. HBase 热点问题——rowkey散列和预分区设计

    热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作).大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响 ...

  4. 大数据量场景下storm自定义分组与Hbase预分区完美结合大幅度节省内存空间

    前言:在系统中向hbase中插入数据时,常常通过设置region的预分区来防止大数据量插入的热点问题,提高数据插入的效率,同时可以减少当数据猛增时由于Region split带来的资源消耗.大量的预分 ...

  5. storm自定义分组与Hbase预分区结合节省内存消耗

    Hbas预分区 在系统中向hbase中插入数据时,常常通过设置region的预分区来防止大数据量插入的热点问题,提高数据插入的效率,同时可以减少当数据猛增时由于Region split带来的资源消耗. ...

  6. hbase 预分区与自动分区

    我们知道,HBASE在创建表的时候,会自动为表分配一个Region,当一个Region过大达到默认的阈值时(默认10GB大小),HBase中该Region将会进行split,分裂为2个Region,以 ...

  7. rowkey散列和预分区设计解决hbase热点问题(数据倾斜)

    Hbase的表会被划分为1....n个Region,被托管在RegionServer中.Region二个重要的属性:Startkey与EndKey表示这个Region维护的rowkey的范围,当我们要 ...

  8. HBase Rowkey的散列与预分区设计

    转自:http://www.cnblogs.com/bdifn/p/3801737.html 问题导读:1.如何防止热点?2.如何预分区?扩展:为什么会产生热点存储? HBase中,表会被划分为1.. ...

  9. HBase预分区

    seq 0 7 | awk '{printf("\\x%02x\\x%02x\n", $1/256, $1%256);}' | sort -R |head -3 create 'm ...

随机推荐

  1. django 1.开发接口环境搭建

    首先需要的环境: pycharm Python 3.6.0 django 2.1.3        安装命令: pip3 install django   查看版本号和安装的路径: pip show ...

  2. Linux sed command

    概述 sed 是一种在线非交互式编辑器,它一次处理一行内容. 处理时,把当前处理的行存储在临时缓冲区中,称为"模式空间"(pattern space). 接着用sed命令处理缓冲区 ...

  3. Eclipse - 安装lombok后注解无效

    安装 lombok lombok 的安装过程挺简单的,网上已经有很多相关的博客,这里就不在多说了,可以参考这篇:eclipse集成lombok注解不起作用 但是我按照网上的方式安装之后,注解一直不起作 ...

  4. [面试]synchronized

    synchronized 把面试中遇到的问题进行了整理. 本篇文章copy+整理自: 1. http://www.cnblogs.com/lingepeiyong/archive/2012/10/30 ...

  5. vue引入fastclick设置输入框type="number"报错Failed to execute 'setSelectionRange' on 'HTMLInputElement': The input element's type ('number') does not support selection.的解决办法

    将输入框type设为text,通过正则验证输入的值

  6. [BZOJ 4152][AMPPZ 2014]The Captain

    这道题对费用的规定是min(|x1-x2|,|y1-y2|).如果暴力枚举所有的点复杂度O(n²),n <= 200000,显然爆炸.于是我们要考虑加“有效边”,一个显然的事实是对于两个点,如果 ...

  7. luogu 2157 状压dp

    f[i][j][k]分别代表1-i-1个人全部打完饭时i及其后7个人的状态为j时最后一个打饭的人为i+k的状态下所用的最小时间 当i已经打过饭时 即 j&1 那么 f [i] [j>&g ...

  8. Kafka(一)简介

    1.Kafka简介 Kafka已经被很多公司广泛应用,一款实时流式消息组件.发送消息端称为Producer,接收端称为Consumer,Kafka集群有多个kafka实例组成,每个实例称为broker ...

  9. vuex概念详解

    阅读vuex官网以后用自己的话概括起来就是:vuex是vue配套的公共数据管理工具,它可以把一些共享的数据,保存到vuex中,方便整个程序中的任何组件直接获取或修改我们的公共数据. vuex是为了保存 ...

  10. MySQL学习12 - pymysql模块的使用

    一.pymysql的下载和使用 1.pymysql模块的下载 2.pymysql的使用 二.execute()之sql注入 三.增.删.改:conn.commit() 四.查:fetchone.fet ...