HBase编程开发(三) | 「掘金日新计划 · 12 月更文挑战」

50 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第24天

一、本篇笔记重点内容:

  • 编程应用过滤器
  • 编程实现数据删除
  • 编程实现单行查询
  • Hbase的优化

二、 详细知识点介绍

编程应用过滤器

前面提到的单行查询、集合查询是按照行键值或者列族、字段进行数据显示。但是,在大规模的HBase集群数据中去执行这样的查询,将会极为低效,因为返回的结果集合会是比较庞大的,不利于数据处理与分析。

在HBase中,没有提供像SQL查询语句那样方便的接口,但为方便数据精细化操作,提供了过滤器这样的接口,即对于查询结果,按指定的方法进行过滤后返回结果集,在Get、Scan中均支持过滤器。

过滤器的调用需要实例化Filter类,通过不同的过滤器进行实例化以达到不同的过滤目的。实例化后,在Get或Scan中通过setFilter方法加载过滤器,过滤器的基类是Filter。

在HBase中支持多种过滤器机制,比较常见的是比较过滤器CompareFilter类,在该类中定义了常用的比较运算符,即用设定的值进行比较,满足条件的记录被返回。所有比较运算符如下表所示。

image.png 除了上面的比较运算符外,还定义了比较器,常见的比较器包括:BinaryComparator(字节比较器)、BinaryPrefixComparator(字节前缀比较器)、RegexStringComparator(正则表达式比较器)、NullComparator(空值比较器)、BitComparator(比特位比较器)、SubstringComparator(子串比较器)等。 下面以字段名称过滤器(QualifierFilter)为例,设计一个方法,返回指定字段名的数据集。


Table table = connection.getTable(TableName.valueOf(tbname));

Scan scan = new Scan();

 

QualifierFilter fr = new QualifierFilter(CompareFilter.CompareOp.EQUAL,

new BinaryComparator(Bytes.toBytes(column)));

scan.setFilter(fr);

ResultScanner res = null;

try {

res = table.getScanner(scan);

for(Result r : res) {

for(KeyValue kv : r.list()) {

System.out.print("row:" + Bytes.toString(kv.getRow()));

System.out.print("\t" + Bytes.toString(kv.getFamily()));

System.out.print(":" + Bytes.toString(kv.getQualifier()));

System.out.print(" value:" + Bytes.toString(kv.getValue()));

}

}

}finally {

res.close();

}

}

编程实现数据删除

通过创建delete对象,删除指定表内记录(删除这里有些特别,也就是删除并不是马上将数据从表中删除。)

调用Table的delete(Delete delete)方法,可以删除表集数据,需要传入的参数为Delete类,在Delete类里面,设置可以删除的列对象。

类Delete用于格式化要删除的列对象,通过此对象设定删除对象的条件。它的常用方法如下表所示:

image.png

Hbase的优化

在这里主要介绍下Hbase的一些优化设计,当然企业中不能对这些优化都使用,优化需要根据具体业务实施。

6.9.1 表设计****

1) 预分区

默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候,所有的HBase客户端都向这一个region写数据,直到这个region足够大了才进行切分。这样就会影响部分效率,

想要加快批量写入效率,可以通过预先创建一些空的regions,这样当数据写入HBase时,会按照region分区情况,在集群内做数据的负载均衡。

2) Row Key的设计

行键检索表中的数据主要通过三种方式:

1)通过单个row key访问:按照某个row key键值进行get操作;

2)通过row key的range进行scan:通过设置startRowKey和endRowKey,在这个范围内进行扫描;

3)全表扫描:即直接扫描整张表中所有行记录。

在HBase中,row key可以是任意字符串,最大长度64KB,实际应用中一般为10~100bytes,存为byte[]字节数组,一般设计成定长的。

row key是按照字典序存储,因此,设计row key时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。

举个例子:如果最近写入HBase表中的数据是最可能被访问的,可以考虑将时间戳作为row key的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE - timestamp作为row key,这样能保证新写入的数据在读取时可以被快速命中。

设计规则:

        1)越小越好

          2)Rowkey的设计是要根据实际业务来

3)散列性

a) 取反 001  002  :  100  200 取反后,rowkey可能落在不同的region上

 b) Hash  rowkey取hash值后,可能会均匀分布在不同的region上

散列弊端:降低了范围查找的效率

3) 列族的设计

不要在一张表里定义太多的column family。目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,它邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O。

4) 设置最大版本

创建表的时候,可以通过HColumnDescriptor.setMaxVersions(int maxVersions)设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置setMaxVersions(1)。

5) 存储生命周期

创建表的时候,可以通过HColumnDescriptor.setTimeToLive(int timeToLive)设置表中数据的存储生命期,过期数据将自动被删除,例如如果只需要存储最近两天的数据,那么可以设置setTimeToLive(2 * 24 * 60 * 60)。(相当于Linux中的Crontab任务)

6.9.2 写 操作****

6) HTable

1) 创建多个Htable客户端用于并发写的操作,提高写入数据的吞吐量

2) 参数优化

Auto Flush****

通过调用HTable.setAutoFlush(false)方法可以将HTable写客户端的自动flush关闭,这样可以批量写入数据到HBase,而不是有一条put就执行一次更新,只有当put填满客户端写缓存时,才实际向HBase服务端发起写请求。默认情况下auto flush是开启的。

Write Buffer****

通过调用HTable.setWriteBufferSize(writeBufferSize)方法可以设置HTable客户端的写buffer大小,如果新设置的buffer小于当前写buffer中的数据时,buffer将会被flush到服务端。其中,writeBufferSize的单位是byte字节数,可以根据实际写入数据量的多少来设置该值。

7) 批量写入

通过调用HTable.put(Put)方法可以将一个指定的row key记录写入HBase,同样HBase提供了另一个方法:通过调用HTable.put(List)方法可以将指定的row key列表,批量写入多行记录,这样做的好处是批量执行,只需要一次网络I/O开销,这对于对数据实时性要求高,网络传输RTT高的情景下可能带来明显的性能提升。

6.9.3 读 操作****

8) Htable

1)创建多个Htable客户端用于并发读的操作,提高读入数据的吞吐量

2)参数优化

Scanner Caching****

hbase.client.scanner.caching配置项可以设置HBase scanner一次从服务端抓取的数据条数,默认情况下一次一条。通过将其设置成一个合理的值,可以减少scan过程中next()的时间开销,代价是scanner需要通过客户端的内存来维持这些被cache的行记录。

Scan Attribute Selection****

scan时指定需要的Column Family,可以减少网络传输数据量,否则默认scan操作会返回整行所有Column Family的数据。

Close ResultScanner****

通过scan取完数据后,记得要关闭ResultScanner,否则RegionServer可能会出现问题(对应的Server资源无法释放)。

  1. 批量读

通过调用HTable.get(Get)方法可以根据一个指定的row key获取一行记录,同样HBase提供了另一个方法:通过调用HTable.get(List)方法可以根据一个指定的row key列表,批量获取多行记录,这样做的好处是批量执行,只需要一次网络I/O开销,这对于对数据实时性要求高而且网络传输RTT高的情景下可能带来明显的性能提升。