《HBase 不睡觉》第四章 - 客户端 API 入门

栏目: 数据库 · 发布时间: 6年前

内容简介:创建 HBase 连接请注意以下几点:不推荐将 Connection 实现为单例,这样当某个操作卡住时,其他后续操作也会处于阻塞状态,无法达到并发的效果。早期的教程会教大家使用 HTable 类,而且使用这个类的时候不需要去手动地获取 Connection,只需要把 Configuration 类作为构建参数传给 HTable 类,它会自动地去连接并完成操作。这个方法看起来操作很简单,实则隐含着很多性能和安全问题,所以这个类

创建 HBase 连接请注意以下几点:

  • 把 HBase 配置文件夹中的 hbase-site.xml 和 Hadoop 配置文件夹中的 core-site.xml 配置文件从服务器上拖下来放到项目 resources 文件夹内;
  • 如果创建连接失败,请先排查一下本机的 hosts 文件中是不是忘记配置了服务器的 IP 和 hostname 映射,导致计算机无法找到这些服务器;
  • 操作执行关闭后,记得关闭资源,推荐使用 JDK7 的 try-with-resources 特性;
  • 常规情况下,推荐将 Configuration 做为单例;Connection 随建随用,用完及时关闭。

不推荐将 Connection 实现为单例,这样当某个操作卡住时,其他后续操作也会处于阻塞状态,无法达到并发的效果。

public static void main(String[] args) throws URISyntaxException, IOException {
    //获取配置文件
    Configuration config = HBaseConfiguration.create();
    config.addResource(new Path(ClassLoader.getSystemResource("hbase-site.xml").toURI()));
    config.addResource(new Path(ClassLoader.getSystemResource("core-site.xml").toURI()));
    //创建连接
    try (Connection connection = ConnectionFactory.createConnection(config); Admin admin = connection.getAdmin()) {
        //定义表名
        TableName tableName = TableName.valueOf("tb1");
        //定义列族
        ColumnFamilyDescriptor myCf = ColumnFamilyDescriptorBuilder.of("cf1");
        //定义表
        TableDescriptor table = TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(myCf).build();
        //执行创建表动作
        admin.createTable(table);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}
复制代码

2、HTable 类和 Table 接口

早期的教程会教大家使用 HTable 类,而且使用这个类的时候不需要去手动地获取 Connection,只需要把 Configuration 类作为构建参数传给 HTable 类,它会自动地去连接并完成操作。这个方法看起来操作很简单,实则隐含着很多性能和安全问题,所以这个类 被废弃了

官方建议大家先手动获取 Connection,然后再从 Connection 中获取 Table 接口(注意:不是 HTable 类,而是 Table 接口):

// 已废弃,不推荐使用
// HTable table = new HTable(config, "mytable");

// 官方推荐
try (Connection connection = ConnectionFactory.createConnection(config)) {
    connection.getTable(TableName.valueOf("tb1"));
}
复制代码

二、几个重要的方法

1、checkAndPut(数据一致性)

在你读出数据之后和修改数据中间这段时间,如果有别人也修改了这个数据,就会发生数据不一致的问题,checkAndPut 方法就是为了解决这个问题而产生的。

checkAndPut 方法只是把检查和写入这两个步骤合二为一了,checkAndPut 方法在写入前会先比较目前存在的数据是否与你传入的数据一致,如果一致则进行 put 操作,并返回 true;如果不一致,则返回 false,但不写入数据。

最新版本中 checkAndPut 已经弃用了,官方推荐使用 checkAndMutate。

2、checkAndMutate

checkAndPut 与 checkAndDelete 在最新的 API 中已经不推荐使用了,官方推荐使用 Table.checkAndMutate(byte[], byte[]) 。checkAndMutate 会在执行 Put/Delete/RowMutations 操作前检查 row/family/qualifier value 是否与预期的值匹配,如果不匹配则不执行操作。

table.checkAndMutate(row, family).qualifier(qualifier).ifNotExists().thenPut(put);
复制代码

3、increment

保证原子性的情况下,把数据库中的某个列的数字加 N(N 可以是正数或者负数)。

Table table = connection.getTable(TableName.valueOf("tb1"));
Increment inc = new Increment(Bytes.toBytes("row1"));
inc.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("age"), 1L);
table.increment(inc);
复制代码

4、批量操作(batch)

当需要一次性操作(Put、Get、Delete)很多条数据的时候,为了操作方便并且提高性能,可以使用 batch 方法;这里的操作列表 actions 里面的操作可以是 Put、Get、Delete 中的任意一种;第二个参数的 results 是操作的结果,results 中的结果顺序是跟传入的操作列表顺序一一对应的。

void batch(List<Row>actions, Object[] results)
复制代码

最好不要把针对同一个单元格的 Put 和 Delete 放到同一个 actions 列表里面,因为 HBase 不一定是顺序地执行这些操作的,你可能会得到意想不到的结果。

5、批量 put 操作

HBase 提供了专门针对批量 put 的操作方法: void put(List<Put> puts) ;其实内部也是用 batch 来实现的。需要注意的是,当一部分数据插入成功,但是另一部分数据插入失败,比如某个 RegionServer 服务器出现了问题,这时会返回一个 IOException,操作会被放弃,不过插入成功的数据不会被回滚,还是成功插入了。

插入失败的重试

对于插入失败的数据,服务器会尝试着再次去插入或者换一个 RegionServer,当尝试的次数大于定义的最大次数会抛出 RetriesExhaustedWithDetailsException 异常,该异常包含了很多错误信息,包括有多少操作失败了,失败的原因以及服务器名和重试的次数。

如果定义了错误的列族,则只会尝试一次,因为如果连列族都错了,就没必要再继续尝试下去了,HBase 会直接返回 NoSuchColumnFamilyException。

写缓冲区

插入失败的数据会继续被放到本地的写缓冲区,并在下次插入的时候重试,你甚至可以操作它们,比如清除这些数据。

6、BufferedMutator

客户端写缓冲区就是一个在客户端 JVM 里面的缓存机制,可以把多个 Put 操作攒到一起通过单个 RPC 请求发送给客户端,目的是节省网络握手带来的 IO 消耗。这个缓冲区可以通过调用 HTable.setAutoFlush(false) 来开启。

最新版的 API 中 setAutoFlush 被废弃了,每个表自带的 writeBuffer 也被废弃了,但是客户端写缓冲区还是存在的,只是转而使用 BufferedMutator 对象。

BufferedMutator bm = connection.getBufferedMutator(TableName.valueOf("tb1"));
// 然后用BufferedMutator对象来提交Put操作
bm.mutate(put);
// 然后调用 flush 或者 close 方法都可以把请求批量地提交给服务端
bm.flush();
bm.close();
复制代码

大部分情况下我们不需要直接调用到 BufferedMutator,也不推荐直接调用 BufferedMutator。

7、Scan 缓存

早期的 HBase 在扫描的时候默认是不开启缓存的,但是经过了广大使用者许多次的实践后,现在的 HBase 在扫描的时候已经默认开启了缓存。

具体地说就是:每一次的 next() 操作都会产生一次完整的 RPC 请求,而这次 RPC 请求可以获取多少数据是通过 hbase-site.xml 中的 hbase.client.scanner.caching 参数配置的。比如你如果配置该项为 1,那么当你遍历了 10 个结果就会发送 10 次请求,显而易见这是比较消耗性能的,尤其是当单条的数据量较小的时候。

可以在表层面修改缓存条数,也可以在扫描层面去修改,在表的层面修改是通过把这段配置写到 hbase-site.xml 内去实现:

<property>
    <name>hbase.client.scanner.caching</name>
    <value>200</value>
</property>
复制代码

意思是每次 next 操作都获取 200 条数据,默认配置是100。

可以使用 Scan.setCaching(int caching) 方法在扫描层面修改缓存,这个配置优先级比配置文件内的高,可以复写这个配置值。缓存固然好,但是带来的危害就是会占用大量内存,最糟糕的就是直接出现 OutOfMemoryException,所以也不要盲目的调大缓存。

Any Code,Code Any!

扫码关注『AnyCode』,编程路上,一起前行。

《HBase 不睡觉》第四章 - 客户端 API 入门

以上所述就是小编给大家介绍的《《HBase 不睡觉》第四章 - 客户端 API 入门》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Distributed Systems

Distributed Systems

Sukumar Ghosh / Chapman and Hall/CRC / 2014-7-14 / USD 119.95

Distributed Systems: An Algorithmic Approach, Second Edition provides a balanced and straightforward treatment of the underlying theory and practical applications of distributed computing. As in the p......一起来看看 《Distributed Systems》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具