HBase的原型是Google的BigTable论文,受到了该论文思想的启发,目前作为Hadoop的子项目来开发维护,用于支持结构化的数据存储。HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。HBase是Google Bigtable的开源实现,但是也有很多不同之处。HBase利用Hadoop HDFS作为其文件存储系统,它利用Hadoop MapReduce来处理HBase中的海量数据,使用Zookeeper作为协同服务。

首先学习HBase需要搭建对应的环境,这里为了不在环境上浪费过多的时间,我采用了Docker搭建HBase的方式,使用其内置的Zookeeper以及Hadoop实现数据的操作。Docker是一个非常强大的工具,它能够非常方便的帮我们搭建出想要的各种环境,我使用Docker也有快一年的时间,也处于一个学习的状态,后期我会专门写一篇关于Docker使用的文章进行总结。今天我们来介绍一下HBase的搭建以及如何使用Java API进行访问。

使用Docker搭建HBase的环境

Docker的安装不是本篇的重点,后面会专门写一篇关于Docker使用的总结。至于Docker能安装在什么机器上,无论你是本地PC还是远程Linux服务器,Docker都能够实现安装。我使用的是Mac的环境,安装Docker Desktop即可。首先我们需要从镜像仓库中拉取HBase的镜像,使用如下的命令:

docker search hbase

我们能够看到有以下的仓库镜像:

我们选择harisekhon/hbase的1.3的版本,因为是测试成功过的,使用以下命令拉取镜像:

docker pull harisekhon/hbase:1.3

然后我们使用docker run的命令启动HBase容器,这里的命令非常重要,和设置端口号有关,与之后能不能使用Java API连接到HBase有很大的关系:

docker run -d -h myhbase -p 2181:2181 -p 9090:9090 -p 9095:9095 -p 16000:16000 -p 16010:16010 -p 16201:16201 -p 16301:16301 --name hbase1.3 harisekhon/hbase:1.3
-d 表示后台运行
-h 表示设置docker容器的虚拟主机名
-p 表示端口映射,冒号前是主机端口号,冒号后是外部映射端口号,其中2181是Zookeeper的端口,16010是HBase的端口
--name 表示给docker容器取名

然后我们使用下面的命令查看容器启动状态:

docker ps

首先可以使用下面的命令进入容器内部,测试HBase能否正常使用:

docker exec -it hbase1.3 bash #进入容器的bash
hbase shell #进入hbase命令行
list #查看表列表

能出现以下的结果则说明容器启动成功:

或者可以直接访问本地的16010端口查看web页面:

至此,本地的Docker搭建HBase的环境就结束了,后面我们就能使用API对HBase进行一系列的数据库操作。

HBase的概述

HBase的架构

首先我们先看一下HBase的架构图:

从图中可以看出Hbase是由Client、Zookeeper、Master、HRegionServer、HDFS等几个组件组成,下面来介绍一下几个组件的相关功能:

1.Client

​ Client包含了访问HBase的接口,另外Client还维护了对应的cache来加速HBase的访问,比如cache的META元数据的信息。

2.Zookeeper

​ HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。具体工作如下:

​ 通过Zoopkeeper来保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务;通过Zoopkeeper来监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式通知Master RegionServer上下线的信息;通过Zoopkeeper存储元数据的统一入口地址。

3.HMaster(NameNode)

​ master节点的主要职责如下:为RegionServer分配Region;维护整个集群的负载均衡;维护集群的元数据信息;发现失效的Region,并将失效的Region分配到正常的RegionServer上;当RegionSever失效的时候,协调对应Hlog的拆分。

4.HRegionServer(DataNode)

​ HRegionServer直接对接用户的读写请求,是真正"干活"的节点。它的功能概括如下:管理master为其分配的Region;处理来自客户端的读写请求;负责和底层HDFS的交互,存储数据到HDFS;负责Region变大以后的拆分;负责Storefile的合并工作。

5.HDFS

​ HDFS为Hbase提供最终的底层数据存储服务,同时为HBase提供高可用(Hlog存储在HDFS)的支持,具体功能概括如下:提供元数据和表数据的底层分布式存储服务;数据多副本,保证的高可靠和高可用性。

附上HBase的读写数据原理图:

HBase中的角色

1.HMaster

​ 监控RegionServer;处理RegionServer故障转移;处理元数据的变更;处理region的分配或转移;在空闲时间进行数据的负载均衡;通过Zookeeper发布自己的位置给客户端。

2.RegionServer

​ 负责存储HBase的实际数据;处理分配给它的Region;刷新缓存到HDFS;维护Hlog;执行压缩;负责处理Region分区。

HBase中的其他组件

1.Write-Ahead logs

​ HBase的修改记录,当对HBase读写数据的时候,数据不是直接写进磁盘,它会在内存中保留一段时间(时间以及数据量阈值可以设定)。但把数据保存在内存中可能有更高的概率引起数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入内存中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。

2.Region

​ HBase表的分区,HBase表会根据RowKey值被切分成不同的region存储在RegionServer中,在一个RegionServer中可以有多个不同的region。

3.Store

​ HFile存储在Store中,一个Store对应HBase表中的一个列族(列簇,Column Family)。

4.MemStore

​ 顾名思义,就是内存存储,位于内存中,用来保存当前的数据操作,所以当数据保存在WAL中之后,RegsionServer会在内存中存储键值对。

5.HFile

​ 这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以Hfile的形式存储在HDFS的。

使用API访问HBase

HBase也支持shell命令进行操作数据库,进入到docker容器中然后输入hbase shell命令回车,即可进入到命令行模式,但通常我们更多的是使用API进行操作数据库,因为很多时候我们写的MapReduce就需要放在Hadoop上运行,所以掌握API操作HBase是非常重要的。

导入Maven依赖

<dependencies><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>1.3.2</version></dependency>
</dependencies>

封装工具类

测试API的过程中发现每次连接HBase都需要配置连接信息,还有关闭资源这些操作,就想到将他们封装成一个工具类,其中还包含了生成分区键和分区号的方法,采用了和Map存放类似的生成hash码的方式。

package com.jinqi.util;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;import java.io.IOException;/*** HBase操作工具类*/
public class HBaseUtil {//保证线程安全,从本地线程缓存中获取连接private static ThreadLocal<Connection> connHolder = new ThreadLocal<Connection>();//    private static Connection conn = null;private HBaseUtil() {}/*** 获取连接对象* @return*/public static void makeHBaseConnection(String hostName,String post) throws IOException {//        Configuration conf = HBaseConfiguration.create();
//        conf.set("hbase.zookeeper.quorum", hostName);
//        conf.set("hbase.zookeeper.property.clientPort", post);
//        conn = ConnectionFactory.createConnection(conf);Connection conn = connHolder.get();if (conn == null){Configuration conf = HBaseConfiguration.create();conf.set("hbase.zookeeper.quorum", hostName);conf.set("hbase.zookeeper.property.clientPort", post);conn = ConnectionFactory.createConnection(conf);connHolder.set(conn);}}/*** 生成分区键,例如3个分区需要两个分区键* @param regionCount* @return*/public static byte[][] genRegionKeys(int regionCount){byte[][] bs = new byte[regionCount-1][];for (int i = 0; i < regionCount - 1; i++) {bs[i] = Bytes.toBytes(i+"|");}return bs;}/*** 生成分区号* @param rowKey 根据rowKey生成分区号* @param regionCount 分区数量*/public static String genRegionNum(String rowKey,int regionCount){int regionNum;int hash = rowKey.hashCode();if (regionCount > 0 && (regionCount & (regionCount -1)) == 0){//2的n次方regionNum = hash & (regionCount - 1);}else {regionNum = hash & (regionCount);}return regionNum + "_" + rowKey;}/*** 插入数据* @param tableName* @param rowKey* @param family* @param value*/public static void insertData(String tableName,String rowKey,String family,String column,String value) throws IOException {Connection conn = connHolder.get();Table table = conn.getTable(TableName.valueOf(tableName));Put put = new Put(Bytes.toBytes(rowKey));put.addColumn(Bytes.toBytes(family),Bytes.toBytes(column),Bytes.toBytes(value));table.put(put);table.close();}/*** 关闭连接*/public static void close() throws IOException {Connection conn = connHolder.get();if (conn != null){conn.close();connHolder.remove();}}
}

连接、插入数据测试:

package com.jinqi.hbase;import com.jinqi.util.HBaseUtil;
import java.io.IOException;/*** 测试HBase API*/
public class TestHbaseAPI3 {public static void main(String[] args) throws IOException {//创建连接对象HBaseUtil.makeHBaseConnection("myhbase", "2181");HBaseUtil.insertData("ross:student", "1003", "info", "name", "jinqi");//关闭连接HBaseUtil.close();}
}

查询数据

package com.jinqi.hbase;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.util.Bytes;import java.io.IOException;/*** 查询*/
public class TestHbaseAPI4 {public static void main(String[] args) throws IOException {Configuration conf = HBaseConfiguration.create();conf.set("hbase.zookeeper.quorum", "myhbase");conf.set("hbase.zookeeper.property.clientPort", "2181");Connection connection = ConnectionFactory.createConnection(conf);TableName tableName = TableName.valueOf("student");Table table = connection.getTable(tableName);Scan scan = new Scan();
//        scan.addFamily(Bytes.toBytes("info"));BinaryComparator bc = new BinaryComparator(Bytes.toBytes("1002"));RegexStringComparator rsc = new RegexStringComparator("^\\d{5}$");
//        Filter filter = new RowFilter(CompareFilter.CompareOp.GREATER_OR_EQUAL,bc);Filter filter = new RowFilter(CompareFilter.CompareOp.EQUAL,rsc);RowFilter rowFilter = new RowFilter(CompareFilter.CompareOp.EQUAL,bc);//MUST_PASS_ALL:必须满足所有条件//MUST_PASS_ONE:只需要满足一个即可,能显示所有满足条件的数据//过滤器的集合FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);list.addFilter(filter);list.addFilter(rowFilter);//扫描时,增加过滤器,即添加查询规则//过滤,每条数据都会过滤,性能较低scan.setFilter(list);ResultScanner scanner = table.getScanner(scan);for (Result result : scanner) {//展示数据for (Cell cell : result.rawCells()) {System.out.println("rowKey=" + Bytes.toString(CellUtil.cloneRow(cell)));System.out.println("family=" + Bytes.toString(CellUtil.cloneFamily(cell)));System.out.println("column=" + Bytes.toString(CellUtil.cloneQualifier(cell)));System.out.println("value=" + Bytes.toString(CellUtil.cloneValue(cell)));}}table.close();connection.close();}
}

简单API的操作已经介绍完了,但通过HBase的相关Java API,我们可以实现伴随HBase操作的MapReduce过程,比如使用MapReduce将数据从本地文件系统导入到HBase的表中,比如我们从HBase中读取一些原始数据后使用MapReduce做数据分析,这些内容我们会在后面的文章中总结。

使用Docker部署HBase并使用Java-API连接相关推荐

  1. ASP.NET Core微服务(七)——【docker部署linux上线】(RDS+API接口测试部分)

    ASP.NET Core微服务(七)--[docker部署linux上线]: 本文测试采用阿里云的RDS(sqlserver服务器)+ECS(linux服務器)进行测试,由于是测试,[按量付费]买个最 ...

  2. java连接虚拟机hadoop_本地eclipse java api连接远程虚拟机HBase

    1.本地与远程连通 无论是域名或者ip都可以,另外需保证HBase在虚拟机集群上正常运行. 2.本地要有一个跟远程相同的hadoop环境 当然不相同,只要兼容也可以,现采用hadoop-2.5.0-c ...

  3. Java API连接Kerberos认证的HBASE

    网上关于 Java 代码连接启用了Kerberos认证的HBASE资料很多,但是总感觉不够准确,总是出现各种问题.经过整合网上资料和亲自试验,得出连接成功的最小配置项如下: java.security ...

  4. Java API连接HBase

    导入依赖 <dependency><groupId>junit</groupId><artifactId>junit</artifactId> ...

  5. HBase的常用Java API

    1. 创建HBase表的对象 HBase表的对项名字叫HTable,创建它的方法有很多,常见的有如下: org.apache.hadoop.hbase.client.HTable hTable = n ...

  6. 报错:使用java api连接redis集群时报错 READONLY You can't write against a read only slave....

    报错: READONLY You can't write against a read only slave. 报错原因: 因为连接的是从节点,从节点只有读的权限,没有写的权限 解决方案: 进入red ...

  7. hadoop 使用HA后java api连接获取 FileSystem

    所需要配置的参数:  Configuration conf = new Configuration();   conf.set("fs.defaultFS", "hdfs ...

  8. 报错:使用java api连接redis集群时报错 READONLY You can't write against a read only slave.

    报错: READONLY You can't write against a read only slave. 报错原因: 因为连接的是从节点,从节点只有读的权限,没有写的权限 解决方案: 进入red ...

  9. HBase总结(十二)Java API 与HBase交互实例

    HBase提供了Java Api的访问接口,掌握这个就跟Java应用使用RDBMS时需要JDBC一样重要 [html] view plaincopy import java.io.IOExceptio ...

最新文章

  1. HashSet 与TreeSet和LinkedHashSet的区别
  2. 使用python发送邮件和接收邮件
  3. java架构师进阶之独孤九剑:数据结构以及书籍推荐
  4. Vue 项目调试总结
  5. 嵌入式linux加载引导内核和根文件系统的方法
  6. 1.4.1bat脚本命令COPY 拷贝 复制到
  7. Java设计模式中的单例模式
  8. MVVM模式下,自定义用户控件不执行COMMAND的原因
  9. HTML5日期输入框(date)
  10. 玩转二叉链表 (20 分)
  11. C如何简单的读写文件?二进制文件如何读写?如何移动文件指针?
  12. python 空数组_Python笔记
  13. windows计算机查看里设置,windows10电脑配置怎么查看
  14. [报错]CXF动态客户端报错:No operation was found with the name
  15. PD3.0 PPS限流
  16. EasyExcel解析动态表头及导出
  17. Unity技能系统框架(三)分析一个具体被动技能
  18. Spring 02
  19. 人民币升值,贬值,顺差,逆差,货币国际化
  20. 交通运输大数据发展特点、政策、应用及趋势 | 交通运输部科学研究院黄莉莉

热门文章

  1. 未来已来,光伏产业将走向何方?十大趋势待揭晓!
  2. linux程序返回码的含义
  3. RabbitMQ消息可靠性投递及分布式事务最终一致性实现
  4. Hive:split函数
  5. 11月最新纯净版XP系统999宝藏网GhostXP_SP3会员专用版V5.0
  6. c++20中的分支预测
  7. php 多版本开发环境,「开发环境」让 Valet 支持多个本地项目使用不同 PHP 版本...
  8. 切尔诺贝利是hbo的吗_什么是HBO Max,值得花多少钱?
  9. matplotlib绘图练习2——绘制菱形sin,星形cos
  10. 时速云正式成为中国通信标准化协会全权会员