如何通过Java代码查询HBase Region的大小及数据存储状态
HBase Java API查询Region数据存在性与大小的实现方案
以下两种方案兼容HBase 1.x与2.x主流版本,可按需选择:
获取Region大小的两种实现
方案1:使用HBase内置Admin的RegionMetrics API(推荐)
不需要额外依赖HDFS客户端权限,直接通过HBase服务端返回的统计数据获取,性能最高:
// 初始化Connection Configuration conf = HBaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "你的ZK集群地址"); try (Connection connection = ConnectionFactory.createConnection(conf); Admin admin = connection.getAdmin()) { TableName tableName = TableName.valueOf("你的表名"); // 获取表所有Region的位置信息 List<HRegionLocation> regionLocations = connection.getRegionLocator(tableName).getAllRegionLocations(); for (HRegionLocation loc : regionLocations) { RegionInfo regionInfo = loc.getRegion(); // 获取Region的度量信息 RegionMetrics metrics = admin.getRegionMetrics(regionInfo.getRegionName()); // 单位为字节,可自行转换为MB/GB long regionSizeBytes = metrics.getStoreFileSize().get(); System.out.printf("Region %s 总大小:%d 字节%n", regionInfo.getEncodedName(), regionSizeBytes); } } catch (IOException e) { e.printStackTrace(); }
HBase 1.x版本适配:将
getRegionMetrics替换为getRegionLoad,从返回的RegionLoad对象中调用getStorefileSizeMB即可获取大小。
方案2:通过HDFS API统计Region目录大小
如果需要更精确的实时大小(排除服务端统计延迟),可以直接读取HDFS上Region的存储目录统计总大小,需要当前执行程序的用户有HDFS对应目录的读权限:
// 初始化HDFS Configuration Configuration hdfsConf = new Configuration(); hdfsConf.set("fs.defaultFS", "你的HDFS NameNode地址"); // HBase在HDFS上的根目录,默认是/hbase,示例为默认命名空间下的表路径 String hbaseRootDir = "/hbase/data/default/你的表名/"; try (FileSystem fs = FileSystem.get(hdfsConf)) { // 替换为你要查询的Region的encoded name String regionEncodedName = "xxxxxxx"; Path regionPath = new Path(hbaseRootDir + regionEncodedName); long totalSize = 0; // 递归遍历目录下所有文件统计大小 RemoteIterator<LocatedFileStatus> iterator = fs.listFiles(regionPath, true); while (iterator.hasNext()) { totalSize += iterator.next().getLen(); } System.out.printf("Region %s 实际存储大小:%d 字节%n", regionEncodedName, totalSize); } catch (IOException e) { e.printStackTrace(); }
判断Region是否包含数据
构造仅针对该Region范围的Scan,设置最大返回结果数为1,只要查询到结果就说明该Region有数据,资源消耗极低:
Configuration conf = HBaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "你的ZK集群地址"); try (Connection connection = ConnectionFactory.createConnection(conf); Table table = connection.getTable(TableName.valueOf("你的表名"))) { // 替换为你要查询的Region的RegionInfo对象 RegionInfo targetRegion = xxx; Scan scan = new Scan(); // 设置扫描的范围为该Region的起止键 scan.withStartRow(targetRegion.getStartKey()); scan.withStopRow(targetRegion.getEndKey()); // 只返回一行,不读取实际内容,仅判断是否存在数据 scan.setLimit(1); scan.setRaw(true); scan.setCacheBlocks(false); try (ResultScanner scanner = table.getScanner(scan)) { boolean hasData = scanner.next() != null; System.out.printf("Region %s 是否包含数据:%b%n", targetRegion.getEncodedName(), hasData); } } catch (IOException e) { e.printStackTrace(); }
注意事项
- 刚创建的空Region没有写入过数据的话,上述两种大小查询方式返回的结果都会是0,和是否包含数据的判断结果一致。
- 针对设置了TTL或存在大量删除标记的Region,存储大小可能远大于实际有效数据的大小,若需要统计有效数据大小需要额外做全表扫描统计,性能会大幅下降。
内容的提问来源于stack exchange,提问作者smitz
相关产品推荐
相关产品推荐

