outline
(一)
HTable的作用
(二)
HTable的特点
1)HTable对象对于客户端读写数据来说不是线程安全的
2
)创建的HTable要尽可能共享Configuration
3
)创建HTable的代价是比较大的
4
)由于HTable创建的代价比较大,因此可以使用HTablePool这个对象池解决
另外HTablePool中维护的所有HTable可以共享Configuration
(三)
1)HTablePool的使用场景,不要混淆
2)HTabelPool的参数
2-1)maxSize指定对象池中保留的个数,HTablePool不会线程请求者获取对象,如果对象池中个数不够会不断创建,只不过这些对象被put回来时不会保留
2-2)如果需要将HTablePool应用于对线程,HTablePool提供了一个线程封闭技术下的方案,保证共享时线程安全。外使用默认类型HTablePool,并发时也OK!
3)HTablePool API
3-1)创建HTablePool
3-2)获取或者回收HTable对象实例
3-3) 关闭HTablePool
0)HTabel
HTable是HBase客户端与HBase服务端通讯的Java API对象,客户端可以通过HTable对象与服务端进行CRUD操作(增删改查)。它的创建很简单:
Configuration conf = HBaseConfiguration.create(); HTable table = new HTable(conf, "tablename"); //TODO CRUD Operation……
1)HTable对象对于客户端读写数据来说不是线程安全的
特别是在客户端auto flash被置为false时,由于存在本地write buffer,在并发线程中共享不是线程安全的
2)创建的HTable要尽可能共享Configuration
HTable对象共享Configuration对象,这样的好处在于:
共享ZooKeeper的连接:每个客户端需要与ZooKeeper建立连接,查询用户的table regions位置,这些信息可以在连接建立后缓存起来共享使用;
共享公共的资源:客户端需要通过ZooKeeper查找-ROOT-和.META.表,这个需要网络传输开销,客户端缓存这些公共资源后能够减少后续的网络传输开销,加快查找过程速度。
3)创建HTable的代价是比较大的
因为客户端创建HTable对象后,需要进行一系列的操作:检查.META.表确认指定名称的HBase表是否存在,表是否有效等等,整个时间开销比较重,可能会耗时几秒钟之长,因此最好在程序启动时一次性创建完成需要的HTable对象,如果使用Java API,一般来说是在构造函数中进行创建,程序启动后直接重用。
根据1),多线程中要使用HTable来执行HBase的CRUD操作,
每个线程都需要各自创建HTable对象。
但是根据2),要尽可能的在同一个线程中需要使用HTable对象的地方共享HTable对象,即一个线程一个,只在线程开始运行
时创建。
4)由于HTable创建的代价比较大,因此可以使用HTablePool这个对象池解决
另外HTablePool中维护的所有HTable可以共享Configuration
但是如果在多线程中使用HTablePool,也要解决线程安全问题的。HTablePool是如何解决的呢?!!!
PoolType.ThreadLocal 类型:
通过线程封闭技术保证了基于从HTablePool中获得HTable的操作是线程安全的。
PoolType.Reusable类型:
应用于多线程场景时需要基于 HTableInterfaceFactory的实现来保证共享的HTable线程安全。
默认实现的HTableInterfaceFactory在HTable入池时调用HTable.close()方法。
这样多线程中复用的HTable实例状态会reset,以此保证了多线程下使用PoolType.Reusable类型的HTablePool线程安全。
HTablePool中所有的HTable对象都共享Configuration
!!!综上:需要使用HTable场景的地方都使用HTablePool
1)HTablePool的使用场景,不要混淆
HTablePool产生的作用是用于复用HTable实例,而不是用来解决共享HTable时的线程安全问题的
但是,不同种类的HTablePool,确实使用了不同的实现方法,保证了再并发线程中使用HTablePool时线程安全的
由此不但单线程中、并发线程中也可以使用HTablePool实现对HTable对象的复用。
2)HTabelPool的参数
2-1)maxSize指定对象池中保留的个数,HTablePool不会线程请求者获取对象,如果对象池中个数不够会不断创建,只不过这些对象被put回来时不会保留
Setting the maxSize parameter during the construction of a pool does not impose an upper limit on the number of HTableInterface instances
the pool is allowing you to retrieve. You can call getTable() as much as you like to get a valid table reference.
The maximum size of the pool only sets the number of HTableInterface instances retained within the pool, for a given table name. For ex-
ample, when you set the size to 5, but then call getTable() 10 times, you have created 10 HTable instances (assuming you use the default). Upon returning them using the putTable() method, five are kept for subsequent use, while the additional five you requested are simply ignored.
More importantly, the release mechanisms of the factory are not invoked.
The maximum size of the pool only sets the number of HTableInterface instances retained within the pool, for a given table name. For ex-
ample, when you set the size to 5, but then call getTable() 10 times, you have created 10 HTable instances (assuming you use the default). Upon returning them using the putTable() method, five are kept for subsequent use, while the additional five you requested are simply ignored.
More importantly, the release mechanisms of the factory are not invoked.
2-2)如果需要将HTablePool应用于对线程,HTablePool提供了一个线程封闭技术下的方案,保证共享时线程安全。外使用默认类型HTablePool,并发时也OK!
PoolType.ThreadLocal 类型:
通过线程封闭技术保证了基于从HTablePool中获得HTable的操作是线程安全的。
PoolType.Reusable类型:
应用于多线程场景时需要基于 HTableInterfaceFactory的实现来保证共享的HTable线程安全。
默认实现的HTableInterfaceFactory在HTable入池时调用HTable.close()方法。
这样多线程中复用的HTable实例状态会reset,以此保证了多线程下使用PoolType.Reusable类型的HTablePool线程安全。
3)HTablePool API
3-1)创建HTablePool
HTablePool()
HTablePool(Configuration config, int maxSize)
HTablePool(Configuration config, int maxSize, HTableInterfaceFactory tableFactory)
HTablePool(Configuration config, int maxSize)
HTablePool(Configuration config, int maxSize, HTableInterfaceFactory tableFactory)
——
HTableInterface createHTableInterface(Configuration config, byte[] tableName)
void releaseHTableInterface(HTableInterface table)
3-2)获取或者回收HTable对象实例
HTableInterface getTable(String tableName)
HTableInterface getTable(byte[] tableName)
void putTable(HTableInterface table)
The getTable() calls retrieve an HTable instance from the pool, while the putTable() returns it after you are done using it. Both internally defer some of the work to the mentioned HTableInterfaceFactory instance the pool is configured with.
HTableInterface getTable(byte[] tableName)
void putTable(HTableInterface table)
The getTable() calls retrieve an HTable instance from the pool, while the putTable() returns it after you are done using it. Both internally defer some of the work to the mentioned HTableInterfaceFactory instance the pool is configured with.
3-3) 关闭HTablePool
void closeTablePool(String tableName)
void closeTablePool(byte[] tableName)
void closeTablePool(byte[] tableName)
The close call of the pool iterates over the list of retained references for a specific table, invoking the release mechanism provided by the factory. This is useful for freeing all resources for a named table, and starting all over again. Keep in mind that for all resources to be released, you would need to call these methods for every table name you have used so far.