本文将介绍HBase的客户端连接实现,并说明如何正确管理HBase的连接。

最近在搭建一个HBase的可视化管理平台,搭建完成后发现不管什么查询都很慢,甚至于使用api去listTable都要好几秒。

经过一番排查发现,是每次请求的时候,都去临时创建了一个connection,而创建connection非常耗时导致整体的rt上升。

因此,就深入了解了下如何正确管理HBase的connection,同时,也在优化过程中有些小细节的总结。

本文基于hbase 2.0.0版本的源码,github上3.0版本的源码已经有很大差异了,但是思想还是差不多的

1.HBase-client和HBase是如何连接的?

这个问题实际上在我之前的文章 深入HBase读写 中介绍过。

当HBase-client第一次请求读写的时候,需要三步走:

1)HBase-client从zk中获取保存meta table的位置信息,知道meta table保存在了哪个region server,然后缓存这个位置信息;

2)HBase-client会查询这个保存meta table的特定的region server,查询meta table信息,在table中获取自己想要访问的row key所在的region在哪个region server上。

3)客户端直接访问目标region server,获取对应的row

所以,我们知道hbase-client实际上包含三部分连接:

  • 跟zk连接,获取相关元信息
  • 跟HMaster连接,做相关DDL操作
  • 直接跟各个region server进行连接,进行增删改查

2.HBase客户端连接原理

常规写法是这样的

Connection connection = ConnectionFactory.createConnection(conf);

try {
Table table = connection.getTable(TableName.valueOf("tablename”));
// 插入数据
Put put = new Put(Bytes.toBytes("row"));
put.addColumn(Bytes.toBytes("family"), Bytes.toBytes("qualifier"), Bytes.toBytes("value"));
table.put(put);
// 单行读取
Get get = new Get(Bytes.toBytes("row"));
Result res = table.get(get);
// 删除一行数据
Delete delete = new Delete(Bytes.toBytes("row"));
table.delete(delete);
}catch (IOException e) {
//.....
} finally {
table.close();
connection.close();
}

我们不禁有这样的疑问:

1)HBase没有连接池吗?

2)connection表示的是一个连接吗?

3)connection每个线程都得创建吗?线程安全吗?

4)table每个线程都得创建吗?线程安全吗?

下面一一解答。

首先,Connection是线程安全的,而Table和Admin则不是线程安全的。

因此正确的做法是一个进程(或服务)使用一个Connection对象,而在不同的线程中使用单独的Table和Admin对象。

Connection持有RpcClient,RpcClient管理了一个连接池poolMap

protected final PoolMap<ConnectionId, T> connections;

//….

this.connections = new PoolMap<>(getPoolType(conf), getPoolSize(conf));

通过AbstractRpcClient的getConnection看到,连接T继承RpcConnection,叫做NettyRpcConnection。

这里顺便通过getPoolType和getPoolSize看了下线程池的大小和类型。

在枚举类PoolType中有三种线程池类型Reusable, ThreadLocal, RoundRobin,用户可以用hbase.client.ipc.pool.type指定线程池类型,通过hbase.client.ipc.pool.size指定线程池大小(默认是1)。

3.优化实践

搞清楚上面的原理后,下面就可以开始优化我们的HBase管理平台了。

只需要对每个HBase集群的connection使用Map保存下来,每次请求的时候拿出对应的connection进去相关操作即可。然后需要注意在系统退出的时候关闭所有的connection。

上代码:

public class ConnectionManager {
private Map<String, Connection> connectionMap = new ConcurrentHashMap<>(); public Connection getConnection(String resourceId, Configuration configuration) {
ResourceInfo resourceInfo = ResourceInfoCache.getResourceInfoByCache(resourceId);
if (resourceInfo == null) {
throw new IllegalArgumentException("error resourceid: " + resourceId);
}
String key = getClusterKey(resourceInfo);
if (connectionMap.containsKey(key)) {
return connectionMap.get(key);
}
synchronized (this) {
//DCL检查
if (connectionMap.containsKey(key)) {
return connectionMap.get(key);
}
Connection connection = null;
try {
connection = ConnectionFactory.createConnection(configuration);
} catch (IOException e) {
return null;
}
connectionMap.put(key, connection);
return connection;
}
} @PreDestroy
public void doDestroy() {
for (Map.Entry<String, Connection> entry : connectionMap.entrySet()) {
Connection connection = entry.getValue();
if (connection != null) {
try {
connection.close();
} catch (IOException e) {
//。。。。
}
}
}
}
}

这里有几个注意点:

  • 将ConnectionManager注册为bean,交给spring容器管理生命周期,同时保证单例。
  • 使用@PreDestroy保证应用关闭时,能正确释放所有连接,避免连接泄漏
  • connectionMap使用ConcurrentHashMap保证线程安全
  • DCL检查,避免重复创建同一个connection,浪费资源;并且避免重复创建connection后,无法关闭导致连接泄漏。

在需要查询时,只需要通过getConnection获取已经存在的connection即可。

当然,如果是普通的应用使用HBase-client,一般只需要对一个HBase的集群创建全局唯一的一个Connection即可(一般交给spring容器管理),每次请求的时候,创建对应的Table进行CRUD。

看到这里了,原创不易,点个关注、点个赞吧,你最好看了~

知识碎片重新梳理,构建Java知识图谱:https://github.com/saigu/JavaKnowledgeGraph(历史文章查阅非常方便)

扫码关注我的公众号“阿丸笔记”,第一时间获取最新更新。同时可以免费获取海量Java技术栈电子书、各个大厂面试题。

如何正确管理HBase的连接,从原理到实战的更多相关文章

  1. HBase存储及读写原理介绍

    一.HBase介绍及其特点 HBase是一个开源的非关系型分布式数据库,它参考了谷歌的BigTable建模,实现的编程语言为Java.它是Apache软件基金会的Hadoop项目的一部分,运行于HDF ...

  2. IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

    本文引用了简书作者“骑小猪看流星”技术文章“Cookie.Session.Token那点事儿”的部分内容,感谢原作者. 1.前言 众所周之,IM是个典型的快速数据流交换系统,当今主流IM系统(尤其移动 ...

  3. Hbase的连接池--HTablePool被Deprecated之后

      说明: 最近两天在调研HBase的连接池,有了一些收获,特此记录下来. 本文先将官方文档(http://hbase.apache.org/book.html)9.3.1.1节翻译,方便大家阅读,然 ...

  4. ssh连接的原理

    ssh是linux系统中的一个远程连接工具,也是一种网络协议,通过各种加密算法达到安全连接的效果.若能使用ssh连接到另外一台机器上,我们就可以认为是安全的.本节主要介绍的是ssh连接的原理以及ssh ...

  5. 管理IPv6网络连接

    以下操作建立在Linux功能-管理IPv4网络连接之上,请先完成该部分操作后进行以下测试. 1. 修改 net1,配置 IPv6 地址为 2001:X/64 ,网关为 2001:254 [root@d ...

  6. 解决SQL Server管理器无法连接远程数据库Error: 1326错误

    解决SQL Server管理器无法连接远程数据库Error: 1326错误 我们在在使用SQL Server时都会遇到使用SQL Server Management Studio无法连接远程数据库实例 ...

  7. 全易通人事考勤工资验厂管理系统软件创建连接SQL2000数据库的操作方法和说明

    全易通人事考勤工资验厂管理系统软件创建连接SQL2000数据库的操作方法和说明.全易通人事考勤工资验厂管理系统软件,有2种数据库,一个是ACCESS,另一个是SQL.不过由于ACCESS数据库比较小, ...

  8. HTTP协议学习笔记---HTTP持久连接和如何正确地关闭HTTP连接

    一,持久连接 什么是持久连接?对于HTTP协议而言,它是基于请求响应模型,Client向Server发请求时,先建立一条HTTP连接,Server给Client响应数据后,连接关闭. 当Client发 ...

  9. Foxpro数据库连接错误解决方法--【VFP DBF文件不是一个有效的路径。 确定路径名称拼写是否正确,以及是否连接到文件存放的服务器】

    直接访问vfp dbf文件时报错: 错误描述: 'd:\vfpData\test.dbf'不是一个有效的路径. 确定路径名称拼写是否正确,以及是否连接到文件存放的服务器. 解决办法:Data Sour ...

随机推荐

  1. iOS 指纹认证登陆开发(TouchID)

    设计思路 TouchID 关联账号 用户登陆成功 -> 开启TouchID登陆 -> TouchID验证 -> 记录用户信息(验证通过) -> 关联完成 TouchID 登陆 ...

  2. Python编写“去除字符串中所有空格”

    #利用迭代操作,实现一个trim()函数,去除字符串中所有空格 def trim(str): newstr = '' for ch in str: #遍历每一个字符串 if ch!=' ': news ...

  3. 2019牛客多校第四场 A meeting

    链接:https://ac.nowcoder.com/acm/contest/884/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言10485 ...

  4. MySQL到底能有多少个字段

    今天技术讨论群里 “一切随遇而安”同学看书时出现一个疑问,一个MySQL的表中到底可以有多少个字段?带着这个疑问,我们展开了探讨,也接着讨论了一个单字段长度的问题. 1.  官方文档说明 官方文档的内 ...

  5. Typora+markdown 最常用语法教程

    Typora+markdown 最常用语法教程(by 程序员宝藏) Typora+markdown 最常用语法教程(by 程序员宝藏) 请先配置推荐配置(文件->偏好设置): 文章目录 Typo ...

  6. liunx 上安装redis

    目录 1.安装包 2.解压:tar xzf redis-5.0.5.tar.gz 3.安装 4.编辑redis.conf文件 5.配置密码 6.启动配置: 7.配置公网链接 8.杀掉redis进程 9 ...

  7. Python python 五种数据类型--数字

    一:Number 数字 不可变类型 整型(Int) - 通常被称为是整型或整数,是正或负整数,不带小数点. 长整型(long integers) - 无限大小的整数,整数最后是一个大写或小写的L.(P ...

  8. intelliJ IDEA 教育版下载教程

    ​声明:本教程针对的是在校本科大学生及以上学历学生群体,因为申请账号需要学校的邮箱来进行验证,所以"社会人士"为了对的起"社会"这两个字,还是花点钱买个正版吧! ...

  9. 《JAVA与模式》之责任链模式 【转载】

    转载自java_my_life的博客 原文地址:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html 在阎宏博士的&l ...

  10. 爬虫简介和requests模块

    目录 爬虫介绍 requests模块 requests模块 1.requests模块的基本使用 2.get 请求携带参数,调用params参数,其本质上还是调用urlencode 3.携带header ...