HBase 官方文档

HBase 介绍

HBase 是什么?

  1. Apache HBase™ is the Hadoop database, a distributed, scalable, big data store.
  2. Apache HBase is an open-source, distributed, versioned, non-relational database modeled.
  3. This project’s goal is the hosting of very large tables — billions of rows X millions of columns(亿级的行百万级的列) — atop clusters of commodity hardware.
  4. Use Apache HBase™ when you need random, realtime read/write access to your Big Data.

Apache HBase 是一个 Hadoop 上的数据库。一个分布式,可扩展非关系型的大数据存储引擎。

HBase 的特点

1、HBase 支持非常大的数据集,数十亿行、数百万列。
2、HBase 支持大数据量的随机、实时读写操作。在海量数据中,可以实现毫秒级的数据读写。
3、HBase 的数据是强一致性的,从 CAP 理论来看,HBase 是属于 CP 的。这种设计可以不需要担心脏读、幻读这些事务最终一致性带来的问题。
4、HBase 从一开始就深度集成了 Hadoop。HBase 基于 Hadoop 进行文件持久化,还继承了 Hadoop 带来的强大的可扩展性。

HBase 与 RDBMS

HBase RDBMS
HBase 无模式,不具有固定列的概念;
仅定义列族。
RDBMS 有它的模式,描述表的整体结构的约束。
它专门创建为宽表。 支持横向扩展。Column 可以动态添加,Column 的值为空不需要要占空间。 这些都是细而专为小表。很难形成规模。
Column 不能动态添加,需要更改表结构,而且对于数量大的表添加字段非常麻烦。
另外 column 的值为空也要占空间。
没有任何事务存在于 HBase。 RDBMS 是事务性的。
它用于半结构以及结构化数据是非常好的。 用于结构化数据非常好。
表和表之间分离,没有复杂的表和表之间的关系。 而传统数据库通常有各式各样的函数和连接操作
不支持 sql,只有 rowkey 索引(引入phoenix)。 支持sql,支持多种索引。
支持亿级数据存储和随机读取,数据量大时可水平扩展。 支持千万级数据数据的存取和读取,随数据量性能下降。
自身不能水平扩展。

使用场景

1、场景上不需要复杂的事务,目标只是大数据与高并发。
2、随机读的场景。
3、现有的关系型数据库已经无法在硬件上满足数据疯狂增长的需要。
mysql 中单表数据超过千万时,数据的查询速度越来越慢。而 Hbase 一个表支持数百亿行,上百列。
4、基于大数量高并发操作考虑
为了满足每天上亿级别的访问,而 HBase 根据 Rowkey 进行查询的速度相当快。

HBase 基本操作

HBase 客户端

连接 HBase

  1. 使用 bin/hbase shell 脚本来连接到 HBase
# 查看 HBase 基础指令
[root@192-168-65-174 hbase-2.4.4]# bin/hbase --help
# hbase 命令行
[root@192-168-65-174 hbase-2.4.4]# bin/hbase shell
# 查看帮助
hbase:001:0> help
# 列出已有的表
hbase:002:0> list
# 退出
hbase:002:0> quit

表操作

在 HBase 里参数一般使用 ‘’ 包围。比如 list ‘test’

创建表

使用 create 命名来创建一张表。创建表时需要指定表的名称,和列簇。

create 'tableName','columnFamily'
# 创建表 user 表,有一个列簇 basicinfo
hbase:003:0> create 'user','basicinfo'


# 创建表 user 表,有一个列簇 basicinfo
hbase(main):001:0> create 'test', 'cf'
0 row(s) in 0.4170 seconds
=> Hbase::Table - test

查看表信息

HBase 表操作常用的命令有:list、describe(desc)、disable、enable、drop、alter。
使用 list 命令来确认表是否存在。
使用 describe(desc) 命令来查看表的信息和一些默认配置。
如果需要修改表结构或者删除表,需要先 disable 表。使用 disable 命令来 disable 表,使用 enable 命令来重新启用表。
使用 drop 命令来删除表。

hbase(main):002:0> list 'test'
TABLE
test
1 row(s) in 0.0180 seconds
=> ["test"]

# describe
hbase(main):003:0> describe 'test'
Table test is ENABLED
test
COLUMN FAMILIES DESCRIPTION
{NAME => 'cf', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false',
NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DATA_ON_WRITE
=>
'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0',
REPLICATION_SCOPE => '0', BLOOMFILTER => 'ROW', CACHE_INDEX_ON_WRITE => 'f
alse', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false',
PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION => 'NONE', BLOCKCACHE => 'true',
BLOCKSIZE
=> '65536'}
1 row(s)
Took 0.9998 seconds

# disable、enable
hbase(main):008:0> disable 'test'
0 row(s) in 1.1820 seconds
hbase(main):009:0> enable 'test'
0 row(s) in 0.1770 seconds

# drop
hbase(main):011:0> drop 'test'
0 row(s) in 0.1370 seconds

数据操作

插入数据

put ‘tableName’, ‘rowkey’, ‘columnFamily:columnName’, ‘value’

HBase 查询数据只能依据 Rowkey 来进行查询,而 Rowkey 是由客户端直接指定的,所以在使用 HBase 时, Rowkey 如何设计非常重要,要带上重要的业务信息。

hbase(main):003:0> put 'test', 'row1', 'cf:a', 'value1'
0 row(s) in 0.0850 seconds
hbase(main):004:0> put 'test', 'row2', 'cf:b', 'value2'
0 row(s) in 0.0110 seconds
hbase(main):005:0> put 'test', 'row3', 'cf:c', 'value3'
0 row(s) in 0.0100 seconds

查询数据

使用 get 命令来获取一行数据。语法格式:get ‘tableName’, ‘rowKey’

hbase(main):007:0> get 'test', 'row1'
COLUMN CELL
cf:a timestamp=1421762485768, value=value1
1 row(s) in 0.0350 seconds

使用 scan 命令来获取批量的数据。语法格式:scan ‘tableName’ [,{STARTROW => ‘minRowKey’, STOPROW => ‘maxRowKey’}]。

scan 指令后面的查询条件,STARTROW 和 STOPROW 是必须大写的。查询的结果是左开右闭的。

hbase(main):006:0> scan 'test'
ROW COLUMN+CELL
row1 column=cf:a, timestamp=1421762485768,
value=value1
row2 column=cf:b, timestamp=1421762491785,
value=value2
row3 column=cf:c, timestamp=1421762496210,
value=value3
3 row(s) in 0.0230 seconds

统计数量

使用 count 命令来统计表中的记录数。语法格式为:count ‘tableName’。

#查询表中的记录数。
hbase:013:0> count 'test'

删除数据

删除列
delete ‘tableName’,’rowKey’,’columnFamily:columnName’
删除一行数据:
deleteall ‘tableName’,’rowKey’
清空表数据:
truncate ‘tableName’

#删除某一列
delete 'user','1002','basicinfo:sex'
#删除某一条数据
deleteall 'user','1003'
#清空表数据
truncate 'user'

最佳实践

按月分表

主要针对的是具有时效性的业务数据,随着时间的推移,旧有订单的查询需求越来越少,按月分表可以提高热数据(当月的表)的查询效率。
例如某订单表,记录了大量的数据,并且当月的访问量最大,每月产生 region 上百,建议分表。
另数据写入量比较低的表不建议按月分表。如有些表一个月只有 1 个 region。
如果是日志类数据,数据只保留一段时间,如 1 个月,则不分表, 通过在建表时指定 ttl(存活时间,time to live)来解决表数据膨胀以及清理的问题。如:部分记录访问次数和耗时的日志表,只需要保留一个月的数据即可,则不需要分表,并且需要设置数据的存活时间。

ROWKEY 分布

Rowkey 决定了数据插入和读取的效率,如果 rowkey 设计的不均衡,则会造成集群负载的不均衡。
例如,现在有个表有 3 个 region,rowkey 范围分别是 10000~20000、20000~30000、30000~40000,当某段时间只或大部分写入 rowkey 在 30000~40000 之间的数据时,则只有一个 region 有请求,其他 2 个 region 则是空闲,如果这 3 个 region 分布在不同的机器上,那等于只有 regionserver 有请求,如果这样的表比较多,则会造成巨大的不均衡。
另外一个实际的例子是使用时间戳做 rowkey,因为时间戳有很强的连续性,一段时间内数据只会写入一个 region,就会造成这种结果。
理想的情况是,同一时刻,写入数据的 rowkey 是分散的,不是大量连续的,往不同的 regionserver 的 region 上写入,这样集群负载也比较均衡。
例如使用手机号做 rowkey,手机号相对均衡,不是一直连续递增。

ROWKEY 保持队形

使用连续的用户 id 也可以,如订单表用户 id 递增相对稳定,写入更多的是用户订单的时候,假设此时 rowkey 设计为 mid++日期++订单号, 如:00000000000220180503_28123123435345
注意 rowkey 要注意保持队形,考虑到按字典序存储,你最好保持队形。这样当 scan 用户数据时不会出问题,以上的按用户 id,你应该使用 000000000002_20180503_28123123435345 而不是 2_20180503_28123123435345 如果你使用了后者,范围查找时如果指定 startKey 为2,endKey 为 2
会把 20、21、222 等等的都会查出来,前者则指定 startKey 为 000000000002 而 endKey 为000000000002__ 即可。