初识 HBase

Posted by danner on May 8, 2019

介绍

  • Google BigTable 的开源实现
  • 分布式 NoSQL数据库
  • 存储
  • 基于 HDFSZookeeper

适用场景

NoSQL = Not Only SQL

  • 适用
    • 存储格式: 半结构化数据, 结构化数据存储, Key-Value存储
    • 数据版本: 固定集合(多版本) , 定时删除(TTL
    • 更新: 列族结构经常调整
    • Pattern重写轻读
  • 不适用 - SQL 擅长的 NoSQL 都不擅长
    • 事务
    • 复杂查询 Operator Join, Union, Group By
    • 索引支持:
    • Pattern: 高并发随机

特点

  • 生产环境检验
    • 理论与实践: 理论(Google BigTable) 经过生产环境检验
    • 社区: 社区成熟, 丰富工具支持
  • 高效
    • 读写 Pattern: 将随机读写转化为顺序读写, 适应高并发写入
    • 数据存储格式: 列存储节省空间
    • 数据倾斜: 数据均衡效果好
  • 分布式特性
    • CAP:一致性, 可用性, 分区容忍性
    • 扩展性: 利用 HDFS线性扩展
    • 高可用: 利用 HDFSZookeeper

架构

  • Zookeeper
    • HMaster HA (机制类似 Hadoop)
    • 节点状态监控
    • 储存元数据
  • HMaster
    • client 的 DDL 操作
    • 管理集群的负载均衡, 调整 HRegion 分布
  • Region Server
    • client 的 DML 操作
    • HRegion 管理
    • ZK 汇报节点状态
    • 数据路由、读写和持久化
  • HRegion:管理表数据,包含 Store - 表有几个列簇就有几个 Store
  • Store:表数据
    • MemStore:一个列簇数据在内存中存储有且仅有一个,超过阈值落盘成StoreFile
    • StoreaFile:一个列簇数据在磁盘中存储,看数据量容量可能会有多个;也叫做 HFile 存储在 HDFS 上的文件

数据模型

HBase 中的数据如下展示

一条数据的构成

  • RowKey:每条数据的主键,不能重复,设计表结构时需要重点考虑字典排序
  • Column Family :列簇简称 CF,包含一或多列,存储时依据列簇数将表分割成多个 Store
  • Column:列名
  • Version:时间戳类型为 Long
  • Value:以 (rowkey + column Family + column) 为key 的值

在设计表时, CF 个数最好不超过3个

一条数据的结构清楚了,下面来看看一张表的数据模型

逻辑视图

依据 Region 划分, rowkey 按字典排序划分为不同 Region,相当于是分表。上图row1-row4 划到 region 1;row5-row6 划到region 2;row7-row8 划到 region 3。当某个region 的数据不断增大超过阈值则会被再次分割(HMaster 负责)。

物理视图

依据列簇(CF) 划分表数据的物理存储,上图左右两侧各表示一个列簇(不同颜色是不同region),同个region下相同的列簇就会存储在一块( Store)。

多版本

HBase 中有多版本的概念即同 rowkey下的某列存在多个多个值,上图中 row1-SkuSum 值。在说明多版本之前先说一个机制:HBase 里的修改并不是直接覆盖,而是新增一条数据,只是 TimeStamp 不同,此时存在两条数;类似的删除数据也不是立即删除而是对该数据打上 delete 标签。由于这个机制的存在,数据自然存在多版本(TimeStamp)。在读取数据时(若没有指定版本),会读取所有数据然后选取最新数据返回。由此可见 ,HBase重写轻读:只管写,但读取时缺要做判断。

update、delete 的数据在大合并才真正执行,但生产中应避免打合并,GC 有可能会导致HBase 请求卡顿。

实战

有理论基础后,我们操作 HBase 来验证下上面的知识。

hbase shell 进行交互界面,

  • ctrl+back 可以在交互界面删除
  • help 列出所有命令帮助
  • help 'cmd' 列出对应 cmd 的帮助

创建表

# 先创建命名空间,类似库的概念
hbase(main):068:0> create_namespace 'rz'
0 row(s) in 0.1020 seconds
# 在 rz 下创建表 orderinfo,表有两个列簇 SKU ORDER
# create 'ns1:t1', 'f1'
hbase(main):069:0> create 'rz:orderinfo','SKU','ORDER'
0 row(s) in 2.4890 seconds

=> Hbase::Table - rz:orderinfo
hbase(main):001:0> describe 'rz:orderinfo'
Table rz:orderinfo is ENABLED      # table 使能
rz:orderinfo                       # 表名                                                                                          
COLUMN FAMILIES DESCRIPTION                                                               # ORDER 列簇信息   VERSIONS  默认为1,只能获取1个版本                                   
{NAME => 'ORDER', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'N
ONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0
'}                                                                                       # SKU 列簇信息                                              
{NAME => 'SKU', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NON
E', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s) in 0.3260 seconds

添加数据

# put 'ns1:t1', 'r1', 'c1', 'value'
hbase(main):001:0>  put 'rz:orderinfo','row1','SKU:SKUName','apple'
0 row(s) in 0.3390 seconds

hbase(main):002:0>  put 'rz:orderinfo','row2','SKU:SKUName','banana'
0 row(s) in 0.0170 seconds

hbase(main):003:0>  put 'rz:orderinfo','row3','SKU:SKUName','orange'
0 row(s) in 0.0160 seconds

查看数据

hbase(main):004:0> scan 'rz:orderinfo'
ROW                     COLUMN+CELL                                                                                         
 row1                   column=SKU:SKUName, timestamp=1574696800783, value=apple                                            
 row2                   column=SKU:SKUName, timestamp=1574696805573, value=banana                                           
 row3                   column=SKU:SKUName, timestamp=1574696810623, value=orange                                           
3 row(s) in 0.0750 seconds
# 单条数据
hbase(main):005:0> get 'rz:orderinfo','row3'
COLUMN                             CELL                                                                                                
 SKU:SKUName                       timestamp=1574696810623, value=orange                                                               
1 row(s) in 0.0320 seconds

多版本

# 每个数据获取2个版本
hbase(main):015:0> scan 'rz:orderinfo', {RAW => true, VERSIONS => 2}
ROW                      COLUMN+CELL                                                                                         
row1                    column=SKU:SKUName, timestamp=1574696800783, value=apple 
# 存在两个版本,时间戳不一样
row2                    column=SKU:SKUName, timestamp=1574697023615, value=banana02       row2                    column=SKU:SKUName, timestamp=1574696805573, value=banana         row3                    column=SKU:SKUName, timestamp=1574696810623, value=orange                                           
3 row(s) in 0.0130 seconds
# get 多版本需要列簇支持多版本,但默认创建表是不支持
# VERSIONS => '3' 最多存储三个版本
hbase(main):027:0> alter 'rz:orderinfo',{NAME => 'SKU', VERSIONS => '3'}
Updating all regions with the new schema...
0/1 regions updated.
1/1 regions updated.
Done.
0 row(s) in 3.0100 seconds

hbase(main):028:0> describe 'rz:orderinfo'
Table rz:orderinfo is ENABLED                                                             rz:orderinfo                                                                                                                           
COLUMN FAMILIES DESCRIPTION                                                               {NAME => 'ORDER', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'N
ONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0
'}                                                                                       # VERSIONS => '3' 已修改                                              
{NAME => 'SKU', BLOOMFILTER => 'ROW', VERSIONS => '3', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NON
E', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s) in 0.0280 seconds

hbase(main):031:0>  put 'rz:orderinfo','row2','SKU:SKUName','banana03'
0 row(s) in 0.0130 seconds

hbase(main):032:0> get 'rz:orderinfo','row2',{COLUMN=>'SKU:SKUName',VERSIONS=>4}
COLUMN                             CELL                                                                                                
SKU:SKUName                       timestamp=1574698344934, value=banana03               SKU:SKUName                       timestamp=1574697023615, value=banana02                                                             
2 row(s) in 0.0100 seconds

删除

# 删除数据
hbase(main):033:0> delete 'rz:orderinfo','row3'
0 row(s) in 0.0330 seconds

hbase(main):034:0> scan 'rz:orderinfo', {RAW => true, VERSIONS => 2}
ROW                      COLUMN+CELL                                                                                         
row1                    column=SKU:SKUName, timestamp=1574696800783, value=apple         row2                    column=SKU:SKUName, timestamp=1574698344934, value=banana03     row2                    column=SKU:SKUName, timestamp=1574697023615, value=banana02     
# 已被标识删除
row3                    column=ORDER:, timestamp=1574698545510, type=DeleteFamily       row3                    column=SKU:, timestamp=1574698545510, type=DeleteFamily         row3                    column=SKU:SKUName, timestamp=1574696810623, value=orange                                           
3 row(s) in 0.0170 seconds

# 删除表
hbase(main):035:0> drop  'rz:orderinfo'

ERROR: Table rz:orderinfo is enabled. Disable it first.
# 提示先 disbale 表

hbase(main):036:0> disable 'rz:orderinfo'
0 row(s) in 2.2710 seconds

hbase(main):038:0> describe 'rz:orderinfo'
Table rz:orderinfo is DISABLED        #                                                                                                 
rz:orderinfo                                                                             
...
hbase(main):039:0> drop  'rz:orderinfo'
0 row(s) in 1.2550 seconds

参考资料

若泽数据@J哥Blog