到目前为之,每一个next()调用都会为每行数据生成一个单独的RPC请求,即使使用next(int nbRow)方法,也是如此,因为该方法仅仅是在客户端循环地调用next()方法。很显然,当单元格数据较小时,这样做的性能不会很好。因此,如果一次RPC请求可以获取多行数据,这样会更有意义,更加节约资源的使用,减少负载。这样的方法可以由扫描器缓存(scanner caching)实现,默认情况下,这个缓存是关闭的。可以在两个层面上打开他:在表的层面上,这个表所有扫描实例的缓存都会生效;也可以在扫描层面,这样便只会影响当前的扫描实例。
1.开启服务器端扫描器缓存
a)表层面(全局)
<property>
<name>hbase.client.scanner.caching</name>
<!-- 整数最大值 -->
<value>2147483647</value>
<source>hbase-default.xml</source>
</property>
b)操作层面
//设置量
scan.setCaching(10);
代码:
@Test /** * @Description: 扫描器缓存,面向行 * @param ${tags} * @return ${return_type} * @throws * @author 邹培贤 * @date 2018/7/21 15:23 */ public void getScanCache() throws IOException { Configuration conf = HBaseConfiguration.create(); Connection conn = ConnectionFactory.createConnection(conf); TableName tableName = TableName.valueOf("ns1:t1"); Scan scan = new Scan(); //缓存5000行数据,10000条数据只需要2次rpc请求 scan.setCaching(5000); Table table = conn.getTable(tableName); ResultScanner rs = table.getScanner(scan); long start = System.currentTimeMillis(); Iterator<Result> iterator = rs.iterator(); while(iterator.hasNext()){ Result r = iterator.next(); System.out.println(r.getColumnLatestCell(Bytes.toBytes("f1"), Bytes.toBytes("name"))); } System.out.println(System.currentTimeMillis()-start); }
但是,有一个问题存在,那就是,我们如果缓存了太多的数据,直接发给客户端使用,有可能造成客户端无法承受,造成客户端的压力过大。有什么好的方法可以解决呢,那就是使用批处理扫描,就是把从服务器获得的缓存数据再进行按照列的切割,客户端没次next()就会获得由缓存数据切分的多列数据,直到调用完数据这样就不会给客户端造成太大的压力。
@Test /** * @Description:批量扫描,面向列 * @param ${tags} * @return ${return_type} * @throws * @author 邹培贤 * @date 2018/7/21 15:33 */ public void testBatchAndCaching() throws IOException { Configuration conf = HBaseConfiguration.create(); Connection conn = ConnectionFactory.createConnection(conf); TableName tableName = TableName.valueOf("ns1:t7"); Scan scan=new Scan(); //每次缓存多少行数据 scan.setCaching(2); //将缓存的行数据切分4列,每次调用就会返回每行数据的4列数据 scan.setBatch(4); Table table = conn.getTable(tableName); ResultScanner rs = table.getScanner(scan); Iterator<Result> iterator = rs.iterator(); while(iterator.hasNext()){ Result r = iterator.next(); //得到一行的所有map,key=f1,value=Map<Col,Map<Timestamp,value>> NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = r.getMap(); for(Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> entry:map.entrySet()){ //得到列族 String f = Bytes.toString(entry.getKey()); NavigableMap<byte[], NavigableMap<Long, byte[]>> colDataMap = entry.getValue(); for(Map.Entry<byte[], NavigableMap<Long, byte[]>> ets:colDataMap.entrySet()){ String c = Bytes.toString(ets.getKey()); NavigableMap<Long, byte[]> tsValueMap = ets.getValue(); for(Map.Entry<Long, byte[]> e :tsValueMap.entrySet()){ Long ts = e.getKey(); String value = Bytes.toString(e.getValue()); System.out.print(f + "/" + c + "/" + ts + "=" + value + ","); } } } System.out.println(); } }