HTablePool的实现分析

1)基本概念

HTablePool

  • ​3种类型
    • ​PoolType.Reusable(默认)一个实例池,多线程复用,内部是每个table一个ConcurrentLinkedQueue装多个实例
    • PoolType.ThreadLocal,很奇怪的实现,每个线程只能有一个实例,感觉在多线程的场景没有意义
    • PoolType.RoundRobin​(没有被使用,就算设置了该类型也没用,见HTablePool的构造函数)
  • PoolMap 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 callable = new Callable() {
			public Result call() throws Exception {
				return get();
			}
		};
		
		FutureTask task1 = new FutureTask(callable);

		FutureTask task2 = new FutureTask(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);

  • 从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而带来同步和阻塞的问题,线上使用必须好好的压力测试一下

你可能感兴趣的:(hbase)