HBase的介绍
HBase的背景
- Hadoop仅适合存储大批量的数据,进行顺序化读写,并不支持随机的读取数据操作
HBase的特点
1)他是用java写的Nosql型数据库,基于HDFS,是一个支持高效随机读写能力的Nosql型数据库
2)HBASE支持三种查询方式:
1- 支持主键查询
2- 支持主键范围查询
3- 支持全表查询
3)他的本质是存储数据的容器,数据是存储在HDFS文件上的,不支持join,多行事务,和sql语句的查询,仅支持单行事务,存储格式为字节
4)可以通过横向拓展的,就像Hadoop集群一样
HBase表的特点
1)大:可存储海量的数据,存储十亿行数据,上百万列
2)面向列:数据是面向与列(列族)的形式的存储方案
3)稀疏性:在HBASE中的表存储数据,如如果一个字段为null,并不会 占用磁盘的空间,所以表结构可以非常稀疏
HBase和其他软件的对比
1)HBase和RDBMS:
1- HBASE是以表的形式存储数据,不支持join,仅支持单行事务,采用分布式存储,主要存储半结构化数据和结构化数据
2- RDBMS也是以表的形式存储,支持join和sql语句查询,支持多行事务,采用中心化存储,主要存储结构化数据
2)HBase和HDFS:
1- HBASE强依赖于HDFS,数据最终存储在HDFS中,支持高效的随机读写操作
2- HDFS是分布式的存储容器,适合于批量化的数据存储,不支持随机读写的能力
3)HBase和hive
1- HBase:基于Hadoop的软件, 是NoSQL存储容器, 延迟较低, 接入在线业务.
2- Hive:基于Hadoop的软件, 数仓分析工具, 延迟较高, 接入离线业务, 用于OLAP操作.
HBase的应用场景
- 存储海量的数据
- 表结构设计比较稀疏
- 需要高效的随机读写
HBASE的启动步骤
#先启动zookeeper集群
cd /export/server/zookeeper/bin
./zkServer.sh start
#查看进程状态
./zkServer.sh status
#再启动Hadoop集群
start-all.sh
#然后启动HBASE集群
start-hbase.sh
#进入hbase的命令行,查看运行状态
hbase shell
输入status
#web端查看
http://node1:16010/master-status
HBASE的数据模型
HBase数据模型的介绍
1)HBASE是采用表的方式存储数据的,数据也是通过表的形式组织在一起的,hbase可以组建多张表
2)行键(rowkey):类似于RDBMS中的主键,保证唯一非空
3)列名包括两部分
1- 列族:在一个表中可以构建多个列族,每个列族下可以有多个列,最多支持上百万个列(建表时列族越少越好)
2- 列限定符:也称为列名,一个列名必然属于一个列族,列名在建表的时候不需要指定
4)时间戳:每一个数据都有时间戳的概念,默认为添加数据的时间
5)版本号:是否需要保留每个数据的历史变更信息,以及保留多少个,默认是一个
6)一个单元格 = 行键 + 列族 + 列限定符 + 列值
HBase的相关操作
shell操作HBase
#查看hbase的命令使用
help ‘命令名’
#查看集群得状态信息
status
#查看hbase中有哪些表
list
#展示表结构信息
describe
#检查表是否存在, 适用于表量特别多的情况
exists
#检查表是否启用或禁用
is_enabled, is_disabled
#该命令可以改变表和列族的模式
alter
使用shell命令建表查询
#创建一张表user
create 'user', 'info', 'data'
#创建一张表user02,并指定版本号
create 'user02', {NAME => 'info01', VERSIONS => '3'}, {NAME => 'data01'}
#如何向表中添加数据
put 'user', 'rk001', 'info:name', 'zhangsna'
#向user表中插入信息, row key为rk001, 列族info中添加gender列标示符, 值为female
put 'user', 'rk001', 'info:gender', 'female'
--------------------------------------------------
#查询数据的操作
get 'user', 'rk001'
#查询info列族中的数据
get 'user', 'rk002', 'info'
#查看列族中的具体那个列名的信息
get 'user', 'rk002', 'info:name', 'info:age'
#查看列族中的具体那个列族的信息
get 'user', 'rk0001', 'info', 'data'
#查看表中rk001行键中是否有zhangsan的值
get 'user', 'rk001', {FILTER => "ValueFilter(=, 'binary:zhangsan')"}
--------------------------------------------------
#查询user表中的所有信息
scan 'user'
#FORMATTER => 'toString': 表示用于显示中文
scan 'user', {FORMATTER => 'toString'}
#limit: 表示显示前N条数据.
scan 'user', {LIMIT => 3, FORMATTER => 'toString'}
#列族查询: 查询user表中列族为info的信息.
scan 'user', {COLUMNS => 'info'}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 5}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 3}
----------------------------------------------
#指定多个列族与按照数据值模糊查询, 即: 查询user表中列族为info和data且列标示符中含有a字符的信息.
scan 'user', {COLUMNS => ['info', 'data'], FILTER => "QualifierFilter(=, 'substring:a')"}
#rowkey的范围值查询, 即: 查询user表中列族为info, rk的范围是[rk0001, rk0003)的数据
scan 'user', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'}
#指定rowkey模糊查询, 即: 查询user表中rowkey以rk字符开头的数据.
scan 'user', {FILTER => "PrefixFilter('rk')"}
#指定数据范围值查询, 即: 查询user表中指定范围的数据
scan 'user', {TIMERANGE => [1392368783980, 1392380169185]}
更新数据操作
#更新数据值, 注意: 更新操作同插入操作一模一样, 只不过有数据就更新, 没有数据就添加.
put 'user', 'rk0001', 'info:name', '张三'
#更新版本号, 即: 将user表的f1列族版本号改为5
alter 'user', NAME => 'info', VERSIONS => 5
删除操作
#删除一个列族
alter 'user', 'delete' => 'info'
#清空表数据
truncate 'user'
#首先需要先让该表为 disable 状态,再删除表
disable 'user'
drop 'user'
统计一张表有多少行数据
count 'user'
hbase的过滤操作
格式:
scan '表名', {FILTER => "过滤器(比较运算符, '比较器表达式')"}
过滤器的查询地址:
http://hbase.apache.org/2.2/devapidocs/index.html
HBase中常用的过滤器:
rowkey过滤器:
RowFilter
实现行键字符串的比较和过滤
PrefixFilter
rowkey前缀过滤器
列族过滤器:
FamilyFilter
列名过滤器:
QualifierFilter
列标示符过滤器, 只显示对应列名的数据
列值过滤器:
ValueFilter
值过滤器, 找到符合值条件的键值对
SingleColumnValueFilter
在指定的列族和列中进行比较的值过滤器
SingleColumnValueExcludeFilter
#在指定的列族和列中进行比较的值过滤器(排除匹配成功的值)
其他过滤器:
PageFilter
#用于实现分页查询的操作
比较运算符:
>, >=, <, <=, =, !=
比较器:
BinaryComparator //匹配完整字节数组
BinaryPrefixComparator //匹配字节数组前缀
NullComparator //匹配空值
SubstringComparator //模糊(包含)匹配子字符串
比较器表达式(比较器的使用方式):
BinaryComparator binary:值
BinaryPrefixComparator binaryprefix:值
NullComparator null
SubstringComparator substring:值
hbase的架构
整体架构
- hbase架构说明
1)HMaster的作用:(主节点)
1- 他是HBase集群的主节点
2- 管理多有的HRegionServer
3- 负责分配所有的Region
4- 负责Region的负载均衡
5- 负责维护和更新元数据
2)HRegionServer的作用:(从节点)
1- 负责接收和管理HMaster分配的Region
2- 负责和HMaster的通信(心跳机制)
3- 负责数据的读写操作
3)细节:
1- 1个HRegionServer是由1个HLog文件和多个Region组成
2- 一个Region是由多个Store组成,一个Region管理一个大的HFile的文件
3- 1个Store由多个StoreFile和1个MemStore(内存)组成
hbase的读取流程
①客户端发起请求,例如:get ‘user’,‘rk001’,‘info’, 通过该zookeeper连接到master
②获取到hbase:meta的存储原数据的regionserver(从节点)信息,返回给客户端
③客户端根据元数据的信息,连接需要存有读取信息的regionserver
④先从mestore中读取数据
⑤如果mestore中没有数据的话,再从blockcache中读取数据
⑥如果还是没有需要的数据就去hfile中读取
注:
读取顺序为: mestore(一级缓存)→blockcache(二级缓存)→hfile
上述的读取数据的方式为 并行的,例如每个RS节点中都有需要的数据 则进行并行读取
hbase的写入流程
①客户端发起请求,例如:put ‘user’。。。。
②通过连接zookeeper连接到HMaster,读取存储元数据表的RS信息
③通过读取到的元数据信息,连接到存储元数据表的RS,并获取存储,具体要被写入到那个RS中
④客户端把数据写入到HLog的文件中(预写日志文件,可以做故障恢复)
⑤客户端再把数据写入到Memstore文件中,如果这两个地方都写入成功则客户端认为数据写入成功
--------------------以上是客户端的写入操作-------------------------
--------------------以下是服务端的写入操作------------------------
⑥当Memstore中的数据达到一定的阈值(128M或者1小时),就会触发flush机制,将数据刷出到storefile中
⑦在数据被刷出到storefile中之前,可能会遇到 in-memory(内存合并)机制(这个机制是hbase2.0以后的新特性),默认是关闭的需要进行手动设置,他的目的是减少storefile文件的数量,让数据尽可能的晚的刷出到storefile文件中
⑧当storefile文件达到一定的阈值(3个或3个以上),就会触发compact机制,将他们合并到一个大的hfile文件中
⑨当hfile文件达到一定的阈值(最大10GB)后就会触发spilt机制,对一个大的hfile文件进行切割,获取到两个HFile文件,此时就会有两个新的Region了,旧的Region将会下线,产生两个新的Region将会被HMaster根据负载均衡机制,分配到指点的RS从节点中来维护
region和store的关系
- 说明
1)Region的解释:
1- 所谓的Region就是对HBase表的横向切分
2- 默认一张hbase表只有一个Region,当该表的总容量达到10GB时,将开启split机制,将该表的文件(也就是HFlie文件)一分为二
3- 后去我们通过创建预分区表的方式,直接指定HFlie的个数
2)Store的解释:
1- 所谓的store是对hbase的纵向(垂直)切分
2- 默认情况下,一个列族对应一个store
3- 列族在数设计得时候越少越好,因为一个列族应对应一个store,当列族过多的时候,可能出现多个列组分布在不同的RS(子节点)中存储,读写时影响效率
hbase的三大机制
flush机制
- 说明
1)目的:把Memstore中的数据刷出到storefile文件中
(阈值:128M-region级别, 1小时- regionserver级别)
2)hbase2.X以前:
1- 当Memstore达到阈值以后,会触发flush机制,该Memstore会被禁用掉(可读不可写),然后创建一个新的Memstore(可读可写)
2- 被禁用的Mestore中的数据写出到一个队列中
3- 队列中的一个Memstore完整的数据将对应一个storefile文件(即,一个Memstore对应一个storefile文件,容易导致storefile文件过多)
3)在hbase2.X以后:
1- 当Memstore达到一定的阈值后,会触发flush机制,该Memstore将会被禁用(可读不可写),然后创建一个新的Memstore(可读可写)
2- 旧的Memstore得数据会被放到一个消息队列中(pipeline),该队列采用segment(可以理解为索引)来记录数据,会尽可能晚的将Memstore刷出到storefile中,减少storefile文件的个数
注
1)上述所描述的就是hbase2.X的新特性,叫 in-memory(内存合并)他就是用pipeline对列中的Memstore数据进行合并的,默认该特性是被关闭的,需要手动设置)
2)合并有3中方式:
1- Basic(基础型):只对数据进行和并排序,不会删除重复的数据和过期的版本数据
2- Eager(饥渴型):对数据进行合并排序,也会删除重复的数据和过期的数据
3- Adaptive(适应型):满足条件下会自动启用,Eager,否则就Basic
compact机制
- 说明
1)目的:将多个storefile文件合并到一个大的hfile文件中
(阈值:storefile文件的个数达到3个或三个以上,又或者hbase集群刚启动的时候)
2)主要分为两个阶段:
1- minor:负责把多个storefile文件合并成一个大的storefile文件
2- major:负责把大的storefile文件和hfile文件做合并(阈值7天或者手动)
split机制
-说明
1)目的:对hfile文件进行切割,将其变成两个hfile文件,对应的region也会一分为二
阈值:最终:10GB
公式:min(region的平方 * 128MB, 10GB)
2)当启动spilt机制后,大的10GB文件hfile文件,会分为两个,这时也就会产生两个region,旧的hfile对应的region会被下线,新的两个region将会被master根据负载均衡被随机分配到指定的RS从节点进行管理
HRegionServer的上下线问题
- 说明
HMaster如何管理Regionserver的?
1)一个region只能被一个Regionserver管理
2)HMaster会根据记录的元数据,以及各个RS汇报的region信息,计算出那些Region被谁管理,那些Region还没有别分配
3)那些没有被分配的Region就会被HMaster根据负载均衡机制,找一个相对比较空闲的RS,给他分配一个装载任务,这样Region就会被RS管理了
--------------------------------------------
当Regionserver上线或者下线之后,做了那些事情?
1)其实就是ZK的发布和订阅功能,所有的RS启动后都会去ZK的RS节点下创建自己的临时节点
2)当某一个RS宕机之后,他的临时节点就会消失,从而被HMaster监听到
3)HMaster会将该RS管理得所有的Region,根据负责均衡机制分配给其他的RS进行管理
4)当RS重新启动后,还会去zk的rs节点下创建自己的临时节点,从而被HMaster监听到,此时HMaster还会从其他的RS从节点中转移一些Region来给刚启动的Region
HMaster的上下线问题
- 说明
1)所有的HMaster都要去ZK中去创建自己的临时节点
2)当hbase集群刚启动的时候,所有的HMaster都会抢占式的去ZK的master节点下,创建自己的临时节点,那个HMaster先创建成功,他就是Active
3)其他的HMaster就去backup-master 节点下创建自己的临时节点,他们的状态就是standby
4)所有的standbymaster的状态都会实时监听ZK的ACtive节点,如果发现宕机,立即抢占Active节点
BulkLoad批量装载
hive和hbase集成
- 说明
1)hive和hbase的数据都是存储在hdfs中的,为了不让数据重复存储而占用大量的磁盘空间,我们将hive和hbase进行集成
hbase表结构的设计
hbase表的名称空间
- 说明:hbase的名称空间类似于mysql的数据库名称,hbase的默认名称空间是default
#创建命名空间
create_namespace
#查看命名空间
list_namespace
#查看命名空间结构
describe_namespace
#删除命名空间(在没有表的情况下)
drop_namespasce
hbase表的列族的设计
1)列族的数量越少越好,减少中间I/O的开销
2)列族的名设计越小越好,防止占用空间
3)一个表中的列族一般设计不超过5个
hbase中的压缩
1)压缩比:
见上图
2)解压缩效率(解压速度和压缩速度):
见上图
-------------------------------------------
1)建表时如何指定压缩的格式
create '表名', {NAME => '列族名', COMPRESSION => 'GZ'}
2)修改已有的表压缩的格式
alter '表名', {NAME => '烈族名', COMPRESSION => 'GZ'}
hbase的预分区
- 说明
是指在初始化创建表的时候,提前预先设置多个region到hbase中,而多个region可以均匀的落在各个regionserver中,从而分担高并发的读写操作
#如何设计预分区
create '表名', '列族',SPLITS => ['10', '20', '30', '40']
create '表名', '列族', {NUMREGIONS => 10, SPLITALGO => 'HexStringSplit' }
hbase中rowkey的设计原则
1)尽量不要使用递增的时序数据
2)避免rowkey和列的长度过大,否则会占用较大的空间
3)使用了Long等类型比String类型更加节省空间
4)保证rowkey的唯一性
5)避免出现热点数据,也就是数据集中在一个region中(可采用对行键进行反转和加盐的策略和哈希策略)
hbase的协处理器
observer的图解
endpoint的图解
- 协处理器主要分为两类:
1)observer
1-类似于监听者的作用,当put到Memstore中数据时,observer协处理器会有hook(钩子)钩取操作命令,到HLog中。
2)endpoint
1-endpoint类似于函数的这类协处理器,他会将每个storefile中的数据在服务端先进行处理合并,减少客户端拉取数据的量,从而提高效率
Phoenix的介绍
- Phoenix的快速入门
Phoenix可以通过SQL的方式来操作hbase的工具,只不过Phoenix针对hbase做了更深的优化操作,底层大量利用了hbase的协处理器
#启动Phoenix的命令
cd /export/server/Phoenix/bin
sqlline.py node1:2181
#表的创建
create table "order_dtl_01" (
"id" varchar primary key,
"c1"."status" varchar ,
"c1".money integer ,
c1."pay_way" integer ,
c1.user_id varchar,
c1.operation varchar,
c1.category varchar
);
#表的删除
delete 表名
#表的查看
!table
#表结构的信息
!desc 表名
#表数据的的添加和更新
upsert into 表名(列族.列名1, 列族.列名2。。。。)values (值1, 值2,值3, 。。。)
#数据的删除
delete
#分页查询
select * from 表 limit 每页显示多少条 offset 从第几条开始查询
- 手动分区及指定压缩格式(默认情况下只有一个分区)
create table [if not exists] 表名 (
rowkey名称 数据类型 primary key,
列族名.列名1 数据类型,
列族名.列名2 数据类型,
列族名.列名3 数据类型,
列族名.列名4 数据类型,
) compression=‘GZ’ //压缩方式
split on ('10', '20', '30', '40') //手动指定分区方案
- 哈希加盐(自动分区)
create table [if not exists] 表名 (
rowkey名称 数据类型 primary key,
列族名.列名1 数据类型 ,
列族名.列名2 数据类型 ,
列族名.列名3 数据类型 ,
列族名.列名4 数据类型
.....
)
compression='GZ', //压缩方式
salt_buckets=10 //加盐预分区 (hash + rowkey自动加盐)
;
Phoenix的视图操作
- 默认情况下Phoenix中只展示自己创建的表,如果hbase的表是通过hbase自己构建的,那么在Phoenix中是无法看到的如果想看到需要通过Phoenix创建视图进行对hbase中的表进行映射
create view "名称空间"."Hbase对应的表的表名"(
key varchar primary key,
"列族"."列名" 类型,
......
)[default_column_family='列族名'];
注意事项:
1. 视图的名称一定要与 需要建立视图的Hbase的 表名一致.
2. key的名称可以是任意的, 但是必须添加 primary key
3. 普通的列, 需要和 hbase的对应表的列保持一致.
Phoenix的二级索引
- 通过Phoenix可以非常方便的创建二级索引,这些二级索引可以加快查询速度
1)索引的分类
1- 全局索引:会创建索引表,原表有几个region,索引表就有几个region
如果查询列有索引列的出现,则全局索引无效,上述情况可以通过Hint让全局索引有效
create index 索引名 on 表名(列1, 列2.。。)
drop index 索引名 on 表名
2- 本地索引:不会创建索引表,而是在原表的字段上直接存储,如果有查询列有非索引字段,则本地索也有效, 如果使用的是哈希加盐分区表,则本地索引部分功能无效
create local index 索引名 on 表名(列1,列2 。。。)
3- 覆盖索引
4- 函数索引
这两个都不能单独使用,必须结合全局索引和本地索引一起使用,不能创建索引表,而是在字段上直接存储,不需要手动删除当删除本地索引或者全局索引的时候,他们对应的覆盖索引和函数索引也会同步被删除