一、HBase简介
1、Hbase是什么?
Hbase是分布式存储海量数据的Nosql数据库
2、Hbase的应用场景: 实时
3、数据模型
1、Table: 数据存储形式
2、Region: table的一个分段,region保存在regionserver上面
3、Store: store的个数与列簇的个数一致
4、rowkey: hbase的数据的主键。
数据在hbase中是有序的,按照rowkey的字典序进行排序
5、列簇: hbase的表结构的一部分[相当于mysql的字段]
6、列限定符: hbase数据的一部分
7、Column: 列簇:列限定符
8、Cell: rowkey+列簇+列限定符+时间戳
9、Namespace: 命名空间,相当于mysql的库
4、架构
1、Master
职责:
1、负责监控Regionserver,一旦regionserver宕机,会迁移数据到其他活着的regionserver上面
2、负责表结构的变更
2、RegionServer
职责:
1、负责数据的操作[增删改查]
2、负责region的split、compact
Region: 表的一个分段
Store: store的个数与列簇的个数一致
memstore: 是一块内存区域,数据在写入hbase的时候是写入memstore中,memstore达到一定的阈值之后会进行flush,每次flush都会生成一个storeFile
storeFile: memstore flush生成
storeFile最终是以Hfile这种文件格式保存在HDFS
HLOG: 每个regionserver只有一个HLOG,数据在写入memstore之前会先写入HLOG,当memstore进行flush的时候,HLOG会删除预写日志中该memstore的数据
3、zookeeper: 保存元数据的位置,master监听regionserver也是借助zookeeper
二、Hbase安装以及shell使用
1、Namespace相关
1、创建Namespace: create_namespace '命名空间名称'
2、删除Namespace: drop_namespace '命名空间名称'
删除命名空间的时候,必须先删除命名空间下所有表
3、查看命名空间下所有表: list_namespace_tables '命名空间名称'
4、查看所有的命名空间: list_namespace
2、Table相关
1、创建表: create '表名','列簇名1',...
2、删除表:
1、禁用表: disable '表名'
2、删除表: drop '表名'
3、查看所有表: list
4、查看表的详情信息: describe '表名'
5、创建表的时候指定VERSION:
create '表名',{NAME=>'列簇名',VERSIONS=>'版本数'}
3、数据相关
1、插入数据: put '表名',rowkey,'列簇:列限定符','值'
2、查看数据
1、根据rowkey查询数据
1、查询整行数据:get '表名',rowkey
2、查询某个列簇的数据: get '表名',rowkey,'列簇'
3、查询某个列的数据: get '表名',rowkey,'列簇:列限定符'
2、扫描
1、查询整表数据: scan '表名'
2、查询某个列簇的数据: scan '表名',{COLUMNS=>'列簇'}
3、查询某个列的数据: scan '表名',{COLUMNS=>'列簇:列限定符'}
4、查询某几个版本的数据: scan '表名',{COLUMNS=>'列簇:列限定符',VERSIONS=>'版本数'}
3、清空表数据: truncate '表名'
4、统计表条数: count '表名'
三、原理
1、写入流程
1、client向zookeeper发起获取元数据位置的请求
2、zookeeper向client返回元数据所处的位置信息
3、client向元数据所在的regionserver发起获取元数据的请求
4、元数据所在的regionserver给client返回元数据,client会缓存元数据
5、client根据元数据信息知道当前数据应该插入到哪个region,region处于哪个regionserver
6、client向数据所在regionserver发起写入请求
7、首先将数据写入HLOG中
8、HLOG写入成功之后,再将数据写入memstore中
9、向client返回写入完成信息
2、flush触发条件
flush的时候是对整个region进行flush
1、region中某一个memstore的大小达到128M的时候会进行flush
2、当处于写高峰的时候,第一个触发条件可以适当延迟,延迟到region中所有的memstore的大小达到4*128M的时候会阻塞client的写入,优先flush
3、regionserver中所有的region的所有的memstore的大小达到java_heap * hbase.regionserver.global.memstore.size * hbase.regionserver.global.memstore.size.lower.limit的时候会进行flush
4、当处于写高峰的时候,第三个触发条件可以适当延迟,延迟到regionserver中所有的memstore的大小达到java_heap * hbase.regionserver.global.memstore.size,会阻塞client的写入,优先flush
4、当预写日志的个数达到32,会触发flush
5、当某个region中memstore的最后一次flush的时间与当前时间相比达到一个小时,会进行flush
6、手动flush: flush '表名'
3、读流程
1、client向zookeeper发起获取元数据位置的请求
2、zookeeper向client返回元数据所处的位置信息
3、client向元数据所在的regionserver发起获取元数据的请求
4、元数据所在的regionserver给client返回元数据,client会缓存元数据
5、client根据元数据信息知道当前数据应该插入到哪个region,region处于哪个regionserver
6、client向数据所在regionserver发起读取请求
7、首先从block cache中读取数据
8、然后从memstore中读取数据
9、从storeFile中读取数据
store中storeFile个数可能比较多,如何快速找到数据处于哪个storeFile?
1、通过布隆过滤器,判断数据可能存在哪些storeFile
布隆过滤器特点: 如果判断存在,则不一定存在,如果判断不存在,则一定不存在
2、通过HFile这种文件格式中的数据索引找到数据所在的位置
HFile文件: Hfile中包含数据信息,数据的索引信息,数据元数据信息
10、将数据返回给client
4、compact
原因: 当memstore flush会生成一个storeFile文件,随着时间的流逝,storeFIle文件会越来越多,会影响查询性能,所以hbase提供文件的合并机制
1、minor compact:
触发条件: 当小文件[小于128M]数据达到3个的时候会触发
合并过程: 只是单纯的合并文件的内存,不会清除过期数据或者无效数据
合并结果: 将小文件合并成大文件
2、major compact:
触发条件: 7天一次
合并过程: 在合并的过程中,会清除清除过期数据或者无效数据
合并结果: 将store中是所有文件合并成一个文件
5、split
原因: 当数据写入region,时间过长之后,region越来越大,后续请求大部分可能都会落在该region上,导致数据的读写请求负载不均衡
0.94版本之前: 当region中某个store的大小达到10G,该region就会进行split
0.9-2.0版本: 会根据region所属表在当前regionserver上有几个region[N]
N==0 || N>100 ? 10G : Min(10G,2* 128M *N^3)
2.0版本之后: 会根据region所属表在当前regionserver上有几个region[N]
N==1 ? 2*128M : 10G
四、Hbase优化
1、预分区[在创建表的的时候多创建几个region]:
原因: 默认情况下,创建表的时候只有一个region,前期所有的请求都会落在这一个region上,会对region所在的regionserver造成请求压力
1、shell
1、create '表名','列簇名',SPLITS=>['rowkey1','rowkey2',..]
create 'person','f1',SPLITS=>['10','11']
此时会创建三个region。
第一个region的起始rowkey是'',结束rowkey是'10'
第二个region的起始rowkey是'10',结束rowkey是'11'
第三个region的起始rowkey是'11',结束rowkey是''
2、create '表名','列簇名',SPLITS_FILE=>'文件路径'
2、api
admin.createTable(TableDescribetor,splitKeys)
2、rowkey的设计
rowkey的原则:
1、长度原则: rowkey的长度不要太长
rowkey太长会占用过多的磁盘空间
rowkey过长会导致client端缓存的元数据会比较少
2、唯一原则: 每条数据的rowkey必须唯一
3、hash原则: 让数据不会产生倾斜
热点问题的解决方案:
1、字符串的反转
2、hash
3、加盐-加随机数
3、内存优化:hbase分配的内存不要太多,16-40G比较合适
4、基础优化
1、让HDFS能够追加
2、调整监听client的PRC的个数
3、超时时间的配置
4、flush的时候10G配置的调整
5、flush、compact、split的参数配置
6、最大文件打开数
7、客户端缓存
8、写入效率-压缩
五、phoenix
1、phoenix shell操作
1、查看所有表: !tables
2、创建表:
1、Hbase中没有表[会在hbase中同步创建表]
create table 表名(
字段名 字段类型 primary key,
字段名 字段类型,
字段名 字段类型,
....
[constraint 主键名称 on(字段1,字段2)] //组合主键,是上面没有指定primary key的时候使用
)COLUMN_ENCODED_BYTES=0
COLUMN_ENCODED_BYTES=0:代表不对字段进行编码
在创建表的时候,会同步的在hbase中创建表
表名会自动的转成大写,如果想要保持小写,需要通过""括起来
2、Hase中有表[在phoenix中建表建立映射]
create table 表名(
字段名 字段类型 primary key,
"列簇"."字段名" 字段类型, //如果hbase中列簇与列限定符为小写,需要用""括起来
字段名 字段类型,
)COLUMN_ENCODED_BYTES=0
3、创建视图[视图只能查看数据,不能修改/删除/插入数据]
create view 视图名(
字段名 字段类型 primary key,
"列簇"."字段名" 字段类型, //如果hbase中列簇与列限定符为小写,需要用""括起来
字段名 字段类型,
)COLUMN_ENCODED_BYTES=0
4、删除表与视图
1、删除表: drop table 表名
删除表的时候会同步删除hbase的表
2、删除视图: drop view 视图名
删除视图的时候不会删除hbase的表
5、插入数据: upsert into 表名 values(值,...)
6、查询数据: select * from 表名
2、jdbc
3、协处理器
用途: 在向hbase表插入/删除/查询之前或者之后自动干什么事情
1、编程class实现RegionObserver、RegionCoprocessor
2、重写方法:
@Override
public Optional<RegionObserver> getRegionObserver() {
return Optional.of(this);
}
3、重新动作方法[在put/get/scan/delete之前[prePut/Get/Delete]或者put/get/scan/delete之后做操作[postPut/Get/Delete]]
4、打包上传HDFS
5、禁用表
6、修改表,给表加载协处理器
alter '表名', METHOD => 'table_att', 'Coprocessor'=>'jar所处HDFS路径| 协处理器所在的全类名|优先级|参数'
7、启动表: enable
8、通过动作[put/get/scan/delete]查看协处理器是否正常
4、二级索引
二级索引的实现主要是通过协处理器完成
原因:
hbase中查询速度快主要是因为可以用待查询数据的rowkey通过meta元数据找到rowkey处于哪个region,
region处于regionserver.但是如果想要根据value值查询的是,没办法通过meta元数据找到数据处于哪个region,哪个regionserver,所以只能全部扫描,效率低
1、全局二级索引
1、原理: 将建立索引的字段的值与原来的rowkey组成新的rowkey,将include中包含的字段名作为列限定符,将include中包含的字段值作为新值,将新rowkey、列限定符、新值放入新创建的索引表中。
查询的时候优先查询索引表,如果索引表不满足,则继续查找原表[全部扫描]
2、创建: create index 索引名 on 命名空间名称.表名(字段名,..) [include(字段名,..)]
//如果表是映射表,则字段名必须用: 列簇名.列名
3、删除: drop index 索引名 on 命名空间名称.表名
2、本地二级索引
1、原理:
在原表中插入数据,插入的数据rowkey=__索引字段值_.._原来的rowkey
后续根据字段值查询的时候,首先查新rowkey,得到原来的rowkey,再通过原来的rowkey查询原始数据
2、创建: create local index 索引名 on 命名空间名称.表名(字段名,..)
3、删除: drop index 索引名 on 命名空间名称.表名
5、hbase与hive整合
1、内部表[在hive建表的时候,会同步在hbase创建表,如果hbase的表已经存在,则报错]
CREATE TABLE hive_hbase_emp_table(
字段名 字段类型,
....)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,列簇名:列名,...")
TBLPROPERTIES ("hbase.table.name" = "hbase表名");
2、外部表[在hive建表的时候,不会同步在hbase创建表,如果hbase的表不存在,则报错]
CREATE EXTERNAL TABLE hive_hbase_emp_table(
字段名 字段类型,
....)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,列簇名:列名,...")
TBLPROPERTIES ("hbase.table.name" = "hbase表名");