HBase表数据倾斜治理_Scan读取Hbase表与Hbase表快照

HBase表数据倾斜治理_Scan读取Hbase表与Hbase表快照

HBase获取数据的方式

1.HBase数据查询分类

HBase查询数据的方式主要有get和scan两种方式,其中get用于按照指定rowkey获取唯一一行数据。scan主要用于批量查询,可以通过添加过滤器实现分页等条件查询功能。

scan有三种常见用法:ScanAPI(Scan和SnapScan)、TableScanMR、SnapshotScanMR。

2.ScanAPI

ScanAPI是一种串行读取数据的方式,HBase客户端每次发送请求到RegionServer获取100行数据,获取到100行数据之后才会发送下一次请求,当scan请求的数据量很大时扫描数据效率极低。就连get都实现了不同region并发执行扫描,scan还没实现。

3.TableScanMR

TableScanMR使用MapReduce计算任务来实现数据读取,就是ScanAPI的并行化,将scan请求分别并行下放到每个RegionServer,如下图所示。

4.SnapshotScanMR

HBase可以通过api创建snapshot,snapshot是HBase表的元数据的一个快照,并不是整个HBase表的快照。snapshot的主要作用就是帮助我们在扫描HBase表数据时绕过RegionServer直接从HDFS中读取Hfile文件数据,极大减轻RegionServer的压力,并且已经封装好了文件合并、数据版本、Filter等功能。(注意HBaseHDFS都提供了创建snapshot的api,这两者的snapshot不是同一个东西,创建方式也不相同。)

SnapshotScanMR同样使用MapReduce计算任务来实现数据读取,但是HBase客户端只需要在最开始与RegionServer交互一次,获取snopshot文件,然后直接根据snopshot找到数据在HDFS系统中的位置并读取。这种扫描方式减少了一次网络传输,极大提高了扫描速度,如下图所示。

initTableMapperJob读取Hbase表

1.创建Mapper类,实现map计算任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//重要:map计算任务执行完之后一定是以key-value的形式保存到HFile中的,Mapper接口的最后两个泛型类表示存储时key和value的数据类型。此处的TableMapper<Text, Text>表示以字符串形式保存key和value。
public class ReadHFileMapper extends TableMapper<Text, Text> {
private Text writeKey = new Text();

//重要:一个Result对象表示HBase表中一行数据,一个Text对象表示HFile文件中一行字符串数据。
@Override
public void map(ImmutableBytesWritable row, Result value, Context context)
throws InterruptedException, IOException {

//Cell是Hbase当中的最小存储单元,也就是Hbase表中的一个数据单元格,其中主要以key-value的形式保存数据。
for (Cell cell : value.listCells()) {
String colName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
String colValue = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()).replaceAll("\\n|\\r|\\t|\1|\\\\N", " ");
String res = colName + "," + colValue;
writeKey.set(new Text(Bytes.toString(row.get())));
context.write(writeKey, new Text(res));
System.out.println(Bytes.toString(row.get()) + " " + res);
}
}
}
  • map计算任务执行完之后一定是以key-value的形式保存到HFile中的,Mapper接口的最后两个泛型类表示输出时key和value的数据类型。此处的TableMapper<Text, Text>表示以字符串形式保存key和value到HFile中。
  • Mapper实现类的map方法每次对文件或者HBase表中的一行数据执行计算任务,该方法的第二个输入参数就是一行数据,如果是处理字符串文件则用Text对象来装载,如果是读取HBase表则用Result对象来装载。
  • HBase java api提供了Cell对象来装载HBase当中最小的存储单元,也就是表中的一个数据单元,数据以key-value的形式保存在其中。

2.创建Driver类

initTableMapperJob是HBase提供的实现TableScanMR的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Demo {
public static void main(String[] args) {

Configuration conf = HBaseConfiguration.create();
String hdfsRoot = "hdfs://localhost:9005/"; //hdfs 的根目录
String tablename = "fellowshell";
Scan scan = new Scan();
scan.setCaching(500);
scan.setCacheBlocks(false);
Job job = null;

try {
job = Job.getInstance(conf, "read table : " + tablename);

//重要:在该scanMR执行过程中,会自动扫描hbase文件夹,根据表名找到表的元数据文件,不需要设置文件输入路径。
//tablename为源表名,scan为扫描类对象
TableMapReduceUtil.initTableMapperJob(tablename, scan, ReadHFileMapper.class, Text.class, Text.class, job, false);

//重要:扫描得到的数据以HFile的形式放在HDFS目录下。
FileOutputFormat.setOutputPath(job, new Path( hdfsRoot +"fellowshellread1"));

System.exit(job.waitForCompletion(true) ? 0 : 1);

} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
  • scanMR在执行过程中,会自动扫描hbase文件夹,根据表名找到表的元数据文件,不需要配置HDFS文件输入路径。
  • scanMR扫描得到的数据按照Mapper中配置好的格式保存到新建的HFile中,需要配置HFile文件输出路径。

执行main方法后打开HDFS客户端可以看到出现输出文件夹,如下图所示。

下载其中HFile文件可以看到就是以字符串形式保存key-value数据的,如下图所示。