乐趣区

关于java:Hbase踩坑计

Hbase 数据库比拟实用于写多读少的场景。其查问能力并不突出。
在应用 Scan 扫描表的时候,很容易踩坑。

踩坑 1:在表数据量偏大的状况下(比方上千万数据),执行 scan 提醒 60000ms 的 timeout,并且呈现 OOM。
剖析:

scan 对象有几个重要的参数:caching:该值示意一次从 RPC 申请 Client 能够从 Hbase 服务器获取的数据条数。默认值是 -1。依照源码,如果是 -1,那么发送给 Hbase 的值是:HConstants#DEFAULT_HBASE_CLIENT_SCANNER_CACHING,即:Integer.MAX_VALUE。这是一个十分大的值。![image.png](/img/bVcRFNj)

  maxResultSize:client 从 Hbase 服务端获取的数据在客户端缓存的最大字节数。默认是 -1。如果应用的是默认值,则缓存大小限度是:2M(即 2 * 1024 * 1024)。![image.png](/img/bVcRFNg)
                 
  limit:示意一次 Scan 扫描的行数,相当于 MySql 的 limit。** 须要留神的是:此参数值在 2.x 版本失效,1.x 版本没有此参数。**
         默认值是 -1。如果是默认值,则不会应用该参数。呈现这个问题的起因是 Hbase-client 采纳的是 2.x 版本,然而 Hbase 服务端是 1.x 版本。应用 limit 参数对其有效。所以会一次去
服务端查问 Integer.MAX_VALUE 条数据,导致 OOM 和 timeout。在结构 Hbase 服务端的申请参数时,代码别离如下(能够看到 2.x 多了 limitOfRows 参数):2.x 版本:
public static ScanRequest buildScanRequest(byte[] regionName, Scan scan, int numberOfRows,
      boolean closeScanner) throws IOException {ScanRequest.Builder builder = ScanRequest.newBuilder();
    RegionSpecifier region = buildRegionSpecifier(RegionSpecifierType.REGION_NAME, regionName);
    builder.setNumberOfRows(numberOfRows);
    builder.setCloseScanner(closeScanner);
    builder.setRegion(region);
    builder.setScan(ProtobufUtil.toScan(scan));
    builder.setClientHandlesPartials(true);
    builder.setClientHandlesHeartbeats(true);
    builder.setTrackScanMetrics(scan.isScanMetricsEnabled());
    if (scan.getLimit() > 0) {builder.setLimitOfRows(scan.getLimit());
    }
    return builder.build();}

在 1.x 版本:

  public static ScanRequest buildScanRequest(final byte[] regionName, final Scan scan,
      final int numberOfRows, final boolean closeScanner) throws IOException {ScanRequest.Builder builder = ScanRequest.newBuilder();
    RegionSpecifier region = buildRegionSpecifier(RegionSpecifierType.REGION_NAME, regionName);
    builder.setNumberOfRows(numberOfRows);
    builder.setCloseScanner(closeScanner);
    builder.setRegion(region);
    builder.setScan(ProtobufUtil.toScan(scan));
    builder.setClientHandlesPartials(true);
    builder.setClientHandlesHeartbeats(true);
    builder.setTrackScanMetrics(scan.isScanMetricsEnabled());
    return builder.build();}

踩坑 2:在进行 Scan 扫描的时候,随着工夫的推移,Scan 的速度越来越慢。
剖析:Scan 有 2 个参数:

  startRow:扫描的起始 rowkey。filter:值过滤器,比方:RowFilter。其解决代码如下:
byte[] startRow = scan.getStartRow();
   if (startRow != null && startRow.length > 0) {scanBuilder.setStartRow(ByteStringer.wrap(startRow));
   }
   byte[] stopRow = scan.getStopRow();
   if (stopRow != null && stopRow.length > 0) {scanBuilder.setStopRow(ByteStringer.wrap(stopRow));
   }
   if (scan.hasFilter()) {scanBuilder.setFilter(ProtobufUtil.toFilter(scan.getFilter()));
   }

在应用 scan 进行全表扫描的时候,如果没有指定 startRow,那么就会越来越慢。因为每次都是从头开始扫描,所以会越来越慢。
所以 startRow 尽量都要增加上。

退出移动版