《HBase 基础》学习指导

一、HBase 安装

参考:《HBase 分布式环境搭建》要求会搭建分布式 HBase 环境。

二、HBase 架构原理

1.1 HBase 架构

HBase 架构是比较复杂的,也是比较难理解的部分。

HBase 也是 Master/slaves 架构,从前面安装环境应该能看出,HBase 分布式环境安装成功后,是有一个 HMaster,多个 HResgionServer 进程。HBase 架构如图所示:

hbase初探实验 hbase实验报告答案_HDFS


从上图中能看出 HBase 是由 Client、ZooKeeper、HMaster、HRegionServer、HDFS 等几个组件组成,组件的相关功能:

Hbase的角色:
Client:客户端 缓存 Region 的位置信息,减少获取元数据的时间
ZooKeeper:HMaster的高可用、HRegionServer的监控、元数据的入口以及集群配置的维护等工作
HMaster:HRegionServer 故障转移,新的HRegion的分配,处理元数据的变更,数据的负载均衡,发布自己的位置给客户端。
HRegionServer:负责和底层 HDFS 的交互,存储数据到 HDFS;处理分配给它的 HRegion;刷新缓存到 HDFS;维护 HLog;处理来自客户端的读写请求;负责处理 HRegion 变大后的拆分;负责 StoreFile 的合并工作
HDFS:提供元数据和表数据的底层分布式存储服务。数据多副本,保证的高可靠和高可用性。
Write-Ahead Logs:预写日志,Hbase读写数据的时候会将数据保存在内存中,数据在写入内存前会先写在一个叫做 Write-Ahead logfile 的文件中,然后再写入内存中,系统出现故障的时候,数据可以通过这个日志文件重建。
HRegion:一张表分片成不同的HRegion分散在不同的HRegionServer上,一个HRegionServer上的HRegion来自不同的表。(类似hdfs的block块的概念理解)
Store:一个HRegion中的一个列族为一个Stroe,
MemStore:内存存储。当数据保存在 WAL (Write-Ahead Logs) 预写日志中之后,HRegsionServer 会在内存中存储键值对。达到一定阈值会被刷写到HFile中。
HFile:是实际的存储文件。StoreFile是以 HFile 的形式存储在 HDFS 的。文件内容是二进制。

1. Client

Client客户端 可以是 HBase Shell、Java API 客户端、RestAPI 等Client 就是用来访问 HBase 数据库的,它不仅提供了访问接口,还维护了对应的缓存(cache)来加速 HBase 的访问。Client 端的缓存主要是缓存 Region 的位置信息,减少获取元数据的时间。当 Client 端没有缓存的时候(第一次请求),会加载 Region 的位置信息到 Client 端,后面直接使用 cache 中的信息,如果出现重试,则会重新获取 Region 的位置信息,更新 Client 端的 cache。

2. ZooKeeper

HBase 通过 ZooKeeper 来做 HMaster 的高可用、HRegionServer 的监控、元数据的入口以及集群配置的维护等工作。它具体工作如下:
(1)通过 ZoopKeeper 来保证集群中只有 1 个 HMaster 在运行,如果 HMaster异常,会通过竞争机制产生新的 HMaster 提供服务。
(2)通过 ZoopKeeper 来监控 HRegionServer 的状态,当 HRegionSevrer 有异常的时候,通过 Master 会收到 ZooKeeper 消息通知 HRegionServer 上下线的信息。
(3)通过 ZoopKeeper 存储元数据的统一入口地址(该部分内容后面会介绍具体存储了什么元数据信息)。

3. HMaster

HMaster 节点的主要职责如下:
(1)监控 HRegionServer ,处理 HRegionServer 故障转移,当某个HRegionServer 挂掉时,ZooKeeper 会将分配在该 HRegionServer 上的 HRegion 分配到其他 HRegionServer 上进行管理。
(2)HRegion 分裂后,负责新的 HRegion 的分配。
(3)处理元数据的变更,比如对表的添加,修改,删除等操作。
(4)在空闲时间进行数据的负载均衡,主要就是在 HRegionServer 间迁移HRegion,达到负载均衡。
(5)通过 ZooKeeper 发布自己的位置给客户端。

4. HRegionServer

HRegionServer 直接负责用户的读写请求,是真正的“干活”的节点。它的功能概括如下:
(1)负责和底层 HDFS 的交互,存储数据到 HDFS,HBase 是依托于 HDFS的 NoSQL 数据库,数据会存储在 HDFS 上。后面《数据 Flush 过程》会解释什么时候执行数据存储到 HDFS 上的操作。
(2)处理分配给它的 HRegion。
(3)刷新缓存到 HDFS。
(4)维护 HLog,HLog 是一个容错机制,下面的内容会介绍到 HLog 的功能。
(5)处理来自客户端的读写请求。HRegionServer 是实际管理数据的,所以客户端的读写请求最终都要由 HRegionServer 来处理。
(6)负责处理 HRegion 变大后的拆分。
(7)负责 StoreFile 的合并工作。

5. HDFS

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

6. Write-Ahead Logs

Write-Ahead Logs 也叫预写日志,在 HBase 中为 HLog,HLog 存储在 HDFS 上。为什么存在要有预写日志呢?其实跟 HBase 架构设计有关,当对 HBase 读写数据的时候,数据不是直接写进磁盘,它会在内存中保留一段时间(时间以及数据量阈值可以设定)。但把数据保存在内存中可能有更高的概率引起数据丢失,为了解决这个问题,数据在写入内存之前会先写在一个叫做 Write-Ahead logfile 的文件中,然后再写入内存中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。需要注意的是,HLog 是每一个 RegionServer 对应一个。

7. HRegion

HRegion 可以看成是表的横向切分,HBase 表的分片,HBase 每个表都会根据 RowKey 值被切分成不同的 HRegion 分散存储在 HRegionServer 中,在一个 HRegionServer 中可以有多个不同的 HRegion。这些 HRegion 可以是来自不同的表。HRegion、Table、HRegionServer 关系如下面的图所示。(该部分可以画图使用两个表 TableA、TableB,分别切成 HRegion,分散存储在 HRegionServer 上进行理解)

hbase初探实验 hbase实验报告答案_数据_02


值得注意的是,一个 HRegion 只能在一个 HRegionServer 上,不能跨多个HRegionServer。

8. Store

每一个 HRegion 内部,又分为多个 Store,一个 Store 对应表中的一个列族。也就是说一个 Store 存储了对应表该列族下的部分数据。

9. MemStore

顾名思义,就是内存存储,位于内存中,用来保存当前的数据操作,所以当数据保存在 WAL (Write-Ahead Logs) 中之后,HRegsionServer 会在内存中存储键值对。当RS处理写请求的时候,数据首先写入到Memstore,然后当到达一定的阀值的时候,Memstore中的数据会被刷到HFile中。

10.HFile

这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以 HFile 的形式存储在 HDFS 的。文件内容是二进制。组件功能可以看该文档《写流程》和《数据 Flush 过程》。

1.2 HBase 数据存储结构

HBase 是稀疏的,稀疏主要是针对 HBase 列的灵活性,在列族中,你可以指定任意多的列,在列数据为空的情况下,是不会占用存储空间的。HBase 底层存储的数据是 KeyValue 格式的数据。这一块内容在 hbase shell 插入数据部分有详细的解释。HBase 逻辑上也可以看成一个二维表格,可以添加行,可以动态添加列。

Hbase数据存储结构:
RowKey:RowKey 是用来检索记录的主键。HBase 中表数据会按照 RowKey 进行排序(字典序,在设计RowKey时将经常一起读取的行存储放到一起),并会在 HRegion 达到一定大小后,会按照 RowKey 范围进行裂变
Column Family:列族,需要在建表的时候定义列族,每个列都属于某个列族,列名都以列族作为前缀。每一个列族对应一个 Store,在物理存储上对应于 HDFS 上的一个目录
Cell:由 { RowKey, ColumnFamily, Version } 唯一确定的单元,Version实际是TimeStamp,其中数据没有类型都是字节码形式存储
Time Stamp:时间戳,HBase通过时间戳来管理版本,最新的时间戳在最前面。可以由HBase在数据写入时自动赋值

1.2.1 RowKey

RowKey 是用来检索记录的主键。类似关系型数据库中的主键,但是 RowKey 在 HBase 中功能不只是为了检索,HBase 中表数据会按照 RowKey 进行排序,并会在 HRegion 达到一定大小后,会按照 RowKey 范围进行裂变(该部分内容在下一课内容中会详解)。
HBase Table 中的行,只有三种方式:
1.通过单个 RowKey 访问
2.通过 RowKey 的 range(正则)
3.全表扫描
RowKey 行键 (RowKey)可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在 HBase 内部,RowKey 保存为字节数组。存储时,数据按照 RowKey 的字典序排序存储。设计 RowKey 时,要充分利用排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)。

1.2.2 Column Family

列族是 HBase 对表在纵向上的优化,前面介绍过 Region,将一个表横向上切成多个 Region,列族是在纵向进行切分的,将多列分成一组进行管理。列族在在物理存储上对应于 HDFS 上的一个目录。HBase 表中的每个列,都归属于某个列族。列族是表的 schema 的一部分(而列不是),必须在使用表之前定义(也就是创建表时定义)。列名都以列族作为前缀。例如 courses:history,courses:math 都属于 courses 这个列族。
每一个列族对应一个 Store,也对应 HDFS 一个目录,类似于 Hive 分区操作一样,HBase 相当于按列族进行了分区。(该部分内容可以辅助查看 HBase Shell操作插入数据部分内容)

1.2.3 Cell

由 { RowKey, ColumnFamily, Version } 唯一确定的单元。其中 Versions 实际上是TimeStamp。Cell 可以看成是一个存储空间,类似与 Excel 中的单元格,Cell 中的数据是没有类型的,全部是字节码形式存储。

1.2.4 Time Stamp

HBase中通过rowkey和 ColumnFamily:Column确定的一个存储单元称为Cell。每个 Cell 都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64 位整型。时间戳可以由 HBase(在数据写入时自动 )赋值,此时时间戳是精确到毫秒 的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 cell 中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
为了避免数据存在过多版本造成的管理 (包括存储和索引)负担,HBase 提供了两种数据版本回收方式。一是保存数据的最后 n 个版本,二是保存最近一段时间内的版本(比如最近七天)。

1.3 HBase 原理

1.3.1 元数据存储

HBase 中有一个系统表 hbase:meta 存储 HBase 元数据信息,可以在 HBase Web UI 查看到相关信息。如下图。

hbase初探实验 hbase实验报告答案_客户端_03


该表记录保存了每个表的 Region 地址,还有一些其他信息,例如 Region 的名字,对应表的名字,开始行键,结束行键,服务器的信息。hbase:meta 表中每一行对应一个单一的 Region。数据如下图。

// 创建表customer  定义两个列族 addr 和 gender 
create 'customer' ,{ NAME=>'addr'},{NAME =>'gender'}
// 插入数据  向addr列族中插入RowKey为r1 列city city列的值为NanJing
put 'customer','r1','addr:city','NanJing'
scan 'customer'
ROW         COLUMN+CELL
 r1         column=addr:city, timestamp=1608193479129, value=NanJing
scan 'hbase:meta'
选取和customer表相关的内容展示如下:
customer,,1608193373282.923856b234205aaa9c9fad660320b0d6.    column=info:regioninfo, timestamp=1608193373770, value={ENCODED => 923856b234205aaa9c9fad660320b0d6, NAME => 'custofad660320b0d6.', STARTKEY => '', ENDKEY => ''}
customer,,1608193373282.923856b234205aaa9c9fad660320b0d6.    column=info:seqnumDuringOpen, timestamp=1608193373770, value=\x00\x00\x00\x00\x00\x00\x00\x02
customer,,1608193373282.923856b234205aaa9c9fad660320b0d6     column=info:server, timestamp=1608193373770, value=hadoop100:60020
customer,,1608193373282.923856b234205aaa9c9fad660320b0d6.    column=info:serverstartcode, timestamp=1608193373770, value=1608169478373

hbase:meta表单个数据含义:

hbase初探实验 hbase实验报告答案_hbase初探实验_04

1.ZooKeeper 中存储了 hbase:meta 表的位置,客户端可以通过 ZooKeeper 查找到 hbase:meta 表的位置,hbase:meta 是 hbase 当中一张表,肯定由一个 HRegionServer 来管理,其实主要就是要通过ZooKeeper的“/hbase/meta-region-server”获取存储“hbase:meta”表的 HRegionServer 的地址。

[root@hadoop100 ~]# zkCli.sh
[zk: localhost:2181(CONNECTED) 1] get /hbase/meta-region-server

hbase初探实验 hbase实验报告答案_HDFS_05


图中可以看出,hbase:meta 表的位置是 hadoop100

1.3.2 读流程(面试重点)

HBase 读数据流程如图所示:

hbase初探实验 hbase实验报告答案_HDFS_06


1.Client 先访问 ZooKeeper,从 meta 表读取 Region 的位置,然后读取 meta 表中的数据。meta 中又存储了用户表的 Region 信息;

2.根据 RowKey 在 meta 表中找到对应的 Region 信息;

3.找到这个 Region 对应的 RegionServer;

4.查找对应的 Region;

5.先从 MemStore 找数据,如果没有,再到 BlockCache 里面读;

6.BlockCache 还没有,再到 StoreFile 上读(为了读取的效率);

7.如果是从 StoreFile 里面读取的数据,不是直接返回给客户端,而是先写入 BlockCache,再返回给客户端。

从整体的方面看,如下图所示:

hbase初探实验 hbase实验报告答案_客户端_07

1.3.3 写流程(面试重点)

需要能用自己的话描述 HBase 写数据流程。

Hbase 写流程如图所示(写数据比读数据要快):

hbase初探实验 hbase实验报告答案_hbase初探实验_08


1.Client 访问 ZooKeeper,获取 Meta 表所处位置(ip)

2.访问 Meta 表,然后读取 Meta 表中的数据。

3.根据 namespace(类似与关系型数据库中的数据库,下一课会介绍)、表名和 RowKey 在 Meta 表中找到该 RowKey 应该写入到哪个 Region。

4.找到这个 Region 对应的 RegionServer,并发送写数据请求

5.HRegionServer 将数据先写到 HLog(Write Ahead Log)。为了数据的持久化和恢复;

6.HRegionServer 将数据写到内存(MemStore);

7.反馈 Client 写成功。

写数据这一块也可以看出,HBase 将数据写入到内存中后,就返回给客户端写入成功,响应非常快。这也是为什么 HBase 写数据速度快的原因。

1.3.4 数据 Flush 过程

从上面写入数据的流程中可以看出,HBase 写数据是写入到 MemStore 内存就会返回客户端了,并没有直接落磁盘。这也是为什么 HBase 插入数据会比较快的原因,磁盘 IO 非常小。那么什么时候数据会落磁盘呢?
其实 MemStore 空间是有限的,当 MemStore 数据达到阈值(默认是 128M,老版本是 64M),RegionServer 将数据刷到 HDFS 上,生成 HFile,然后将内存中的数据删除,同时删除 HLog 中的历史数据。该操作是由 RegionServer 自己完成的。

三、HBase Shell 操作

开发重点,后面项目中也经常使用。

3.1 基本操作

1.进入 HBase 客户端命令行
[hadoop@hadoop102 hbase]$ $HBASE_HOME/bin/hbase shell
注意:进入到 shell 环境后,不能使用退格键,需要使用 crtl+退格键。
2.查看帮助命令
hbase(main):001:0> help
HBase Shell, version 1.2.0-cdh5.14.2, rUnknown, Tue Mar 27 13:31:54 PDT 2018
Type 'help "COMMAND"', (e.g. 'help "get"' -- the quotes are necessary) for help on a specific command.
Commands are grouped. Type 'help "COMMAND_GROUP"', (e.g. 'help "general"') for help on a command group.

COMMAND GROUPS:
  Group name: general
  Commands: status, table_help, version, whoami

  Group name: ddl
  Commands: alter, alter_async, alter_status, create, describe, disable, disable_all, drop, drop_all, enable, enable_all, exists, get_table, is_disabled, is_enabled, list, locate_region, show_filters

  Group name: namespace
  Commands: alter_namespace, create_namespace, describe_namespace, drop_namespace, list_namespace, list_namespace_tables

  Group name: dml
  Commands: append, count, delete, deleteall, get, get_counter, get_splits, incr, put, scan, truncate, truncate_preserve

  Group name: tools
  Commands: assign, balance_switch, balancer, balancer_enabled, catalogjanitor_enabled, catalogjanitor_run, catalogjanitor_switch, close_region, compact, compact_mob, compact_rs, flush, major_compact, major_compact_mob, merge_region, move, normalize, normalizer_enabled, normalizer_switch, split, trace, unassign, wal_roll, zk_dump

  Group name: replication
  Commands: add_peer, append_peer_tableCFs, disable_peer, disable_table_replication, enable_peer, enable_table_replication, get_peer_config, list_peer_configs, list_peers, list_replicated_tables, remove_peer, remove_peer_tableCFs, set_peer_tableCFs, show_peer_tableCFs, update_peer_config

  Group name: snapshots
  Commands: clone_snapshot, delete_all_snapshot, delete_snapshot, list_snapshots, restore_snapshot, snapshot

  Group name: configuration
  Commands: update_all_config, update_config

  Group name: quotas
  Commands: list_quotas, set_quota

  Group name: security
  Commands: grant, list_security_capabilities, revoke, user_permission

  Group name: procedures
  Commands: abort_procedure, list_procedures

  Group name: visibility labels
  Commands: add_labels, clear_auths, get_auths, list_labels, set_auths, set_visibility

  Group name: rsgroup
  Commands: add_rsgroup, balance_rsgroup, get_rsgroup, get_server_rsgroup, get_table_rsgroup, list_rsgroups, move_servers_rsgroup, move_tables_rsgroup, remove_rsgroup

SHELL USAGE:
Quote all names in HBase Shell such as table and column names.  Commas delimit
command parameters.  Type <RETURN> after entering a command to run it.
Dictionaries of configuration used in the creation and alteration of tables are
Ruby Hashes. They look like this:

  {'key1' => 'value1', 'key2' => 'value2', ...}

and are opened and closed with curley-braces.  Key/values are delimited by the
'=>' character combination.  Usually keys are predefined constants such as
NAME, VERSIONS, COMPRESSION, etc.  Constants do not need to be quoted.  Type
'Object.constants' to see a (messy) list of all constants in the environment.

If you are using binary keys or values and need to enter them in the shell, use
double-quote'd hexadecimal representation. For example:

  hbase> get 't1', "key\x03\x3f\xcd"
  hbase> get 't1', "key\003\023\011"
  hbase> put 't1', "test\xef\xff", 'f1:', "\x01\x33\x40"

The HBase shell is the (J)Ruby IRB with the above HBase-specific commands added.
For more on the HBase Shell, see http://hbase.apache.org/book.html
3.查看当前数据库中有哪些表
hbase(main):002:0> list

3.2 表的操作

1.创建表
hbase(main):002:0> create 'customer', {NAME=>'addr'}, {NAME=>'order'}

NAME=>‘xxx’,xxx 为列族的名字。HBase 中创建一个表,必须指定至少一个列族。
创建完表后,可以在 HDFS 上查看对应的目录结构,表其实就是对应 HDFS上一个目录。列族就对应 HDFS 上一个文件夹。

2.插入数据到表
hbase(main):003:0> put 'customer', 'jsmith', 'addr:city', 'montreal'
hbase(main):004:0> put 'customer', 'jsmith', 'addr:state', 'ON'
hbase(main):005:0> put 'customer', 'jsmith', 'order:numb', '123456'
hbase(main):006:0> put 'customer', 'jsmith', 'order:date', '2015-12-19'
插入数据后,到对应的列族目录下,发现没有对应的文件生成。

这就证明,HBase 写入数据是没有直接落磁盘的,是先在缓冲中的。为了方便演示,可以手动刷出缓存,命令为 flush,在命令行输入 flush,会提示使用方法。

hbase(main):007:0> flush 'customer'

flush 完成后,可以看到对应的列族目录下,有数据文件了,该文件就是 HFile。
列族目录下的文件,可以尝试使用 hdfs 命令查看其内容,会发现是二进制的内容。HBase 提供了查看该文件内容的方式。下面命令在 Linux 命令行执行,不是在 hbase shell 中。

[hadoop@hadoop102 ~]$ hbase hfile -v -p -f
/hbase/data/default/customer/4474c890bdded1896e16cfdab597a956/addr/a6497c8fcab24c48be20c7c6b90392ea

执行完后,会输出下面的内容(只是部分,元数据信息没有列出):

K: jsmith/addr:city/1575960250464/Put/vlen=8/seqid=4 V: montreal
K: jsmith/addr:state/1575960257776/Put/vlen=2/seqid=5 V: ON

前面是 K,后面是 V,从这里也能看出 HBase 是 KeyValue 数据库。

3. 插入多行数据
put 'customer', 'jsmith', 'order:numb', '1235'
put 'customer', 'jsmith', 'order:numb', '1236'
put 'customer', 'jsmith', 'order:numb', '1237'
put 'customer', 'jsmith', 'order:numb', '1238'
put 'customer', 'njones', 'addr:city', 'miami'
put 'customer', 'njones', 'addr:state', 'FL'
put 'customer', 'njones', 'order:numb', '5555'
put 'customer', 'tsimmons', 'addr:city', 'dallas'
put 'customer', 'tsimmons', 'addr:state', 'TX'
put 'customer', 'jsmith', 'addr:city', 'denver'
put 'customer', 'jsmith', 'addr:state', 'CO'
put 'customer', 'jsmith', 'order:numb', '6666'
put 'customer', 'njones', 'addr:state', 'TX'
put 'customer', 'amiller', 'addr:state', 'TX'
4. 扫描查看表
scan 'customer'
scan 'customer', {COLUMNS=>['order:numb'], VERSIONS => 2}
scan 'customer', {STARTROW => 'j', STOPROW => 't'}
5. 查看表结构
desc 'customer'
6. 更新指定字段的数据
put 'customer', 'jsmith', 'order:numb', '654321'
7. 查看“指定行”或“指定列族:列”的数据
get 'customer', 'jsmith'
get 'customer', 'jsmith','addr'
get 'customer', 'jsmith','addr:city'
8. 统计表数据行数
count 'customer'
9. 删除数据

删除某 rowkey 的全部数据

deleteall 'customer','jsmith'

删除某 rowkey 的某一列数据:

delete 'customer','njones','addr:city'
10. 清空表数据
truncate 'customer'

提示:清空表的操作顺序为先 disable,然后再 truncate。disable 的操作会自
动完成。

11. 删除表,注意需要先 disable 表,不然直接删除会报错。

首先需要先让该表为 disable 状态:

disable 'customer'

然后才能 drop 这个表:

drop 'customer'

提示:如果直接 drop 表,会报错:ERROR: Table customer is enabled. Disable it first.

12. 变更表信息

将 order 列族中的数据设置为可以存放 5 个版本:

alter 'customer',NAME=>'order', VERSIONS=>5
13. 获取多版本数据。

先更新一条数据。

put 'customer', 'tsimmons', 'order:city', 'beijing'
put 'customer', 'tsimmons', 'order:city', 'beijing2'

查看多版本数据。

get 'customer','tsimmons',{COLUMN=>'order:city',VERSIONS=>2}

继续添加数据:

put 'customer', 'tsimmons', 'order:city', 'beijing3'
put 'customer', 'tsimmons', 'order:city', 'beijing4'
put 'customer', 'tsimmons', 'order:city', 'beijing5'
put 'customer', 'tsimmons', 'order:city', 'beijing6'
get 'customer','tsimmons',{COLUMN=>'order:city',VERSIONS=>5}
get 'customer','tsimmons',{COLUMN=>'order:city',VERSIONS=>6}

四、HBase API 操作

项目部分会使用到从 Kafka 消费数据,然后存储到 HBase 数据库,使用的是HBase Java API。所以这部分代码需要学员掌握。

4.1 环境准备

新建项目后在 pom.xml 中添加依赖:

<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>1.2.0-cdh5.14.2</version>
</dependency>
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-common</artifactId>
    <version>1.2.0-cdh5.14.2</version>
</dependency>
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-server</artifactId>
    <version>1.2.0-cdh5.14.2</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.6.0-cdh5.14.2</version>
</dependency>

下载cloudera版本可能需要的:

<repositories>
    <repository>
        <id>cloudera</id>
        <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
    </repository>
</repositories>

4.2 HBaseAPI

4.2.1 获取 Configuration 对象
package com.kgc.hbase.util;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
/**
* @author kgc
*/
public class HBaseConfigUtil {
    /**
     * 获取配置信息类,需要指定 hbase-site.xml 和 core-site.xml
     * 也可以通过相应的属性进行配置
     *
     * @return
     */
    public static Configuration getHBaseConfiguration() {
        Configuration configuration = HBaseConfiguration.create();
        //configuration.set("hbase.zookeeper.quorum", "localhost");
        //configuration.set("hbase.zookeeper.property.clientPort", "2181");
        //configuration.set("hbase.master","localhost:16000");
        // 我们也可以集群环境中的配置文件中读取配置信息。
        configuration.addResource(new Path("/etc/hbase/conf/hbase-site.xml"));
        configuration.addResource(new Path("/etc/hadoop/conf/core-site.xml"));
        return configuration;
    }
}
4.2.2 Java API 操作

参考演示实例代码。
运行命令:java -cp jar 包 运行主类
可能出现的问题是打包运行的时候如果不是 fat 包,会报如下错误。需要打成 fat 包。

package cn.kgc;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;

import java.io.IOException;

/**
 * @Author: ChaoKeAiMuZhi
 * @Date: 2020/12/18 8:45
 * @Description:
 **/
public class HBASEClientDemo {
    //创建一个表
    @Test
    public void createTable() throws IOException {
        //1. 获取hbase连接,配置
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","hadoop100");
        conf.set("hbase.zookeeper.property.clientPort","2181");
        //2.创建连接
        Connection conn = ConnectionFactory.createConnection(conf);
        //3.创建admin
        Admin admin = conn.getAdmin();
        //4.创建表的相关信息,表名
        HTableDescriptor student = new HTableDescriptor(TableName.valueOf("student"));
        //5.添加列族信息
        student.addFamily(new HColumnDescriptor("info"));
        student.addFamily(new HColumnDescriptor("score"));
        //6.调用创建表的方法进行建表操作
        admin.createTable(student);
        //7.关闭连接
        conn.close();
    }

    //向表中添加数据
    @Test
    public void putData2Table() throws IOException {
        // 1.配置
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","hadoop100");
        conf.set("hbase.zookeeper.property.clientPort","2181");
        // 2.创建连接
        Connection conn = ConnectionFactory.createConnection(conf);
        // 3.获取table
        Table student = conn.getTable(TableName.valueOf("student"));
        // 4.往表中添加数据  rowkey
        Put put = new Put(Bytes.toBytes("1001"));
        // 5.添加列 info:name  zhangsan
        put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("zhangsan"));
        put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("gender"),Bytes.toBytes("male"));
        put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"),Bytes.toBytes(18));
        // 6.插入数据
        student.put(put);
        // 7.关闭连接
        conn.close();
    }

    //读取数据
    @Test
    public void getDataFromTable() throws IOException {
        // 1.配置
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","hadoop100");
        conf.set("hbase.zookeeper.property.clientPort","2181");
        // 2.创建连接
        Connection conn = ConnectionFactory.createConnection(conf);
        // 3.获取table
        Table student = conn.getTable(TableName.valueOf("student"));
        // 4.读取数据,Get
        Get get = new Get(Bytes.toBytes("1001"));
        // 5.获取结果
        Result result = student.get(get);
        // 6.遍历
        Cell[] cells = result.rawCells();
        for (Cell cell : cells) {
            // 由4个值唯一确定的东西
            System.out.println("rowkey:"+Bytes.toString(CellUtil.cloneRow(cell)));
            System.out.println("列族:"+Bytes.toString(CellUtil.cloneFamily(cell)));
            System.out.println("列名:"+Bytes.toString(CellUtil.cloneQualifier(cell)));
            System.out.println("值:"+Bytes.toString(CellUtil.cloneValue(cell)));
            System.out.println("---------------------------------------");
        }
        // 7.关闭
        conn.close();
    }

    //删除
    @Test
    public void dropTable() throws IOException {
        // 1.配置
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","hadoop100");
        conf.set("hbase.zookeeper.property.clientPort","2181");
        // 2.创建连接
        Connection conn = ConnectionFactory.createConnection(conf);
        // 3.获取admin
        Admin admin = conn.getAdmin();
        // 4.禁用表
        admin.disableTable(TableName.valueOf("student"));
        // 5.删除表
        admin.deleteTable(TableName.valueOf("student"));
        // 6.关闭连接
        conn.close();
    }
}