【HBase】16-计数器

许多收集统计信息的应用有点击流或在线广告意见,这些应用需要被收集到日志文件中用于后续的分析。用户可以使用计数器做实时统计,从而放弃延时较高的批量处理操作。

1、计数器简介

与之前介绍的原子操作检查并修改( check-and- modify)一样, HBase也有一种机制可以将列当作计数器。否则,如果用户需要对一行数据加锁,然后读取数据,再对当前数据做加法,最后写回 HBase并释放该行锁,从而其他写程序可以访问该行数据。这样做会引起大量的资源竞争问题,尤其是当客户端进程崩溃之后,尚未释放的锁需要等待超时恢复——这会在一个高负载的系统中引起灾难性的后果。
客户端API提供了专门的方法来完成这种读取并修改(read-and-modify)操作,同时在单独一次客户端的调用过程中保证原子性。早期的HBae版本只会在每次计数器更新操作中使用一个RPC请求,不过新版本的HBase中CRUD操作开始使用与此相同的机制,让许多更新计数器的请求都可以在一次RPC中完成。
虽然用户可以一次更新多个计数器,但它们都必须属于同一行。更新多行的计数器需要通过独立的API调用,即多个RPC请求。 batch()方法调用目前并不支持 Increment实例,不过这种情况今后可能会改变。
用户分别了解每个类型之前,还需要了解一些计数器在列一级的工作细节。以下是用She创建表之后,两次增加同一个计数器的值,最后查询计数器当前值的例子。

每次incr调用返回这个计数器的新值。最后检查时使用了 get counter,并显示当前计数器值与所预期的一致。
终端的incr命令格式如下:
incr '<table>','<row>','<column>',[increment-value>]

用户可以使用get请求访问这个计数器,结果如下:

这样得到的结果可读性较差,但是这表明了一个计数器就是一个与其他列类似的简单列。用户也可以指定一个更大的递增值:

用户直接读取计数器时得到的是字节数组, Shell把每个字节按十六进制数打印。使用get counter可以以可读格式返回数据,并确认递增数据可行,并且与预期一致。
最后,用户不只可以用incr命令来对一个计数器加值,也可以取回计数器当前值或者减少当前值。实际上,用户也可以完全忽略初始值,默认情况下是1。

使用增加值,即incr命令的最后一个参数,用户可以在下表中观察不同值带来的行为影响。

增加值和对计数器产生的作用
作用
比零大的值按给定值增加计数器中的数值
得到计数器的当前值,与She命令 get_counter的返回值相同
比零小的值减少计数器的当前值

显然,使用incr命令只能一次操作一个计数器。用户也可以使用后面介绍的客户端API操作计数器。

2、单计数器

第一种增加操作只能操作一个计数器:用户需要自己设定列,方法由 Table提供,如下所示
long increment Column value(byte [] row, byte[] family, byte l] qualifier,long amount)throws IOException
long increment ColumnValue(byte [] row, byte[] family, byte[] qualifier,long amount, boolean writeToWAL) throws IOException
这两种方法都需要提供列的坐标( coordinates)和增加值,除此之外这两种方法只在参数 writeToWAL上有差别,这个参数的作用与put, setWriteToWAL()方法一致。
忽略该参数会直接使用默认值true,也就是说,WAL是有效的。
抛开这个参数,用户可以按照下面的示例轻松地使用这些方法。

  1. 计数器值加1。
  2. 第二次给计数器值加1。
  3. 得到计数器当前值,不做自增操作。
  4. 计数器值减1。

对应的输出如下:

与之前使用的 Shell 1命令一样,API调用也有相同的作用:使用正值时增加了计数器的值,使用0时可以得到当前计数器的值,使用负值时可以减少当前计数器的值。

3、多计数器

另一个增加计数器值的途径是 HTable()的方法 increment()。工作模式与CRUD操作类似,请使用以下方法完成该功能:
Result increment(Increment increment) throws IOException
用户需要创建一个 Increment实例,同时需要填充一些相应的细节到该实例中,例如,计数器的坐标。构造器如下:
Increment(){}
Increment (byte[] row)
Increment(byte[] row, RowLock rowLock)
用户构造 Increment实例时需要传入行键,此行应当包含此实例需要通过 increment()方法修改的所有计数器。
可选参数 rowlock设置了用户自定义锁实例,这样可以使本次操作完全在用户的控制下完成,例如,当用户需要多次修改同一行时,可以保证其间此行不被其他写程序修改。
虽然用户可以限制其他写程序修改此行的值,但是用户无法限制读操作。事实上,这里并没有保证读操作的原子性因为读操作不需要获取锁,所以它可能读到一行中被修改到一半的数据!scan和gt操作同样会出现这种情况。
一旦用户使用行键创建了一个 Increment实例,就需要向其中加入实际的计数器,也就是说,用户需要增加列,使用方法如下:
Increment addcolumn(byte[] family, byte [l qualifier, long amount)
与Put方法不同的地方是没有选项来设置版本或时间戳:当做增加操作时,版本都被隐式处理了。同样,这里没有 addFamily()方法,因为计数器都是特定的列,所以需要特定如此,因此去添加一个列族是没有意义的。
Increment类的特别功能是可以添加一个时间范围:
Increment setTimeRange(long minstamp, long maxStamp) throws IoException
设定计数器的时间范围与之前提到的版本被隐式处理相比有些奇怪。时间范围被送到服务器端来限制内部的get操作来取得当前这些计数器的值。用户可以使用它来使计数器过期( expire),例如,用时间划分一行的计数器:用户限制时间范围,可以用来屏蔽比较老的计数器,使它们看上去不存在。一次增加操作会认为这此较老的计数器不存在,并把它们重置为1。
Increment类提供的其他方法见下表。

Increment类的附加方法概览
方法描述
getRow()返回创建 Increment实例时指定的行键值
getRowLock()返回当前 Increment实例中的 Rowlock实例
getLockId()返回构造器中可选参数 rowLock的锁ID,如果没有设置的话,默认该值为-1L
setWriteToWAL()允许用户禁用本次操作服务器端默认的WAL功能
getwriteToWAL()返回是否在本次操作中启用wAL功能
getTimeRange()返回与 Increment实例相关的时间范围,可以使用 setTimeStamp()方法进行设定
numFamilies()便捷地取回 FamilyMap的大小,其中包括添加的所有列的列族
numColumns()返回将要被处理的列的数目
hasFamilies()检查是否有列或列族被添加到这个 Increment实例中
Familyset()/getFamilyMap()使用户可以访问addColumn()方法添加的列。FamilyMap的键存储的是列族名称,相应的值是添加过的列族下列的列表。 familySet()方法返回一个列族的set实例,换句话说就是一个只包括列族名
的集合

与上面命令行的例子相似,下面例自使用了多个增加值来增加、获取或减少一个计数器的值。
增加一行中多个计数器的计数

  1. 使用不同的增加值增加计数器的计数。
  2. 使用上述的计数器更新值调用实际的增加方法,并得到返回结果。
  3. 打印 Keyvaule和返回的计数器计数结果。
  4. 使用正、负和零增加值来修改计数器值。

运行上面例子的输出如下:


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值