HBase客户端API提供了Write Buffer的方式,即批量提交一批Put对象到HBase服务端。本文将结合HBase相关源码,对其进行深入介绍,分析如何在实际项目中合理设置和使用它。
什么时候需要Write Buffer?
默认情况下,一次Put操作即要与Region Server执行一次RPC操作,其执行过程可以被拆分为以下三个部分:
- T1:RTT(Round-Trip Time),即网络往返时延,它指从客户端发送数据开始,到客户端收到来自服务端的确认,总共经历的时延,不包括数据传输的时间;
- T2:数据传输时间,即Put所操作的数据在客户端与服务端之间传输所消耗的时间开销,当数据量大的时候,T2的开销不容忽略;
- T3:服务端处理时间,对于Put操作,即写入WAL日志(如果设置了WAL标识为true)、更新MemStore等。
其中,T2和T3都是不可避免的时间开销,那么能不能减少T1呢?假设我们将多次Put操作打包起来一次性提交到服务端,则可以将T1部分的总时间从T1 * N降低为T1,其中T1为一次RTT时间,N为Put的记录条数。
正是出于上述考虑,HBase为用户提供了客户端缓存批量提交的方式(即Write Buffer)。假设RTT的时间较长,如1ms,则该种方式能够显著提高整个集群的写入性能。
那么,什么场景下适用于该种模式呢?下面简单分析一下:
- 如果Put提交的是小数据(如KB级别甚至更小)记录,那么T2很小,因此,通过该种模式减少T1的开销,能够明显提高写入性能。
- 如果Put提交的是大数据(如MB级别)记录,那么T2可能已经远大于T1,此时T1与T2相比可以被忽略,因此,使用该种模式并不能得到很好的性能提升,不建议通过增大Write Buffer大小来使用该种模式。
如何配置使用Write Buffer?
如果要启动Write Buffer模式,则调用HTable的以下API将auto flush设置为false:
void setAutoFlush(boolean autoFlush) |
默认配置下,Write Buffer大小为2MB,可以根据应用实际情况,通过以下任意方式进行自定义:
1) 调用HTable接口设置,仅对该HTable对象起作用:
void setWriteBufferSize(long writeBufferSize) throws IOException |
2) 在hbase-site.xml中配置,所有HTable都生效(下面设置为5MB):
<property>
<name>hbase.client.write.buffer</name>
<value>5242880</value>
</property>
|
该种模式下向服务端提交的时机分为显式和隐式两种情况:
1) 显式提交:用户调用flushCommits()进行提交;
2) 隐式提交:当Write Buffer满了,客户端会自动执行提交;或者调用了HTable的close()方法时无条件执行提交操作。
如何确定每次flushCommits()时实际的RPC次数?
客户端提交后,所有的Put操作可能涉及不同的行,然后客户端负责将这些Put对象根据row key按照 region server分组,再按region server打包后提交到region server,每个region server做一次RPC请求。如下图所示:
如何确定每次flushCommits()时提交的记录条数?
下面我们先从HBase存储原理层面“粗略”分析下HBase中的一条Put记录格式:
HBase中Put对象的大小主要由若干个KeyValue对的大小决定(Put继承自org/apache/hadoop/hbase/client/Mutation.java,具体见Mutation的代码所示),而KeyValue类中自带的字段占用约50~60 bytes(参考源码:org/apache/hadoop/hbase/KeyValue.java),那么客户端Put一行数据时,假设column qualifier个数为N,row key长度为L1
bytes,value总长度为L2 bytes,则该Put对象占用大小可按以下公式预估:
Put Size = ((50~60) + L1) * N + L2) bytes |
下面我们通过对HBase的源码分析来进一步验证以上理论估算值:
HBase客户端执行put操作后,会调用put.heapSize()累加当前客户端buffer中的数据,满足以下条件则调用flushCommits()将客户端数据提交到服务端:
1)每次put方法调用时可能传入的是一个List<Put>,此时每隔DOPUT_WB_CHECK条(默认为10条),检查当前缓存数据是否超过writeBufferSize,超过则强制执行刷新;
2)autoFlush被设置为true,此次put方法调用后执行一次刷新;
3)autoFlush被设置为false,但当前缓存数据已超过设定的writeBufferSize,则执行刷新。
private void doPut(final List<Put> puts)throws IOException {
int n = 0;
for (Put put : puts) {
validatePut(put);
writeBuffer.add(put);
currentWriteBufferSize += put.heapSize();
// we need to periodically see if the writebuffer is full instead
// of waiting until the end of the List
n++;
if (n % DOPUT_WB_CHECK == 0
&& currentWriteBufferSize > writeBufferSize) {
flushCommits();
}
}
if (autoFlush || currentWriteBufferSize > writeBufferSize) {
flushCommits();
}
}
|
由上述代码可见,通过put.heapSize()累加客户端的缓存数据,作为判断的依据;那么,我们可以编写一个简单的程序生成Put对象,调用其heapSize()方法,就能得到一行数据实际占用的客户端缓存大小(该程序需要传递上述三个变量:N,L1,L2作为参数):
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
public class PutHeapSize {
/**
*@param args
*/
public static void main(String[] args) {
if (args.length != 3) {
System.out.println(“Invalid number of parameters: 3 parameters!”);
System.exit(1);
}
int N = Integer.parseInt(args[0]);
int L1 = Integer.parseInt(args[1]);
int L2 = Integer.parseInt(args[2]);
byte [] rowKey =new byte [L1];
byte [] value =null ;
Put put =new Put(rowKey);
for (int i = 0; i < N; i++) {
put.add(Bytes.toBytes(“cf”), Bytes.toBytes(“c” + i), value);
}
System.out.println(“Put Size: ” + (put.heapSize() + L2) + ” bytes”);
}
}
|
该程序可以用来预估当前设置的Write Buffer可以一次性批量提交的记录数:
Puts Per Commit = Write Buffer Size / Put Size |
更进一步地,如果知道业务中的每秒产生的数据量,就可知道客户端大概多长时间会隐式调用flushCommits()向服务端提交一次,同时也可反过来根据数据实时刷新频率调整Write Buffer大小。
Write Buffer有什么潜在的问题?
首先,Write Buffer存在于客户端的本地内存中,那么当客户端运行出现问题时,会导致在Write Buffer中未提交的数据丢失;由于HBase服务端还未收到这些数据,因此也无法通过WAL日志等方式进行数据恢复。
其次,Write Buffer方式本身会占用客户端和HBase服务端的内存开销,具体见下节的详细分析。
如何预估Write Buffer占用的内存?
客户端通过Write Buffer方式提交的话,会导致客户端和服务端均有一定的额外内存开销,Write Buffer Size越大,则占用的内存越大。客户端占用的内存开销可以粗略地使用以下公式预估:
hbase.client.write.buffer * number of HTable object for writing |
而对于服务端来说,可以使用以下公式预估占用的Region Server总内存开销:
hbase.client.write.buffer * hbase.regionserver.handler.count * number of region server
|
其中,hbase.regionserver.handler.count为每个Region Server上配置的RPC Handler线程数。
相关推荐
Hbase 可视化客户端工具(非phoenix连接),支持Hbase1.x,配置方便,类似PL/SQL,是一个HBase数据库的客户端数据管理软件。
hbase客户端下载,可以直接连接插入、查看 hbase客户端下载,可以直接连接插入、查看 hbase客户端下载,可以直接连接插入、查看
1、有多个工具可选择使用
hbase可视化客户端 类似PL/SQL,是一个HBase数据库的客户端数据管理软件。 1: put支持中文 2: 支持文件形式的批量put命令执行 3: 支持扫描目录下所有文件的批量put命令执行 4: 支持put命令字符的执行 5: 支持文件...
HBASE的java版本的客户端,运行代码需要设定环境变量且打包成jar文件运行
hbase操作必备客户端源代码
该资源为java客户端连接hbase集群,在windows客户端配置hadoop环境所需要用到的工具类,有需自取
hbase的java客户端api操作示例代码
HBase客户端数据管理软件 概要说明 类似PL/SQL,是一个HBase数据库的客户端数据管理软件。是免费开源的软件。 基于XJava,使用xml配置文件绘制可视化界面。 可视化界面操作 表 表的定义、编辑、删除; 数据 数据的...
nosql-实验三HBase管理工具和客户端
这是 HBase 的纯 CSharp 客户端。 支持的版本 HBase >= 1.0 示例用法 创建客户端 var ZkQuorum = " zooKeep-host-ip " ; var admin = await new AdminClient ( ZkQuorum ). Build (); if ( admin == null ) return...
用 JavaFX 编写的 Apache HBase 的 GUI 客户端 ##构建和运行## mvn 包 java -jar target_package ####supported hbase 版本 hbase 0.98 ###Features### 创建带有预拆分和有用选项的表 实时表格内容编辑 多集群连接...
asynchbase(Asynchronous HBase)是完全异步,非阻塞的,线程安全的,高性能的 HBase 客户端。asynchbase 是 Java 库使用 HBase 的替代品,要求一个完全异步,非阻塞,线程安全,高性能的 HBase API。这个 HBase ...
文章目录HBASE 入梦Hbase 简介什么是HbaseHbase 特点Hbase 架构Hbase 中的角色HMasterRegionServer其他组件HBase 安装Zookeeper 正常部署hadoop正常部署HBase 安装1. 解压到目录2. 配置文件同步其他服务器启动服务...
对HBase的API做了一层抽象,统一了HBase1.x和HBase2.x的实现,并提供了读写HBase的ORM的支持,同时,sdk还对HBase thrift 的客户端API进行了池化封装,(类似JedisPool),消除了直接使用原生API的各种问题,使之...
Hbase1.x可视化客户端工具,内有使用说明,亲测可用。
Golang HBase客户端 这是的纯客户端。 当前状态:测试版。支持的版本HBase的> = 1.0安装go get github.com/tsuna/gohbase用法示例创建一个客户client := gohbase . NewClient ( "localhost" )插入一个单元格// ...
简单的hbase客户端 简单的 HBase 客户端
HBase客户端说明启用方法在命令行中输入:hbase ip=xxx.xxx.xxx.xxx -window主界面数据库管理创建表删除表编辑(添加或删除)列族数
node-hbase-client 是 Node.js 的异步 HBase 客户端,使用纯 JavaScript 实现。当前状态:完全通过 HBase 0.94 和 0.94.16Java hbase-client支持 HBase 服务器的版本[√] 0.94.x[√] 0.94.0[√] 0.94.160.95.x0.96.x...