一、介绍

如果在HBase中使用某一行的值进行Put操作进行计数器功能,为了保证原子性操作,必然会导致一个客户端对计数器所在行的资源占有,如果在大量进行计数器操作时,则会占有大量资源,并且一旦某一客户端崩溃,将会使得其他客户端进入长时间等待。HBase中定义了一个计数器来完成用户的技术操作,并且防止资源占有问题,并且也保证其原子性。

二、解释

1、创建计数器

在HBase中,HBase将某一列作为计数器来使用,因此创建计数器与创建行是相同的,因此创建计数器时不需要特定的创建流程,因为HBase的列具有动态添加的特性,使得计数器跟列具有相同的特性:动态添加。在第一次使用时计数器(实质为列)隐藏的进行了创建。

2、计数器的增加

计数器增加值是增加一个long值,其增加的值也有负有正,不同的数据进行增加时有不同的效果:

大于0:增加计数器的值

等于0:不更改计数器的值

小于0:减少计数器的值

需要注意的是,计数器的值增加的是一个long类型的整数,而不是一个字符串,有时候增减一个字符串会发现结果值会突然增大很多。

3、Shell使用

HBase shell环境也提供了计数器的操作,其命令结构为: incr <tablename>,<rowkey>,<family:qualifier>,long n

hbase(main):003:0> incr 'test','row-cr','test:incr',1
COUNTER VALUE = 1
0 row(s) in 0.1560 seconds

hbase(main):004:0> incr 'test','row-cr','test:incr',1
COUNTER VALUE = 2
0 row(s) in 0.0080 seconds

在进行完计数器增加后,计数器的值立刻被返回给客户端。

4、单列增加

在HTable客户端中提供了多个对计数器进行增加的API方法,这里先介绍HTable直接对计数器进行增加:

incrementColumnValue(byte[] row,byte[] family, byte[] qualifier,long amount)
incrementColumnValue(byte[] row,byte[] family, byte[] qualifier,long amount,boolean writeToWAL)
incrementColumnValue(byte[] row,byte[] family, byte[] qualifier,long amount,Durability durability)

这三个函数都是直接对表中的某一行数据进行添加,不过后两个函数定义了是否将数据写入到预写日志文件的模式,着三个函数都返回进行增加后的计数器的值。

/**
	 * @author wozipa
	 * @Date 2016-3-16 19:13
	 * @see 测试htable自带的技术及效果
	 */
	public void singleIncreament()
	{
		Configuration conf=init();
		try {
			//创建表连接
			HTable table=new HTable(conf,"test");
			//进行已经存在的计数器的增加
			long incr1=table.incrementColumnValue(Bytes.toBytes("row-cr"),Bytes.toBytes("test"),Bytes.toBytes("incr"),2);
			System.out.println(incr1);
			//创建新的计数器
			long incr22=table.incrementColumnValue(Bytes.toBytes("row-cr"),Bytes.toBytes("test"),Bytes.toBytes("incr2"),10);
			System.out.println(incr22);
			//
			table.close();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

5、多列增加

Htable直接对计数器进行增加的话可能只能增加一行,如果对一行中的多个计数器进行增加则需要多次发送RPC请求,在新版本的HBaseAPI结果中提供了对一行中的多个计数器进行增加的API:

incrementColumnValue(Increment increment)

/**
	 * @author wozipa
	 * @Date 2016-3-16 19:25
	 * @see 使用Increment对象进行单行多列的计数器增加
	 */
	public void mutilIncreament()
	{
		Configuration conf=init();
		try {
			HTable table=new HTable(conf,"test");
			Increment increment=new Increment(Bytes.toBytes("row-rc"));
			increment.addColumn(Bytes.toBytes("test"),Bytes.toBytes("incr"),6);
			increment.addColumn(Bytes.toBytes("test"),Bytes.toBytes("incr2"),10);
			Result result=table.increment(increment);
			//对该行数据进行展示
			KeyValue[] kvs=result.raw();
			for(KeyValue kv:kvs)
			{
				System.out.println(kv.toString());
				System.out.println(Bytes.toString(kv.getValue()));
			}
			table.close();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

Increament的使用方法和Put、Get等方法是相似的,并且返回一个result对象将整行数据进行返回。

Increment对象也提供了很多方法进行设置:
(1)setWriteToWAL(boolean write)

是否将该操作写入到预先日志HLog中

(2)setDurability(Durability

设置读写日志写入的模式。

(3)setReturnResults(boolean returnResults)

是否将计数器结果值进行返回。

Increment对象还提供了其他方法,这里不再进行详细的解释了,可以通过API文档进行详细的查看。

三、总结

在HBase中,用户可以使用HBase自己提供的计数器进行操作,这样可以提高效率和稳定性。