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. Spring Bean初始化之后执行指定方法

    转: Spring Bean初始化之后执行指定方法 2017年07月31日 15:59:33 vircens 阅读数:24807   Spring Bean初始化之后执行指定方法 在运用Spring进 ...

  2. sk-learn 决策树的超参数

    一.参数criterion:特征选择标准,[entropy, gini].默认gini,即CART算法. splitter:特征划分标准,[best, random].best在特征的所有划分点中找出 ...

  3. 分布式协调服务Zookeeper集群搭建

    分布式协调服务Zookeeper集群搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装jdk环境 1>.操作环境 [root@node101.yinzhengjie ...

  4. jq常用事件(on,blur,focus,change),js/jq等待图片(页面)加载完毕事件,js读取文件

    jq常用事件(on,blur,focus,change) // 方法一(推荐) $('.box').on( "click",function() {} ) $('.box').on ...

  5. 编译VisualVM源码解决乱码问题

    编译VisualVM源码解决乱码问题 起因 今天在使用VisualVM对测试服务器进行JVM监控的时候,发现所有统计图的横纵坐标都是显示乱码(小方块),即使我的Ubuntu系统使用的是英文语言环境.奇 ...

  6. Qt快速入门第三版下载

    找了半天才找到一个靠谱的: http://www.ddooo.com/softdown/111665.htm

  7. Servlet处理Json请求数据包

    request.setCharacterEncoding('UTF-8'); response.setContentType('text/html;charset=UTF-8'); String ac ...

  8. Coursera, Big Data 4, Machine Learning With Big Data (week 3/4/5)

    week 3 Classification KNN :基本思想是 input value 类似,就可能是同一类的 Decision Tree Naive Bayes Week 4 Evaluating ...

  9. “放到桌面”的Servlet实现

    复习下Servlet下载文件, 当response把ContentType设置成application/xxxx的时候呢,浏览器会默认启动下载,而不是试图打开. 通过给httpHeader里面加入内容 ...

  10. 2018-2019 网络对抗技术 20165231 Exp5 MSF基础应用

    实践内容(3.5分) 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路.具体需要完成: 1.1一个主动攻击实践(1分) ms08_067; (失败) MS17-010永 ...