I recently came across BufferedMutator class of HBase which can be used for batch inserts and deletes.
I was previously using a List to put data as hTable.put(putList)
to do the same.
Benchmarking my code didn't seem to show much difference too, where I was instead doing mutator.mutate(putList);
.
Is there a significant performance improvement of using BufferedMutator over PutList?
1 回答
简答
BufferedMutator
通常提供比仅使用更好的吞吐量,但Table#put(List<Put>)
需要适当调整hbase.client.write.buffer
、和以获得良好的性能。hbase.client.max.total.tasks
hbase.client.max.perserver.tasks
hbase.client.max.perregion.tasks
解释
当您将 put 列表传递给 HBase 客户端时,它会按目标区域对 puts 进行分组,并按目标区域服务器对这些组进行批处理。为每个批次发送一个 rpc 请求。这减少了 rpc 开销,尤其是在 Put 非常小的情况下,从而使每个请求的 rpc 开销很大。
客户端立即将Table
所有 Puts 发送到区域服务器并等待响应。这意味着任何可能发生的批处理都仅限于单个 API 调用中的 Put 数量,并且从调用者的角度来看,api 调用是同步的。但是,在BufferedMutator
缓冲区中不断缓冲 Puts,并决定根据当前缓冲的大小在后台线程中刷新缓冲的 put,这些线程由一个名为AsyncProcess
. 从调用者的角度来看,每个 API 调用仍然是同步的,但整个缓冲策略提供了更好的批处理。后台刷新模型还允许请求的连续流,结合更好的批处理意味着能够支持更多的客户端线程。然而,由于这种缓冲策略,缓冲区越大,调用者看到的每次操作延迟越差,但是通过拥有更多数量的客户端线程可以维持更高的吞吐量。
一些控制 BufferedMutator 吞吐量的配置是:
hbase.client.write.buffer
:缓冲区的大小(字节)(越高提供更好的峰值吞吐量,消耗更多内存)
hbase.client.max.total.tasks
: 在 AsyncProcess 开始阻塞请求之前,集群中的待处理请求数(越高越好,但可能会使客户端 CPU 饿死,或导致服务器过载)
hbase.client.max.perserver.tasks
:在 AsyncProcess 开始阻塞请求之前,一个区域服务器的待处理请求数。
hbase.client.max.perregion.tasks
:每个区域的待处理请求数。
此外,为了完整起见,不言而喻,如果瓶颈在服务器端而不是客户端,那么通过在客户端使用BufferedMutator
over将不会看到太多的性能提升Table
。