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. xml转换为json格式时,如何将指定节点转换成数组 Json.NET

    使用Json.NET转换xml成json时,如果xml只有单个节点,但json要求是数组形式[], JsonConvert.SerializeXmlNode 并不能自动识别 示例如下: RecordA ...

  2. Angular记录(3)

    文档资料 箭头函数--MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_fun ...

  3. 制作OpenStack使用的windows镜像

    1 安装vmware14 2 创建ubuntu-desktop-16.04虚拟机 选择自定义安装 选择ubuntu-16.04-desktop.iso 内存要大于2G,推荐4G. 磁盘要大于50G 关 ...

  4. Python——爬取人口迁徙数据(以腾讯迁徙为例)

    说明: 1.迁徙量是腾讯修改后的数值,无法确认真实性. 2.代码运行期间,腾讯迁徙未设置IP屏蔽和浏览器检测,因此下段代码仅能保证发布近期有效. 3.代码功能:爬取指定一天的四十(此四十是根据自己的城 ...

  5. 内存屏障和volatile内存语义的实现

    趁周末,把以前的书拿出来,再翻一番,顺便做个笔记: 内存屏障:用来控制和规范cpu对内存操作的顺序的cpu指令. 内存屏障列表: 1.loadload:确保“前者数据装载”先于“后者装载指令”: 2. ...

  6. 分享一个在线生成微信跳转链接实现微信内跳转浏览器打开URL的工具

    前言 现如今微信对第三方推广链接的审核是越来越严格了,域名在微信中分享转发经常会被拦截,一旦被拦截用户就只能复制链接手动打开浏览器粘贴才能访问,要不然就是换个域名再推,周而复始.无论是哪一种情况都会面 ...

  7. HTML5 scada 组态工具

    底层引擎 提供了基于WebGL的3D技术的图形组件, WebGL基于OpenGL ES 2.0图形接口,因此WebGL属于底层的图形API接口, 二次开发还是有很高的门槛,通过对WebGL底层技术的封 ...

  8. 2018-2019-2 20165234 《网络对抗技术》 Exp5 MSF基础应用

    实验五 MSF基础应用 实验内容 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路.具体需要完成: 1.一个主动攻击实践,ms08_067(成功) 2. 一个针对浏览器 ...

  9. 【Android手机测试】linux内存管理 -- 一个进程占多少内存?四种计算方法:VSS/RSS/PSS/USS

    在Linux里面,一个进程占用的内存有不同种说法,可以是VSS/RSS/PSS/USS四种形式,这四种形式首字母分别是Virtual/Resident/Proportional/Unique的意思. ...

  10. Linux查看日志工具

    ⒈journalctl journalctl是Centos7才有的工具用于systemd统一管理所有unit的启动日志,只用一个journalctl命令就可以查看所有的日志(包括内核日志和应用日志), ...