HTablePool的实现分析

23 篇文章 0 订阅

1)基本概念

HTablePool

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

2)样例代码

public class HTablePoolTest {  
  
    protected static String TEST_TABLE_NAME = "testtable";  
  
    protected static String ROW1_STR = "row1";  
    protected static String COLFAM1_STR = "colfam1";  
    protected static String QUAL1_STR = "qual1";  
  
    private final static byte[] ROW1 = Bytes.toBytes(ROW1_STR);  
    private final static byte[] COLFAM1 = Bytes.toBytes(COLFAM1_STR);  
    private final static byte[] QUAL1 = Bytes.toBytes(QUAL1_STR);  
  
    private static HTablePool pool;  
  
    @BeforeClass  
    public static void runBeforeClass() throws IOException {  
        Configuration conf = HBaseConfiguration.create();  
        pool = new HTablePool(conf, 10);  
  
        // 填充pool  
        HTableInterface[] tables = new HTableInterface[10];  
        for (int n = 0; n < 10; n++) {  
            tables[n] = pool.getTable(TEST_TABLE_NAME);  
        }  
        for (HTableInterface table : tables) {  
            table.close();  
        }  
    }  
  
    @Test  
    public void testHTablePool() throws IOException, InterruptedException,  
            ExecutionException {  
  
        Callable<Result> callable = new Callable<Result>() {  
            public Result call() throws Exception {  
                return get();  
            }  
        };  
          
        FutureTask<Result> task1 = new FutureTask<Result>(callable);  
  
        FutureTask<Result> task2 = new FutureTask<Result>(callable);  
  
        Thread thread1 = new Thread(task1, "THREAD-1");  
        thread1.start();  
        Thread thread2 = new Thread(task2, "THREAD-2");  
        thread2.start();  
  
        Result result1 = task1.get();  
        assertThat(Bytes.toString(result1.getValue(COLFAM1, QUAL1)), is("val1"));  
  
        Result result2 = task2.get();  
        assertThat(Bytes.toString(result2.getValue(COLFAM1, QUAL1)), is("val1"));  
  
    }  
  
    private Result get() {  
        HTableInterface table = pool.getTable(TEST_TABLE_NAME);  
        Get get = new Get(ROW1);  
        try {  
            Result result = table.get(get);  
            return result;  
        } catch (IOException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
            return null;  
        } finally {  
            try {  
                table.close();  
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  
  
} 


  • 使用多线程访问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);

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值