hbase-region预分区(pre-splitting)

来源:互联网 发布:1吨铀能发多少电 知乎 编辑:程序博客网 时间:2024/05/19 13:19

如果一个节点有过多的读写操作,会造成热点问题,HBase可能会因为Zookeeper的连接超时而关掉该节点,一个好的策略是将表预分割为固定数量的区域(region),并且这些区域均匀地分布在所有的服务器(regionserver)上,然后让HBase的自动分割功能来处理后面不断增加的数据。

RegionSplitter提供三个用于Pre-splitting的工具:HexStringSplit、UniformSplit、SplitAlgorithm。

HexStringSplit

row key是十六进制的字符串(hexadecimal ASCII)作为前缀的时候

HexHash(prefix)作为row key的前缀,其中Hexhash为最终得到十六进制字符串的hash算法
#方式一create 'mytable', { NAME => 'info', COMPRESSION => 'snappy' },  {NUMREGIONS => 60, SPLITALGO => 'HexStringSplit'}#方式二hbase org.apache.hadoop.hbase.util.RegionSplitter mytable HexStringSplit -c 10 -f f1

UniformSplit

row key是字节数组arbitrary bytes的时候

某个hbase的表查询只是以随机查询为主,可以用UniformSplit的方式进行,按照原始byte值(从0x00~0xFF)右边以00填充。以这种方式分区的表在插入的时候需要对rowkey进行一个技巧性的改造, 比如原来的rowkey为rawStr,则需要对其取hashCode,然后进行按照比特位反转后放在最初rowkey串的前面
create 'tracker_total_live_active_fact', 'info',{NUMREGIONS => 15, SPLITALGO => 'UniformSplit'}

rowkey设计:

public static void main(String[] args) throws Exception {          Configuration conf = HBaseConfiguration.create();          conf.set("hbase.zookeeper.quorum", "hadoop1");          conf.set("hbase.zookeeper.property.clientPort", "2181");          HConnection connection = HConnectionManager.createConnection(conf);          HTableInterface table = connection.getTable("huanggang");          for (int i=1; i< 6553500; i++) {              byte[] rowKey = Bytes.add(Bytes.toBytes(Integer.reverse(Integer.valueOf(Integer.valueOf(i).hashCode()))), Bytes.toBytes(i));              System.out.println(rowKey);              Put put = new Put(rowKey);              put.add("f".getBytes(), "col1".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));              put.add("f".getBytes(), "col2".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));              put.add("f".getBytes(), "col3".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));              put.add("f".getBytes(), "col4".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));              put.add("f".getBytes(), "col5".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));              put.add("f".getBytes(), "col6".getBytes(), Bytes.toBytes(new Random().nextInt(10000)));              table.put(put);          }          table.flushCommits();          table.close();      }  

SplitAlgorithm

SplitAlgorithm是一个接口,需要开发人员自己实现相应的分隔策略

SplitAlgorithm splitAlgo = new SplitAlgoInstance(conf, splitClass);//实例化自定义splitAlgorithm对象。

import org.apache.hadoop.hbase.util.Bytes;import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm;import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;import java.util.ArrayList;import java.util.List;public class FileSplit implements SplitAlgorithm {    //  public static final String SPLIT_KEY_FILE = "split-keys";    private String splitKeyFile;    public FileSplit(String splitKeyFile) {        this.splitKeyFile = splitKeyFile;    }    @Override    public byte[] split(byte[] start, byte[] end) {        return null;    }    @Override    public byte[][] split(int numberOfSplits) {        BufferedReader reader = null;        try {            List<byte[]> regions = new ArrayList<byte[]>();            //一行一行读            reader = new BufferedReader(new FileReader(splitKeyFile));            String line;            while ((line = reader.readLine()) != null) {//              System.out.println(line);                if (line.trim().length() > 0) {                    regions.add(Bytes.toBytes(line));                }            }            return regions.toArray(new byte[0][]);        } catch (IOException e) {            throw new RuntimeException("Error reading splitting keys from " + splitKeyFile, e);        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                if (reader != null) reader.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return null;    }    @Override    public byte[] firstRow() {        return null;    }    @Override    public byte[] lastRow() {        return null;    }    @Override    public void setFirstRow(String s) {    }    @Override    public void setLastRow(String s) {    }    @Override    public byte[] strToRow(String input) {        return null;    }    @Override    public String rowToStr(byte[] row) {        return null;    }    @Override    public String separator() {        return null;    }    @Override    public void setFirstRow(byte[] bytes) {    }    @Override    public void setLastRow(byte[] bytes) {    }}

自定义分区

 create 'mytable', 'colfam1', {SPLITS => ['ROW-100','ROW-200','ROW-300','ROW-400']}

还可以指定分区文件

create 'mytable', { NAME => 'dim', COMPRESSION => 'snappy' }, { NAME => 'fact', COMPRESSION => 'snappy' },SPLITS_FILE => 'splits.txt'

分区文件

00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|

这里是以一天的24小时作为前缀来设计rowkey的

参考站点:

http://blog.csdn.net/jdplus/article/details/47273983

http://blog.csdn.net/huanggang028/article/details/40819517

原创粉丝点击