1.设置Scan缓存

  1. 1.scan中的setCachingsetBatch方法的区别是什么呢?
  2. setCaching设置的值为每次rpc的请求记录数,默认是1cache大可以优化性能,但是太大了会花费很长的时间进行一次传输。
  3. setBatch设置每次取的column size;有些row特别大,所以需要分开传给client,就是一次传一个row的几个column
  4. batchcachinghbase table column size共同决意了rpc的次数。

setCaching源码-

  1. HTable table = new HTable(config, Bytes.toBytes(tableName));
  2. Scan scanner = new Scan();
  3. /* batch and caching*/
  4. scanner.setBatch(0);
  5. scanner.setCaching(10000);
  6. ResultScnner rsScanner = table.getScanner(scanner);
  7. for(Result res:rsScanner) {
  8. final List<KeyValue> list = res.list();
  9. String rk = null;
  10. StringBuilder sb = new StringBuilder();
  11. for( final KeyValue kv:list) {
  12. sb.append(Bytes.toStringBinary(kv.getValue)) + ",");
  13. rk = getRealRowkey(kv);
  14. }
  15. if(sb.toString().length()>0) {
  16. sb.setLength(sb.toString().length() - 1);
  17. }
  18. System.out.println(rk + "\t" + sb.toString());
  19. }
  20. rsScanner.close();

2.显式地指定列

因为服务器端处理完的结果,需要通过网络传输到客户端,此时,传输的数据量成为瓶颈,如果能有效地过滤部分数据,使用更精确的需求,能够很大程度上减少网络I/O的花费,否则会造成很大的资源浪费。查询过程中,指定某列,或几列,能够有效减少网络传输量

  1. HTable table = new HTable(config, Bytes.toBytes(tableName));
  2. Scan scanner = new Scan();
  3. // 指定列族
  4. scanner.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(column));
  5. /* batch and caching*/
  6. //scanner.setBatch(0);
  7. //scanner.setCaching(10000);
  8. ResultScnner rsScanner = table.getScanner(scanner);
  9. for(Result res:rsScanner) {
  10. final List<KeyValue> list = res.list();
  11. String rk = null;
  12. StringBuilder sb = new StringBuilder();
  13. for( final KeyValue kv:list) {
  14. sb.append(Bytes.toStringBinary(kv.getValue)) + ",");
  15. rk = getRealRowkey(kv);
  16. }
  17. if(sb.toString().length()>0) {
  18. sb.setLength(sb.toString().length() - 1);
  19. }
  20. System.out.println(rk + "\t" + sb.toString());
  21. }
  22. rsScanner.close();

3.关闭ResultScanner

  1. ResultScanner类用于存储服务端扫描的最终结果,可以通过遍历该类获取查询结果。但是,如果不关闭该类,可能出出现服务端在一段时间内一直保持连接,资源无法释放,从而导致服务器端某些资源的不可用,还有可能引发RegionServer的其他问题。

在 上例代码中最后一行

4.禁用块缓存

  1. Scan扫描中可以使用块缓存,通过setCacheBlocks() 方法控制。
  2. 如果批量进行全表扫描,例如MapReduce任务读取全表数据,需要将该值设置为false。默认是true。因为全表扫描,每条记录只读取一遍,如果使用块缓存,会降低扫描的效率,但是,对于经常读到的行,建议使用默认值,即使用块缓存。

5.优化行健查询

  1. 对表进行全表Scan的时候,如果仅需要行健,而不需要列族,列名,值和时间戳等消息,可以使用过滤器来减少服务器端返回的数据量,降低网络I/O
  2. 使用方法是:使用ScansetFilter()方法,添加MUST_PASS_ALL操作参数,使用FilterList封装两个过滤器。一个是FirstKeyOnlyFilter,另一个是KeyOnlyFilter。通过这样的过滤器组合,就算在最坏的情况下,RegionServer只会从磁盘读取一个值,同时最小化客户端的网络带宽占用。

6.通过HTableTool访问

  1. HTable对象对于客户端读取数据来说不是线程安全的,因此多线程时,要为每个线程单独创建复用一个HTable对象,不同对象间不要共享HTable对象使用,特别是在客户端AutoFlush被设置为false时,由于存在本地WriteBuffer,可能导致数据不一致。
  2. HTablePool连接池机制可以解决HTable存在的线程不安全问题,同时通过维护固定数量的HTable对象,能够在程序运行期间复用这些HTable资源对象,以节省资源创建时间和降低内存使用空间。HTablePool的使用方法如下:
  1. Public class HTablePoolTest{
  2. protected static String TEST_TABLE_NAME="testtable";
  3. protected static String ROW1_STR="r1";
  4. protected static String COLFAM1_STR="cf1";
  5. protected static String QUAL1_STR="testtable";
  6. private final static byte[] ROW1 = Bytes.toBytes(ROW1_STR);
  7. private final static byte[] COLFAM1=Bytes.toBytes(COLFAM1_STR);
  8. private final static byte[] QUAL1 = Bytes.toBytes(QUAL1_STR);
  9. private static HTablePool pool;
  10. public static init() throws IOException {
  11. Configuration conf = HBaseConfiguration.create();
  12. pool = new HTablePool(conf,10);
  13. // 填充线程池
  14. HTableInterface[] tables = new HTableInterface[10];
  15. for(int i = 0; i < 10; n++) {
  16. tables[n] = pool.getTable(TEST_TABLE_NAME);
  17. }
  18. for(HTableInterface table:tables) {
  19. table.close();
  20. }
  21. }
  22. private Result get() {
  23. HTableInterface table = pool.getTable(TEST_TABLE_NAME);
  24. Get get = new Get(ROW1);
  25. try{
  26. Result result = table.get(get);
  27. return result;
  28. } catch(IOException e) {
  29. } finally {
  30. try {
  31. table.close();
  32. }
  33. }
  34. }
  35. }