快乐学习 一个网站喵查铺子(catpuzi.com)全搞定~

Hbase性能优化娓娓道来 涉及到 表的设计 Rowkey的优化 列族

大数据 数据帝 2020-02-27 扫描二维码
文章目录[隐藏]

一.表的设计

默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候,所有的HBase客户端都向这一个region写数据,直到这个region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的regions,这样当数据写入HBase时,会按照region分区情况,在集群内做数据的负载均衡。所以我们在建表的时候,我们可以创建一个二维数组对表进行一个拆分。下面是一个例子:

public static boolean createTable(HBaseAdmin admin, HTableDescriptor table, byte[][] splits)
throws IOException {
try {
admin.createTable(table, splits);
return true;
} catch (TableExistsException e) {
logger.info(“table ” + table.getNameAsString() + ” already exists”);
// the table already exists…
return false;
}
}

public static byte[][] getHexSplits(String startKey, String endKey, int numRegions) { //start:001,endkey:100,10region [001,010][011,020]
byte[][] splits = new byte[numRegions-1][];
BigInteger lowestKey = new BigInteger(startKey, 16);
BigInteger highestKey = new BigInteger(endKey, 16);
BigInteger range = highestKey.subtract(lowestKey);
BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegions));
lowestKey = lowestKey.add(regionIncrement);
for(int i=0; i < numRegions-1;i++) {
BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i)));
byte[] b = String.format(“%016x”, key).getBytes();
splits[i] = b;
}
return splits;
}

二.Rowkey的优化

在Hbase里面row key用来检索表中的记录,支持以下三种方式:
·        通过单个row key访问:即按照某个row key键值进行get操作;
·        通过row key的range进行scan:即通过设置startRowKey和endRowKey,在这个范围内进行扫描;
·        全表扫描:即直接扫描整张表中所有行记录。
所以,我们在创建rowkey的时候,遵循下面三个原则:

1、大小越小越好
2、值根据功能需求决定
3、Row最好有散列原则,就像oracle里面建表时候的hash。

三.列族

不要在一张表里定义太多的column family。目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,它邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O。

四.In Memory

创建表的时候,可以通过HColumnDescriptor.setInMemory(true)将表放到RegionServer的缓存中,保证在读取的时候被cache命中。

五.HTable

HTable是Hbase客户端与Hbase服务端通讯的Java API对象,可以通过HTable对象与服务端进行增删改查的操作。

HTable使用时的一些注意事项:

1.   规避HTable对象的创建开销
因为客户端创建HTable对象后,需要进行一系列的操作:检查.META.表确认指定名称的HBase表是否存在,表是否有效等等,整个时间开销比较重,可能会耗时几秒钟之长,因此最好在程序启动时一次性创建完成需要的HTable对象,如果使用Java API,一般来说是在构造函数中进行创建,程序启动后直接重用。

2.   HTable对象不是线程安全的
HTable对象对于客户端读写数据来说不是线程安全的,因此多线程时,要为每个线程单独创建复用一个HTable对象,不同对象间不要共享HTable对象使用,特别是在客户端auto flash被置为false时,由于存在本地write buffer,可能导致数据不一致。

3.   HTable对象之间共享Configuration
HTable对象共享Configuration对象,这样的好处在于:
·        共享ZooKeeper的连接:每个客户端需要与ZooKeeper建立连接,查询用户的table regions位置,这些信息可以在连接建立后缓存起来共享使用;
·        共享公共的资源:客户端需要通过ZooKeeper查找-ROOT-和.META.表,这个需要网络传输开销,客户端缓存这些公共资源后能够减少后续的网络传输开销,加快查找过程速度。

因此,与以下这种方式相比:
HTable table1 = new HTable(“table1”);HTable table2 = new HTable(“table2”);下面的方式更有效些:
Configuration conf = HBaseConfiguration.create();HTable table1 = new HTable(conf, “table1”);HTable table2 = new HTable(conf, “table2”);

5.HTablePoolHTablePool

可以解决HTable存在的线程不安全问题,同时通过维护固定数量的HTable对象,能够在程序运行期间复用这些HTable资源对象。
Configuration conf = HBaseConfiguration.create();HTablePool pool = new HTablePool(conf, 10);1.   HTablePool可以自动创建HTable对象,而且对客户端来说使用上是完全透明的,可以避免多线程间数据并发修改问题。

2.   HTablePool中的HTable对象之间是公用Configuration连接的,能够可以减少网络开销。
HTablePool的使用很简单:每次进行操作前,通过HTablePool的getTable方法取得一个HTable对象,然后进行put/get/scan/delete等操作,最后通过HTablePool的putTable方法将HTable对象放回到HTablePool中。

 

喜欢 (0)
关于作者: