hbase学习笔记7-计数器,协处理器和HTablePool
二、计数器(Counter)
Hbase提供一个计数器工具可以方便快速的进行计数的操作,而免去了加锁等保证原子性的操作。但是实质上,计数器还是列,有自己的簇和列名。值得注意的是,维护计数器的值最好是用Hbase提供的API,直接操作更新很容易引起数据的混乱。
计数器的增量可以是正数负数,正数代表加,负数代表减。
long icrementColumnValue(byte[] row, byte[] famuly, byte[] qualifier, long amount)
Result increment(Increment increment)
三、协处理器(Coprocessor)
协处理器的思想是把处理的复杂代码分发到各个RegionServer,使大部分的计算可以在服务器端,或者扫描的时候完成,提高处理的效率。形式上比较类似RDBMS中的存储过程,不同的是,存储过程的原理是在服务器端进行预处理等优化,而协处理器仅仅只是服务器处理,这里又有点类似于Map-Reduce中的Map阶段。
协处理器(Coprocesssor)有两种,一种是观察者(Obsever)另外一种是Endpoint(LZ跪了,实在不知道翻译成啥)。
每个协处理器都有一个优先级,优先级分为USER/SYSTEM,优先级决定处理器的执行顺序,SYSTEM级别的处理器永远先于USER。
每个处理器都有自己的执行环境(CoprocessorEnvironment),这个环境包含当前集群和请求的状态等信息,是处理中重要的一部分,以构造函数参数的形式被传入到处理器。
另外就是CoprocessorHost,这是Hbase管理协处理器的类,用来维护所有的处理器和其环境
协处理器的加载有两种方式,一种是通过配置文件,在配置文件中指定加载路径、类名等,通过这种方式加载的处理器都是SYSTEM级别的,会作用于所有的请求,所有的表;另一种方式是通过在创建表的时候在表中指定,这种方式既可以创建全局的SYSTEM级别的处理器,也可以创建USER级别的处理器,USER级别的处理器是针对表的。
Path path = new Paht("test.jar");
HTableDescriptor htd = new HTableDescriptor("test");
htd.addFamily(new HColumnDescriptor("family1"));
htd.setValue("Coprocessor$1", path.toString + "|" + className + "|" + Coprocessor.Priority.USER);
HBaseAdmin admin = new HBaseAdmin(conf);
admin.createTable(htd);
这里setValue方法有两个参数,第一个参数是协处理器的名字,$后面跟的是影响执行顺序的序号;第二个参数是<path>|<classname>|<priority>。
Observer
这是第一种处理器,观察者,观察者有三种,分别用来监听RegionServerObserver、MasterServerObserver、WALObserver。
RegionServer监听的是Region Server上的操作,如在Region Server上的Get、Put等。操作被赋予生命周期:Pending open--open--Pending close
监听器是可以监听生命周期中的各个阶段,并对其做出处理。
每一个监听的方法都有一个上下文参数(Context),通过Context参数可以直接的操作请求的声明周期。
void bypass();
void complete();
MasterObserver监听的是Master Server上的操作,有点类似RDBMS中的DDL的操作如表操作、列操作等。
具体的操作和RegionServer比较类似。
Endpoint
这是第二种处理器,Endpoint相当于被分发到各个RegionServer上的存储过程,可以在客户端远程调用的方法。Endpoint的存在使我们可以进行一些服务器端的计算,如服务器聚集、求和等运算,弥补了查询API的不足。服务器端计算的优势是显而易见的,它可以降低网络传输的数据量,合理利用服务器资源。
从功能上可以看出Endpoint是一个基于RPC调用的模块,所以在实现自己的Endpoint时候需要定义我们自己的通信协议。在Hbase中,通信协议被抽象为CoprocessorProtocol接口,要实现我们的协议,我们要创建协议接口继承自CoprocessorProtocol接口,然后再实现我们的协议类。
public interface MyProtocol extends CoprocessorProtocol {
public int work();
}
协议类本身也是处理器,所以还要继承BaseEndpointCoprocessor类。
public class MyEndpoint extends BaseEndpointCoprocessor implements MyProtocol {
public int work() {
Sytem.out.println("hello");
}
}
在抽象的父类BaseEndpointCoprocessor中还提供了一些有用的方法,如我们可以拿到对应的环境类。
RegionCoprocessorEnvironment getEnvironment()
配置好Endpoint重启集群环境以后,我们的实现类会被分发到各个RegionServer,通过HTable实例的方法我们可以调用到Endpoint。
<T extends CoprocessorProtocol, R> Map<byte[], R> coprocessorExec(Class<T> protocol, byte[] startKey, byte[] endKey, Batch.Call<T, R> callable);
startKey和endKey用于确定哪些RegionServer将执行Endpoint, Batch中的内部类将决定协议中方法的调用。
四、 HTablePool 连接池
在Hbase中,创建一个代表表的HTable实例是一个耗时且很占资源的操作,类似操作数据库,我们也需要建立我们自己的连接池,于是有了代表连接池的抽象类:HTable。
HTablePool(Configuaration conf, int maxSize)
HTablePool(Configuaration conf, int maxSize, HTableInterfaceFactory factory)
创建HTable需要配置文件的实例,连接池的最大连接数也在构造方法中设置。另外,如果想要自己控制HTable被创建的过程,则需要实现自己的工厂方法。在连接池中,最大连接数(maxSize)的含义是,连接池管理的最大的连接数,当所需要的连接数超过最大值时,会临时的创建连接来满足需求,但是这些连接在使用完毕之后会被直接释放且丢弃而不会进入连接池被管理,所以最大连接数代表的是连接池中最大被管理的连接数,而不是使用连接池最大可使用的连接数。
HTableInterface getTable(String tableName)
HTableInterface getTable(byte[] tableName)
void putTable(HTableInterface table)
需要注意的是,使用完连接以后需要手动的调用putTable方法将连接放回池中。