HBase的读写流程&HBase API

HBase读数据流程

  1. HRegionServer保存着.META.的这样一张表以及表数据,要访问表数据,首先Client先去访问zookeeper,从zookeeper里面找到.META.表所在的位置信息,即找到这个.META.表在哪个HRegionServer上保存着。
  2. 接着Client通过刚才获取到的HRegionServer的IP来访问.META.表所在的HRegionServer,从而读取到.META.,进而获取到.META.表中存放的元数据。
  3. Client通过元数据中存储的信息,访问对应的HRegionServer,然后扫描(scan)所在HRegionServer的Memstore和Storefile来查询数据。

HBase写数据流程

  1. Client也是先访问zookeeper,找到-ROOT-表,进而找到.META.表,并获取.META.表信息。
  2. 确定当前将要写入的数据所对应的RegionServer服务器和Region。
  3. Client向该RegionServer服务器发起写入数据请求,然后RegionServer收到请求并响应。
  4. Client先把数据写入到HLog,以防止数据丢失。
  5. 然后将数据写入到Memstore。
  6. 如果Hlog和Memstore均写入成功,则这条数据写入成功。在此过程中,如果Memstore达到阈值,会把Memstore中的数据flush到StoreFile中。
  7. 当Storefile越来越多,会触发Compact合并操作,把过多的Storefile合并成一个大的Storefile。当Storefile越来越大,Region也会越来越大,达到阈值后,会触发Split操作,将Region一分为二。

提示:因为内存空间是有限的,所以说溢写过程必定伴随着大量的小文件产生。

HBase API

首先需要获取Configuration对象:

1
public static Configuration conf;
2
3
static{
4
    //使用HBaseConfiguration的单例方法实例化
5
    conf = HBaseConfiguration.create();
6
    conf.set("hbase.zookeeper.quorum", "hadoop001");
7
    conf.set("hbase.zookeeper.property.clientPort", "2181");
8
    conf.set("zookeeper.znode.parent", "/hbase");
9
}

判断表是否存在:

1
public static boolean isTableExist(String tableName) throws MasterNotRunningException, ZooKeeperConnectionException, IOException{
2
    //在HBase中管理、访问表需要先创建HBaseAdmin对象
3
    Connection connection = ConnectionFactory.createConnection(conf);
4
    HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
5
    
6
    //HBaseAdmin admin = new HBaseAdmin(conf);
7
    return admin.tableExists(tableName);
8
}

创建表:

1
public static void createTable(String tableName, String... columnFamily) throws MasterNotRunningException, ZooKeeperConnectionException, IOException{
2
    HBaseAdmin admin = new HBaseAdmin(conf);
3
    //判断表是否存在
4
    if(isTableExist(tableName)){
5
        System.out.println("表" + tableName + "已存在");
6
        //System.exit(0);
7
    }else{
8
        //创建表属性对象,表名需要转字节
9
        HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName));
10
        //创建多个列族
11
        for(String cf : columnFamily){
12
            descriptor.addFamily(new HColumnDescriptor(cf));
13
        }
14
        //根据对表的配置,创建表
15
        admin.createTable(descriptor);
16
        System.out.println("表" + tableName + "创建成功!");
17
    }
18
}

删除表:

1
public static void dropTable(String tableName) throws Exception{
2
	HBaseAdmin admin = new HBaseAdmin(conf);
3
	if(isTableExist(tableName)){
4
		admin.disableTable(tableName);
5
		admin.deleteTable(tableName);
6
		System.out.println("表" + tableName + "删除成功!");
7
	}else{
8
		System.out.println("表" + tableName + "不存在!");
9
	}
10
}

向表中插入数据:

1
public static void addRowData(String tableName, String rowKey, String columnFamily, String column, String value) throws Exception{
2
	//创建HTable对象
3
	HTable hTable = new HTable(conf, tableName);
4
	//向表中插入数据
5
	Put put = new Put(Bytes.toBytes(rowKey));
6
	//向Put对象中组装数据
7
	put.add(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value));
8
	hTable.put(put);
9
	hTable.close();
10
	System.out.println("插入数据成功");
11
}

删除多行数据:

1
public static void deleteMultiRow(String tableName, String... rows) throws IOException{
2
	HTable hTable = new HTable(conf, tableName);
3
	List<Delete> deleteList = new ArrayList<Delete>();
4
	for(String row : rows){
5
		Delete delete = new Delete(Bytes.toBytes(row));
6
		deleteList.add(delete);
7
	}
8
	hTable.delete(deleteList);
9
	hTable.close();
10
}

得到所有数据:

1
public static void getAllRows(String tableName) throws IOException{
2
	HTable hTable = new HTable(conf, tableName);
3
	//得到用于扫描region的对象
4
	Scan scan = new Scan();
5
	//使用HTable得到resultcanner实现类的对象
6
	ResultScanner resultScanner = hTable.getScanner(scan);
7
	for(Result result : resultScanner){
8
		Cell[] cells = result.rawCells();
9
		for(Cell cell : cells){
10
			//得到rowkey
11
			System.out.println("行键:" + Bytes.toString(CellUtil.cloneRow(cell)));
12
			//得到列族
13
			System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell)));
14
			System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell)));
15
			System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell)));
16
		}
17
	}
18
}

得到某一行所有数据:

1
public static void getRow(String tableName, String rowKey) throws IOException{
2
	HTable table = new HTable(conf, tableName);
3
	Get get = new Get(Bytes.toBytes(rowKey));
4
	//get.setMaxVersions();显示所有版本
5
	//get.setTimeStamp();显示指定时间戳的版本
6
	Result result = table.get(get);
7
	for(Cell cell : result.rawCells()){
8
		System.out.println("行键:" + Bytes.toString(result.getRow()));
9
		System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell)));
10
		System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell)));
11
		System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell)));
12
		System.out.println("时间戳:" + cell.getTimestamp());
13
	}
14
}

获取某一行指定列族:列的数据:

1
public static void getRowQualifier(String tableName, String rowKey, String family, String qualifier) throws IOException{
2
	HTable table = new HTable(conf, tableName);
3
	Get get = new Get(Bytes.toBytes(rowKey));
4
	get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
5
	Result result = table.get(get);
6
	for(Cell cell : result.rawCells()){
7
		System.out.println("行键:" + Bytes.toString(result.getRow()));
8
		System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell)));
9
		System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell)));
10
		System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell)));
11
	}
12
}
Author: VinxC
Link: https://vinxikk.github.io/2018/06/20/hbase/hbase-read-write-process/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.