2014-08-12 09:26:29
来 源
中存储网
HBase
在 HBase: The Definitive Guide 中, Lars George 介绍了 HBase 的一个新特性 Counter Increment,至于 increment 的性能如何,我们只有做测试才能知道。YCSB 已经提供了 Read-Modify-Write 的测试接口,而 increment 接口需要自己完成2。

在 HBase: The Definitive Guide 中, Lars George 介绍了 HBase 的一个新特性 Counter Increment,即把一个 column 当作 一个 counter,这样便于给某些在线应用提供实时统计功能。(PS:比如帖子的实时浏览量:PV)

传统上,如果没有 counter,当我们要给一个 column 的值 +1 或者其他数值时,就需要先从该 column 读取值,然后在客户端修改值,最后写回给 Region Server,即一个 Read-Modify-Write (RMW) 操作。在这样的过程中,按照 Lars 的描述1,还需要对操作所在的 row 事先加锁,事后解锁。这会引起许多 contention,以及随之而来的很多问题。而 HBase 的 increment 接口就保证在 Region Server 端原子性的完成一个客户端请求。

至于 increment 的性能如何,我们只有做测试才能知道。YCSB 已经提供了 Read-Modify-Write 的测试接口,而 increment 接口需要自己完成2。

然后新建 YCSB 的 workload 配置文件:

recordcount=12000

operationcount=12000000

workload=com.yahoo.ycsb.workloads.CoreWorkload

readallfields=false

incrementproportion=1

readproportion=0

updateproportion=0

scanproportion=0

insertproportion=0

requestdistribution=zipfan

recordcount=12000

operationcount=12000000

workload=com.yahoo.ycsb.workloads.CoreWorkload

readallfields=false

readproportion=0

updateproportion=0

scanproportion=0

insertproportion=0

readmodifywriteproportion=1

requestdistribution=zipfan

测试放在集群上进行:1台 master,6台 regionserver,独立的 zookeeper 集群;底层 HDFS 与 HBase 重叠。当前每个 Region Server 负责 255 左右的 region。YCSB 在另一台机器上,开 120 个线程。测试结果如下。

首先看 throughput:

测试图说明测试的时间基本上已经足够长,性能的波动也有反映出来。RMW 虽然波动较大,但总体性能居然优于 Increment,这是比较意外的事情。而 Increment 的表现非常稳定。从箱线图的角度来看也一致。Latency 的情况类似。

最后对测试结果做下简单的分析。出乎意料,RMW 没有想象的那么差,不过中间波动的情况值得深究一下;Increment 的平均 latency 在 10ms 左右,比 RMW 的 15ms 要好,而且几乎没有性能波动现象。

仔细分析 YCSB 的 RMW 操作的代码,它其实只是简单的将 read() 和 update() 封装起来3:

db.read (table,keyname,fields, new HashMap < String,String > ( ) ) ;

db.update (table,keyname,values ) ;

它并没有对所操作的 row 进行加锁、解锁操作,而是简单的读取改写。这在 counter 的应用场景中是不可接受的。不加锁在大并发情况下,很容易导致 counter 的值与预期不符。

继续修改 YCSB,由发起请求的客户端对相应的 row 加锁4。之后再进行 Increment 与 RMW 之间的性能比较。

可以预期的是新的 RMW 的性能会非常的差。这里给个测试结果的片段:

200 sec: 15818 operations; 91.3 current ops/sec; [RMW AverageLatency(ms)=2903.83]

210 sec: 15818 operations; 0 current ops/sec;

220 sec: 15818 operations; 0 current ops/sec;

230 sec: 16880 operations; 106.2 current ops/sec; [RMW AverageLatency(ms)=3136.13]

240 sec: 16880 operations; 0 current ops/sec;

250 sec: 16880 operations; 0 current ops/sec;

260 sec: 17747 operations; 86.69 current ops/sec; [RMW AverageLatency(ms)=4262.21]

270 sec: 17747 operations; 0 current ops/sec;

280 sec: 17747 operations; 0 current ops/sec;

290 sec: 18412 operations; 66.5 current ops/sec; [RMW AverageLatency(ms)=5508.39]

在这里修改 RMW 中的关键代码在于:

lock  = _hTable.lockRow (Bytes.toBytes (key) ) ;

r  = _hTable.get (g ) ;

_hTable.put (p ) ;

_hTable.unlockRow (lock ) ;

即在读之前先加锁,写之后放锁。之前的 RMW 的瓶颈在 Read 操作,并且 put 操作可以在 server 端批处理;而这里,锁的引入导致线程间的 contention 陡增。也就是说,线程数量的增加不一定会带来性能的提升,可能反而使性能变差。我们可以以线程数为变量做些测试(以 100s 为限)。

可以看到当线程数超过 16 之后,throughput 反而稍微变差了,更糟糕的是,latency 大幅度的提升。当线程数定在 128 时,情况就变的非常糟糕:latency 基本上是几秒,或者 NA;而 throughput 只能维持在 200 左右。这验证了之前的想法。

所以 HBase 引入 Increment/Counter 是非常重要的,对某些需要原子性更改操作的应用来说则是“致命”的。除了单个 increment 的接口 incrementColumnValue() 外,还有批量 increment 的接口increment(Increment),方便客户端调用。

除此之外,HBase 还在进行 Coprocessor 的开发,使计算直接在 Region Server 上进行,省去了繁琐耗时的数据移动。(PS:这就是所谓的移动计算比移动数据更划算)

Tips:以上测试数据由于 Hbase 版本很老,加上作者硬件、集群规模限制,仅供参考~

声明: 此文观点不代表本站立场;转载须要保留原文链接;版权疑问请联系我们。