内容简介:创建 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 入门》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Spring Cloud的Feign客户端入门
- Spring Boot响应式客户端WebClient入门
- Hbase 入门(五):客户端(Java,Shell,Thrift,Rest,MR,WebUI)
- 支付宝客户端架构解析:iOS 客户端启动性能优化初探
- 自己动手做数据库客户端: BashSQL开源数据库客户端
- 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。