HTablePool的实现分析

来源:互联网 发布:movielens数据集下载 编辑:程序博客网 时间:2024/06/03 08:17

1)基本概念

HTablePool

  • ​3种类型
    • ​PoolType.Reusable(默认)一个实例池,多线程复用,内部是每个table一个ConcurrentLinkedQueue装多个实例
    • PoolType.ThreadLocal,很奇怪的实现,每个线程只能有一个实例,感觉在多线程的场景没有意义
    • PoolType.RoundRobin​(没有被使用,就算设置了该类型也没用,见HTablePool的构造函数)
  • PoolMap<String, HTableInterface> tables​:用于存放table实例,正如上面提到的默认是每个table对应一个ConcurrentLinkedQueue​
  • maxSize:pool的最大尺寸​

2)样例代码

[java] view plaincopy
  1. public class HTablePoolTest {  
  2.   
  3.     protected static String TEST_TABLE_NAME = "testtable";  
  4.   
  5.     protected static String ROW1_STR = "row1";  
  6.     protected static String COLFAM1_STR = "colfam1";  
  7.     protected static String QUAL1_STR = "qual1";  
  8.   
  9.     private final static byte[] ROW1 = Bytes.toBytes(ROW1_STR);  
  10.     private final static byte[] COLFAM1 = Bytes.toBytes(COLFAM1_STR);  
  11.     private final static byte[] QUAL1 = Bytes.toBytes(QUAL1_STR);  
  12.   
  13.     private static HTablePool pool;  
  14.   
  15.     @BeforeClass  
  16.     public static void runBeforeClass() throws IOException {  
  17.         Configuration conf = HBaseConfiguration.create();  
  18.         pool = new HTablePool(conf, 10);  
  19.   
  20.         // 填充pool  
  21.         HTableInterface[] tables = new HTableInterface[10];  
  22.         for (int n = 0; n < 10; n++) {  
  23.             tables[n] = pool.getTable(TEST_TABLE_NAME);  
  24.         }  
  25.         for (HTableInterface table : tables) {  
  26.             table.close();  
  27.         }  
  28.     }  
  29.   
  30.     @Test  
  31.     public void testHTablePool() throws IOException, InterruptedException,  
  32.             ExecutionException {  
  33.   
  34.         Callable<Result> callable = new Callable<Result>() {  
  35.             public Result call() throws Exception {  
  36.                 return get();  
  37.             }  
  38.         };  
  39.           
  40.         FutureTask<Result> task1 = new FutureTask<Result>(callable);  
  41.   
  42.         FutureTask<Result> task2 = new FutureTask<Result>(callable);  
  43.   
  44.         Thread thread1 = new Thread(task1, "THREAD-1");  
  45.         thread1.start();  
  46.         Thread thread2 = new Thread(task2, "THREAD-2");  
  47.         thread2.start();  
  48.   
  49.         Result result1 = task1.get();  
  50.         assertThat(Bytes.toString(result1.getValue(COLFAM1, QUAL1)), is("val1"));  
  51.   
  52.         Result result2 = task2.get();  
  53.         assertThat(Bytes.toString(result2.getValue(COLFAM1, QUAL1)), is("val1"));  
  54.   
  55.     }  
  56.   
  57.     private Result get() {  
  58.         HTableInterface table = pool.getTable(TEST_TABLE_NAME);  
  59.         Get get = new Get(ROW1);  
  60.         try {  
  61.             Result result = table.get(get);  
  62.             return result;  
  63.         } catch (IOException e) {  
  64.             // TODO Auto-generated catch block  
  65.             e.printStackTrace();  
  66.             return null;  
  67.         } finally {  
  68.             try {  
  69.                 table.close();  
  70.             } catch (IOException e) {  
  71.                 // TODO Auto-generated catch block  
  72.                 e.printStackTrace();  
  73.             }  
  74.         }  
  75.     }  
  76.   
  77. }  
  • 使用多线程访问HTablePool

3)关键点分析

3.1)初始化

HTablePool pool = new HTablePool(conf, 5);

  • 实例化PoolMap
  • ​实例化HTablePool,此时还没有任何HTable实例​,tables为空

3.2)获取table实例

pool.getTable(TEST_TABLE_NAME);​
  • 查看tables是否含有table,如果没有,创建一个HTable实例,HTable的初始化具体的细节见我的博文http://blog.csdn.net/pwlazy/article/details/7417135
  • 将返回HTable实例封装成PooledHTable实例返回
  • PooledHTable是​HTable的一个Wrapper,除了close()不一样,​PooledHTable的close会将​HTable实例返回到上面提到的tables中
  • 所以tables确实存放的是HTable实例,但取出来丢给应用程序的就是PooledHTable实例

3.3)table.get(get);

  • 从regionserver获取数据
  • ​该动作具体的详细细节见我的博文http://blog.csdn.net/pwlazy/article/details/7417135​

3.4)table.close();

  • 将table归还到​HTablePool中,如果此时​HTablePool尺寸超过最大尺寸,释放该实例​,
  • 关于释放HTable实例与释放连接的问题
    • HTable实例相关的两个连接,一个是对zookeeper,一个是regionServer
    • 如果没有其他HTable实例​(在HTablePool尺寸大于0的情况不可能出现这种情况),及没有zookeeper的连接计数为0,此时才会释放zookeeper连接
    • ​regionServer的连接有HBaseClient$Connection这个线程单独维护,与HTable实例基本没啥关系,注意HBaseClient$Connection这个线程绑定了连接
4)总体看HTablePool
  • ​容纳了多个HTable实例
  • 多个HTable实例会共享同一个zookeeper连接
  • 多个HTable实例,如果同在一个RegionServer会共享同一个连接HBaseClient$Connection
  • 很容易让人误解每个HTable实例都有一个HBaseClient$Connection,就像连接池那样,其实不是
  • 虽然HTablePool有最大尺寸,但并没有限制HTable实例不得大于这个尺寸,一旦超过这个尺寸就会实例化,但归还到实例池的时候,如果池满了会弃用,因此​HTablePool就是一个对象池而不是连接池
  • 使用HTablePool的意义?《 HBase-The-Definitive-Guide​》 作者是这么说的
    • ​实例化HTable实例比较耗时,最好启动时初始化(这个理由不是很充分,完全可以使用HTable单例)
    • HTable实例线程不安全,特别是在auto flash为false的情况,因为存在本地的write buffer   ,即使​auto flash为true, 也不建议使用(对此作者并没说为什么​)
    • 建议每个线程一个HTable实例
  • HTablePool存在的问题​​​​​
    • ​PooledHTable的代码很恶心,PooledHTable作为一个HTable的wrapper,两者的关系应该是包含,但源码中却是继承
    • ​HTablePool并不是连接池,就是直接使用​HBaseClient$Connection【如果是同一个region的话就是单线程】来完成网络通讯的,后者的问题在​我的博文http://blog.csdn.net/pwlazy/article/details/7417135有提到, 的确存在多个线程使用​单个HBaseClient$Connection而带来同步和阻塞的问题,线上使用必须好好的压力测试一下
0 0
原创粉丝点击