Skip to content

环境的注意事项

  • Regionserver 和 DataNode 安装在同一个节点从而提升网络性能。
  • 通常情况下800TB存储空间的集群。Master 内存4GB,RegionServer的内存储不小于16GB(挂载6~12个,1TB或2TB磁盘)。
  • 通常情况节点的磁盘性能正比于磁盘数据。通常机械盘单盘100IO PS/s、100m/s吞吐左右。
  • 磁盘优化
  • 挂载时禁用noatime禁止记录最近一次文件访问时间戳("/dev/sdd1 /data ext4 defaults,noatime,nodiratime 0 0")
  • 使用tune2fs减小磁盘预留的存储空间,可以从5%减小到1%
  • 关闭ext4中的延迟分配功能(nodelalloc 参数)
  • HBase只能适配特定版本的HDFS
  • 需要NTP服务,否则会出现莫名其妙的问题
  • 修改文件句柄(Too many open files 异常)和进程限制(OutOfMemoryError)
  • 修改DataNode的xcievers配置,否则HDFS Client可能出现块丢失的异常
  • 关闭交换

HBase支持的文件系统

HBase 的底层文件系统是以插件的形式实现的,支持HDFS、本地、S3等多种文件系统

用户API

HBase Shell

HBase Shell基于hbase-site.xml中的Zookeeper地址来获取Master地址的。因此如果HBase部署在Kubernetes环境中,且使用的是内部网络,那么外网方位HBase可能会有一定困难。

JAVA API接口

主要接口类是org.apache.hadoop.hbase.client包中的HTable类。 用户可一个通过该类完成HBase表的有关操作,需要强调该类。每当用户创建HTable类,这些实例都会定时扫描.META.表,因此建议复用HTable对象,并且使用HTablePool类管理这些对象。

HTable对象不是线程安全的!因此不能多个线程共用一个HTable对象(原因是写缓冲问题!!)。

插入

参考org.apache.hadoop.hbase.client.Put/KeyValue类。

写缓存

每个put操作都对应一次RPC调用,HBase Client可以通过写缓冲区,减少RPC请求次数。默认场景下,写缓冲功能是关闭的,Client每次调用put接口会自动flush。

  • 通过调用HTable的setAutoFlush(false)打开写缓存。
  • 通过flushCommits()提交修改。
  • 通过hbase.client.write.buffer配置客户端缓冲大小(默认2mb)

需要注意的是RPC调用时间和HBase的数据传送时间是分开的。写缓存能够缩小RPC次数,减小RPC时间。对于大Cell,数据时间才是瓶颈,因此写缓存用处不大。

Client缓冲越大,服务端消耗的内存储也越大。参考:hbase.client.write.buffer * hbase.regionserver.handler.count * region服务器数目

hbase.regionserver.handler.count: 表示regionserver的rpc监听数目,默认是30,建议配置是CPU数目的二到三倍。

批量插入

通过put接口可以批量插入多个Put实例,并通过类似写缓存的机制将Put实例加入到写缓存中,最后显式或者隐式调用flushCommits。

如果用户的Put实习存在异常(如Null)等,Client会进行必要检查,停止将后续Put添加到缓存。

某些异常在RegionServer才能发现(如列族不存在等),Client会Catch到异常(表现为flushCommits的异常)。用户检查缓存时可以发现异常的Put对象,如果用户不做处理,Client会在下次flushCommits的时候重试该Put。

compare-and-set操作

checkAndPut接口,即检查写操作。即给定Cell一个值(可以是Null),实际写入时比较当前值是否等于给定值,如果等于则进行写入。否者放弃写入。注意,检查值和修改值可以是不同列,但是必须是同一行。

读取

参考org.apache.hadoop.hbase.client.Get/Result类

exists()方法:使用这个方法时可以验证Cell是否存在,避免数据传输开销。

getRowOrBefore()方法:返回指定行,或者上一行。

删除

参考org.apache.hadoop.hbase.client.Delete

compare-and-delete 参考put的原子操作

batch 操作

batch操作是相对于put、get、delete更加底层的接口。

通过 org.apache.hadoop.hbase.client.row 实现批处理,该类是Put、Get、Delete的父类。

在同一个batch中,操作的顺序无法保证。因此不能将针对同一行的Put和Delete放在同一个batch中。

使用batch时,请求是同步的,即不经过缓存。

显式加锁

RowLock lockRow(byte[] row) throws IOException
void unlockRow(RowLock r1) throws IOExcepiton
  • 避免使用上述方法,为ROW显示添加行锁;
  • 如果行锁发生死锁,会占用服务端的处理线程;
  • 修改Row时,服务端创建lock是隐式的,用户无法得到这个锁实例。
  • 锁的超时时间默认为1min,通过hbase.regionserver.lease.period配置

扫描

调用 HTable 的 getScanner()方法,该方式返回 ResultScanner

用户可以调用Scanner的构造器,创建scan对象(用户可以通过指定startRow、stopRow、Filter自定义扫描器),Scan可以添加addFamily、addColumn等操作。

扫描是非常消耗资源的操作,用户进行扫描之后,应当调用close方法释放资源。

  • 扫描过程中每个next操作都会进行一次RPC调用,通过scanner caching可以改善这种情况,默认情况扫描缓存是关闭的。可以在HTable、或者在Scanner类中设定扫描时的缓存大小。

  • 通过hbase.client.scanner.caching可以设定全局的缓存数目。扫描器的租约可能会超时,如果超时可能会抛出ScannerTimeoutException。

  • 通过Scanner的batch接口,可以配置一次取回的列数(比如有17列,每次取回5列,那么需要4个RPC请求取回整行。)

scan操作需要的RPC次数= 2 + (列数)* (行数)/ (缓存行数) / min(每行列数,批量大小)

API接口的原子性

无论修改涉及几个列,HBase保证这个row所有列的原子性。