智慧出行/HBase-一劳永逸解决Hbase数据热点问题:1.java实现HBase建表并且预分区

13 篇文章 0 订阅
7 篇文章 0 订阅

1.hbase热点问题是什么?

数据倾斜到一个节点,其余节点空转

2.出现haase热点的原因是什么?

出现haase热点情况一定是这两个原因:

  1. rowkey设计太low
  2. 没有做预分区

3.设计hbase经验

rowkey设计原则:唯一,如果不唯一数据就会被覆盖,2散列的,防止出现hbase热点问题,3,字典
rowkey长度设计2的整数倍16,32,64,最长不超过64位.只有这样才可以使用高速缓存,如果不是这些,不能被64整除,就只能使用主机内存,那是比较慢的(最快是寄存器,其次是高速缓存,再往后是内存,磁盘)
列族只设计1个,如果数据量特别大,也就做2个列族,不要在多了.列族最好使用一个字母表示"M",最多使用两个字母"MM"定义其名称

4.为什么row可以设计要使用字典序列去排序的?

为了便利scan操作

5.HBase创建表实现预分区

1.命令行创建HBase的demo01表:

create 'demo01',{NAME=>'M'},SPLITS=>['0','1','2','3']  //列族为一个字母,最大不要超过两个,要使用splits指定预分区

2.通过java代码实现建表并且预分区

hbase给我们提供了两个方法可以做预分区:

  1. RegionSplitter.HexStringSplit:适合于当前rowkey是16进制字符串(7E8A9S777A)
  2. RegionSplitter.UnformSplit:适合于rowkey经过hash,MD5处理过后的

0000| 0001| 0002| 0003|…0007|
竖杠是ASCII中最大的值,因为我们rowkey是字典排序,增加竖杠就就一点会在这个范围之内
在这里插入图片描述

2.1工具类:实现预分区前缀二进制数组的生成

  1. 创建一个指定分区数量的接口
package com.cartravel.hbase;

/**
 * 创建一个指定分区数量的接口
 */
public interface SplitKeyCalulaor {
    public byte[][] getSplitKeys(int regionNum);
    
}

byte[][]二进制数组

实现过程中要运用到lang3这个包下的leftPad()左填充构建前缀

StringUtils.leftPad(null, *, *)     = null
StringUtils.leftPad("", 3, 'z')     = "zzz"
StringUtils.leftPad("bat", 3, 'z')  = "bat"
StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
StringUtils.leftPad("bat", 1, 'z')  = "bat"
StringUtils.leftPad("bat", -1, 'z') = "bat"
@param str:要给那个的字符串左边进行拼接,可以为null
@param size:拼接后总字符个数
@param padChar:拼接的字符
  1. 实现预分区前缀的生成
package com.cartravel.hbase;

import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.util.Bytes;

import java.util.Iterator;
import java.util.TreeSet;

/**
 *工具类实现的是:生成预分区前缀
 */

public class SparkKeyBuilder implements SplitKeyCalulaor {
//##############  实现上述接口生成预分区的前缀(返回的是二进制数组)  ###################
    public byte[][] getSplitKeys(int regionNum) {
        //1.构建前缀
        String[] keys = new String[regionNum];
        for(int i=0;i<regionNum;i++){
            String pre = StringUtils.leftPad(String.valueOf(i), 4, "0") + "|";

            keys[i] = pre;
        }
        //2.构建一个返回值数组
        byte[][] splitKeys = new byte[keys.length][];

        //使用一个有序集合封装前缀
        TreeSet<byte[]> row = new TreeSet<byte[]>();
        for (int i = 0; i < keys.length; i++) {
            row.add(Bytes.toBytes(keys[i]));
        }
        //迭代TreeSet,把值赋值给splitKeys
        Iterator<byte[]> iterator = row.iterator();
        int i =0;
        while(iterator.hasNext()){
            byte[] tempRow = iterator.next();
            iterator.remove();
            splitKeys[i] = tempRow;
            i++;
        }
        row.clear();
        row=null;
        return splitKeys;
    }
}

2.2 通过预分区前缀的二进制数组和表描述器实现创建生成hbase表

package com.cartravel.hbase

import com.cartravel.loggings.Logging
import org.apache.hadoop.hbase.{HColumnDescriptor, HTableDescriptor, TableName}
import org.apache.hadoop.hbase.client.{Connection, TableDescriptorBuilder}
import org.apache.hadoop.hbase.io.compress.Compression.Algorithm
import org.apache.hadoop.hbase.regionserver.BloomType

object hbaseOperation extends Logging {
  private def createTableBySelfBuilt(conn:Connection,tableName:TableName,regionNum:Int,column:Array[String]): Unit ={
    this.synchronized{
      val admin = conn.getAdmin
      try{
        if (admin.tableExists(tableName)){
          //要想创建表,需要一个表的描述器
          val tbDesc: HTableDescriptor = new HTableDescriptor(tableName)
          if (column != null){
            column.foreach(c =>{
              val hcd = new HColumnDescriptor(c.getBytes())
              hcd.setBlockCacheEnabled(false)
              hcd.setMaxVersions(1)
              hcd.setBloomFilterType(BloomType.ROW) //布隆过滤器
              hcd.setCompressionType(Algorithm.SNAPPY) //指定压缩方式
              
              //将列表示器添加到表描述器里面
              tbDesc.addFamily(hcd)
              
            })
          }
          
          val sparkKeyBuilder = new SparkKeyBuilder()
          val splitKeys = sparkKeyBuilder.getSplitKeys(regionNum)
          
          //建表
          admin.createTable(tbDesc,splitKeys)//拥有预分区的hbase表就创建完毕了
        }

      }catch {
        case e:Exception=>
          //邮件报警
      }
    }
  }


}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值