一、Hbase的概述
1.1 Hbase的简介
1)简要介绍
1. Hbase是一个Hadoop 数据库
2. 是一个非关系型(NoSql:Not Only SQL)的、分布式的、具有良好的扩展性、面向列式存储的数据库。
3. 开发灵感来源于Google的Bigtable论文,java语言编写,并且开源。
2)特性
- 强一致性读/写:具有一致性读和写的功能,适合统计分析聚合类型的任务.
- 自动分片:hbase的表对应的region会根据大小自动拆分,并重写分布
- 自动 RegionServer故障转移
- Hbase的存储是基于HDFS的
- hbase可以和Mapreduce进行整合,从而进行数据分析
- Hbase还提供了java语言的客户端接口
- Thrift/REST API:Hbase也提供了非java语言的连接操作
- Hbase提供了块缓存和布隆过滤器等机制来提高查询效率等
3)何时选择Hbas
1. 当数据量特别大的时候,
2. 集群节点数多于10个的情况下。
3. 以及不需要具有事务、高级查询语言等功能的情况下。
1.2 Hbase的表模型(重点)
1.2.1 关系型数据库的表模型
1. 表模型是面向行式存储的。也就是每一条记录的数据都是紧凑的挨着的。
2. 优点:
-- 用户在插入数据时,效率特别高,只是追加操作。
-- 在查询操作时,比如select * 时效率是非常高的
-- 结构清晰,每一行的列的数量是固定的
-- 支持ACID事务
3. 缺点:
-- 一旦数据表中存储数据后,修改表结构变得特别困难。
-- 如果我们想扩展字段时,会对表结构产生影响。
-- 即使某一行中的某个字段没有赋值,也要使用null填充
-- 一旦涉及到多张表,因为数据表存在着复杂的关系,管理非常不方便。 比如外键约束
-- 一旦面对海量数据的处理时,读写性能特别差,尤其在高并发这一块。
1.2.2 Hbase的表模型(重点)
1、 hbase是面向列(colum family:列簇,列族)式存储的。
2. 定义表的时候不需要指定列名,列类型。只需要指定列族名即可
3. 数据实际上是按照key:value形式存储的,一个kv对通常称之为一个Cell(单元格)
4. 每个kv对后都有一个版本号。版本号是一个时间戳。一个K可以有多个版本
5. 为了方便管理多个KV对,引入了列族的概念。
-- 一个列族对应至少一个文件
-- 列族之间一定是不同的文件
6. 又为了区分KV是不同的事物的,引入了rowkey的概念。 因此rowkey必须具有唯一性
7. 为了管理表的数据,引入了region的概念。一个region对应一张表,或者是一张表的一部分。
region是由rowkey的范围来表示的。
如果一张表只有一个region:
region的rowkey的偏移量:startKey没有最小值,endKey也没有最大值。
8. Hbase的中的所有数据,都是byte[]类型。没有其他类型
9. hbase会在内存里进行排序:
查询时:先按照rowkey排序,然后是列族名排序,再按照key进行排序
实际上插入数据时: 先按照rowkey进行排序,再按照key进行排序 都是字典排序规则
1.3 Hbase的体系架构(重点)
1. Client:hbase的客户端
- hbase提供了客户端使用的API接口
- API里还维护了一个缓存机制,用于加快客户端访问的效率,比如缓存查询过的region的地址
2. Zookeeper
- 维护hbase的高可用,保证只有一个活跃的Hmaster,其他的为backup
- 维护着regionserver的动态上下线感知
- 维护着所有的region地址以及部分元数据
3. Hmaster
- hmaster主要管理着region的负载均衡
(1) 表的第一个region分配的位置
(2) region过大后,进行切分后,形成的新region的重新分配
(3) regionserver宕机后的region的重新分配
- hdfs上的垃圾回收
- 处理新的schama的维护(namespace的创建和删除等)
4. RegionServer
- 主要就是管理本节点上的所有region(包括region的切分)。
- 处理客户端的读写请求
- 负责hlog和storefile的读和写
5. Region
- 实际上就是表,或者是表的一部分。 是Hbase的表的存储单元
- 本质:在hdfs上是目录
6. store
- 一个列族对应一个store
- 本质:在是region目录下的子目录。
7. memstore
- 一个store 对应一个memstore(写缓存),默认大小是128M.
8. Hfile/StoreFile
- 当memstore达到阈值(128M,1小时,或者是内存的40%)就会被flush出来,形成一个storefile。以hfile存储格式存储到HDFS上。
9. hlog:
- 一个regionserver上维护着一个hlog文件。以WAL(write ahead log)格式记录着客户端的操作,防止宕机后丢失数据,然后可以重演一次,以便找回数据。
二、Hbase的安装
2.1 单机模式的简要说明(了解)
就是在一台节点上,解压,配置环境变量,启动一个hmaster服务,没有regionserver服务项,使用本地的文件系统存储数据。
2.2 伪分布式的搭建(了解)
伪分布式,指的是除了有hmaster外,只有一个regionserver服务项。存储的文件系统可以是本地文件系统,也可以使用hdfs。
2.3 完全分布式的搭建(重点)
2.3.1 简要说明
完全分布式,指的就是除了hmaster守护进程外,有多个regionserver守护进程,并且每一个regionserver守护进程独占一个机器节点。使用的文件系统是HDFS。
布局如下:
qianfeng01: hmaster regionserver
qianfeng02: hmaster regionserver
qianfeng03: regionserver
环境说明:
必须配置好集群的免密登录认证
必须配置时间同步。保证集群节点的时间差不能超过30秒,否则regionserver启动失败
2.3.2 搭建步骤
步骤1): 上传、解压、配置环境变量 、重导生效
[root@qianfeng01 ~]# tar -zxvf hbase-1.2.1-bin.tar.gz -C /usr/local/
[root@qianfeng01 ~]# cd /usr/local/
[root@qianfeng01 local]# mv hbase-1.2.1/ hbase
[root@qianfeng01 local]# vim /etc/profile
.......省略.......
#hbase environment
export HBASE_HOME=/usr/local/hbase
export PATH=$HBASE_HOME/bin:$PATH
[root@qianfeng01 local]# source /etc/profile
步骤2):配置hbase-env.sh环境脚本
[root@qianfeng01 local]# vi $HBASE_HOME/conf/hbase-env.sh
#找到下面内容,解开注释,添加具体路径
# The java implementation to use. Java 1.7+ required.
export JAVA_HOME=/usr/local/jdk
# Tell HBase whether it should manage it's own instance of Zookeeper or not.
export HBASE_MANAGES_ZK=false #禁止内置zookeeper
步骤3):配置hbase-site.xml文件
<configuration>
<!-- 指定hbase在HDFS上存储的路径 -->
<property>
<name>hbase.rootdir</name>
<value>hdfs://qianfeng01:8020/hbase</value>
</property>
<!-- 指定hbase是分布式的 -->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<!-- 指定zk的地址,多个用“,”分割 -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>qianfeng01:2181,qianfeng02:2181,qianfeng03:2181</value>
</property>
<!--将属性hbase.unsafe.stream.capability.enforce 改为true -->
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>true</value>
</property>
<!-- 取消内存检查 -->
<property>
<name>hbase.table.sanity.checks</name>
<value>false</value>
</property>
</configuration>
步骤4):配置regionservers文件,添加regionserver所在机器的host
[root@qianfeng01 local]# vi $HBASE_HOME/conf/regionservers
删除localhost
添加:
qianfeng01
qianfeng02
qianfeng03
步骤5):配置备份hmaster: 创建backup-masters文件
[root@qianfeng01 local]# cd $HBASE_HOME/conf/
[root@qianfeng01 conf]# echo "qianfeng02">> backup-masters
步骤6): 将hadoop的core-site.xml和hdfs-site.xml拷贝到hbase的conf目录下
[root@qianfeng01 conf]#
cp $HADOOP_HOME/etc/hadoop/{
core-site.xml,hdfs-site.xml} $HBASE_HOME/conf/
步骤7):同步到其他节点上
[root@qianfeng01 local]# scp -r /usr/local/hbase qianfeng02:/usr/local
[root@qianfeng01 local]# scp -r /usr/local/hbase qianfeng03:/usr/local
[root@qianfeng01 local]# scp /etc/profile qianfeng02:/etc/
[root@qianfeng01 local]# scp /etc/profile qianfeng03:/etc/
注意:
重新引导一下各个节点的环境变量配置情况
2.3.3 启动集群
启动顺序如下:
第一步:必须先启动hdfs和zookeeper
[root@qianfeng01 ~]# zkServer.sh start
[root@qianfeng02 ~]# zkServer.sh start
[root@qianfeng03 ~]# zkServer.sh start
别忘记:zkServer.sh status查看状态
[root@qianfeng01 ~]# start-dfs.sh
第二步:启动hbase的守护进程
[root@qianfeng01 ~]# start-hbase.sh
第三步:检查相关进程
方式1: jps
方式2: webui ---> qianfeng01:16010
2.3.4 客户端连接集群
1)hbase本身自己就提供了一个命令行连接工具
[root@qianfeng01 ~]# hbase shell
2)可以使用java语言调用API接口连接
2.4 Hbase集群的扩展和退役(了解)
2.4.1 扩展节点
1)原理说明
regionserver会主动向zookeeper的某一个节点/hbase/rs下注册一个临时节点, 而master一直在监听这个/hbase/rs, 如果突然多了一个临时节点,zookeeper会通知master,从而master可以进行相关任务的分配。
2)具体操作
参考文档
2.4.2 退役节点
1)原理说明
master一直在监听zookeeper上的这个/hbase/rs, 如果突然少了一个临时节点,zookeeper会通知master,从而master可以进行相关任务的分配。
2)具体操作
参考文档
三、Hbase的shell(熟悉)
hbase(main): > help 查看所有的命令组及其命令 名称
hbase(main): > help 'COMMAND GROUPNAME' 查看命令组里的命令用法
hbase(main): > help 'COMMAND' 查看指定的命令用法
3.1 namespace的DDL
1、列出命名空间: list_namespace
2、创建命名空间: create_namespace
3、描述命名空间: describe_namesapce
4、修改命名空间的属性: alter_namespace
5、删除命名空间:drop_namesapce
3.2 table的DDL
表结构的创建:create
表结构的查看:list、list_namespace_tables、describe
表结构的修改:alter
指的是对列族的增加、或者是列族属性的修改
删除指的就是删除列族。
表结构的删除:disable、disable_all、drop、drop_all
3.3. table的CRUD
表数据的增加:put
表数据的查看:scan、get
表数据的删除:delete,truncate
四、hbase的API(重点)
4.1 namespace的DDL
参考代码、视频、文档
4.2 table的DDL
参考代码、视频、文档
4.3 table的CRUD(重点)
参考代码、视频、文档
4.4 Hbase的Filter(重点)
4.4.1 单列过滤器:SingleColumnValueFilter
4.4.2 结构过滤器:FilterList
4.4.3 列值比较器: 四个
正则表达式(可以代替下面三个):
子串:
二进制:
二进制前缀:
4.4.4 KeyValue元数据过滤器
--列族过滤器
--列名过滤器 select
--列名前缀过滤器
--多列名前缀
--列名范围过滤器
4.4.5 RowKey过滤器
RowFilter
4.4.6 Utility过滤器
FirstKeyOnlyFilter
4.4.7 分页过滤器
PageFilter
五、Hbase的工作机制(重点)
5.1 Hbase的寻址机制(重点)
1. table.put() put 'myns:student'
table.get()/getScanner() get/scan....
put 'myns:student', 'rk01000', 'f1:name'
region: startkey, endkey
-- zookeeper: 维护了meta表的信息,就是地址
get /hbase/meta-region-server
-- hbase:meta表: 记录了所有表的所有的region信息
每个region以四个单元格进行记录,单元格的rowkey,就是region的名称
四个单元格中的两个单元格:
info:regioninfo维护的是region的名称,以及行范围
info:server维护的region的位置
region名称: schema:tablename,startkey,timestamp.ENCODED
5.2 Hbase的存储机制(重中之重)
5.2.1 存储机制介绍
1. 通过寻址流程定位到具体的region。
2. 将单元格存储到store对应的memstore中
3. 排序:按照rowkey进行升序,key进行升序,timestamp降序
单元格数据格式如下:
rowkey:column family:column:value:timestamp
4. 达到flush的阈值时,开始flush,生成storefile.然后由store来维护n个storefile的索引信息,比如path,startkey,endkey
flush阈值: 128M、 1小时、 当前region内存的40% 、当前regionserver内存40%
5. 当storefile的数量达到阈值,比如是3个。就进行合并。 合并期间会进行排序(rowkey升序,column升序,timetamp降序), 还会进行真正的删除(当发现有delete标记的单元格,就将所有版本过滤掉)和修改操作(超过版本数量的老版本过滤掉)。
6. 当合并的文件越来越大时,如果达到阈值(10G),就会触发split操作,数据尽量做到均分(会影响其他文件的切分),从而造成了region的切分。 旧region下线,两个的新的region维护数据,由hmaster来重新进行负载均衡。
5.2.2 名词解释
-
flush
当memstore达到阈值是,将内存中的数据冲刷成文件 可以手动flush 查看用法: help 'flush'
-
compact
当storefile达到数量阈值时,进行合并操作。 手动合并: major_compact regionname
-
split
当文件大小达到阈值时,会造成region的切分 手动切分: split regionname,splitkey
5.3 Hbase的Region管理
1)预切分
建表期间,进行预切分,指的就是提前划分region。
create tablename,column family,SPLITS=>[startkey1,startkey2....]
region数量 = startkey的数量+1
2)当文件达到阈值时,会主动切分
split regionname,splitkey
3)region也可以合并
merge_region 'encoded_region','encoded_region'
5.4 Hbase的读写流程(重点)
5.4.1 Hbase的读流程
1. 客户端请求zookeeper,获取meta表的位置信息
2. 客户端跳转到meta表,获取要访问的表的具体region位置
3. 客户端跳转到具体region所在的regionserver,找到该region。
4. 访问对应的store下的memstore(写缓存), 如果有数据就返回,如果没有数据,就访问regionserver对应的读缓存,如果没有数据,再访问磁盘,然后数据返回给客户端,并保存到读缓存中,方便下次快速读取。
5.4.2 Hbase的写流程
1. 客户端请求zookeeper,获取meta表的位置信息
2. 客户端跳转到meta表,获取要访问的表的具体region位置
3. 客户端跳转到具体region所在的regionserver,找到该region,将单元格写入到对应的store里的memstore
4. 在memstore里进行排序(按照rowkey进行升序,key进行升序,timestamp降序)
5. 如果达到memstore的阈值,就会flush成storefile文件,由store来维护该文件的索引信息。
6. 如果storefile数量达到阈值是,会进行合并操作(排序,实际的删除和修改)
7. 如果合并成的文件达到大小阈值时,会进行切分,造成region的切分(旧region下线,两个新region生成)
5.5 布隆过滤器(面试题)
5.5.1 简介
- 布隆过滤器是一个数据结构
- 内部维护着一个二进制向量的位数组,默认大小64K
- 还维护着N个hash算法, 默认值是3个。
- 牺牲了准确率,算法的时间复杂度是O(1)。从而提高了查询效率
- 特点: 判断一个元素是否在一个集合中,有两种结果:一种就是在集合中,但是不一定真实存在
另外一种结果就是不在集合中,那么就一定不在集合中。
5.5.2 原理
当存储元素时,会调用hash算法,计算元素的三个hash值,三个值作为bit数组的下标,将对应的元素由0改为1. (注意,hbase在put数据,不判断是否存在过)。
当在查询一个元素是否在这个集合中时,也是算出三个hash值作为下标,访问对应上的数据是否为1,如果全都是1,表明该元素可能存在这个集合中。只要有一个位置上是0,则表示该元素一定不在集合中。
5.5.3 Hbase中的布隆过滤器的设置
方法:columnfamily.setBloomFilterType()
布隆过滤器的级别:
BloomType.NONE: 表示不启用布隆过滤器
BloomType.ROW: 行级别的, 只对每一个rowkey做 布隆过滤器的数据存储
BloomType.ROWCOL: 行列级别的, 对rowkey:columnfamily:column做布隆过滤器的数据存储
参考文档上的布隆过滤器章节的作用:
六、Hbase与Hive、Mapreduce的整合
6.1 Hbase与Hive的整合
6.1.1 为什么要整合
hbase: hadoop数据库,本质用来存储大数据集,虽然提供了近似实时的读写功能
hive: 数据仓库的管理工具,作用就是用来使用hql语言对数据进行分析。
6.1.2 Hive-to-hbase
在hive创建表, 可以在hbase中看见
create table if not exists employee (
uid int,
uname string,
age int,
sex string,
province string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties(
"hbase.columns.mapping"=":key,base_info:name,base_info:age,base_info:sex,address:provice"
)
tblproperties(
"hbase.table.name"="myns:employee"
);
动态加载数据
insert into employee values(1, 'michael', 32, '男','jilin');
insert into employee values(2,'wcm',23,'男','heilongjiang');
put 'myns:employee','3','base_info:name','lisi'
结果查看
- 在hive中写一个select语句
- 在50070webui上查看hive下的表目录, 结论:没有数据, hive不负责存储
- 在hbase中写一个scan语句
- 在50070webui上查看hbase下的表目录, 结论:应该有数据,如果看不到,是因为还在内存中
6.1.3 Hbase-to-Hive
hbase中先有表,然后映射到hive中
create 'myns:student','f1','f2'
put 'myns:student','rk00001','f1:name','zhaoyun'
put 'myns:student','rk00001','f1:age',23
put 'myns:student','rk00001','f1:gender','m'
put 'myns:student','rk00002','f1:name','zhenji'
put 'myns:student','rk00002','f1:age',24
put 'myns:student','rk00002','f2:province','hebei'
在hive中创建表与hbase中的表进行映射
drop table student;
create external table if not exists student (
sid string,
name string,
province string,
gender string,
age int
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties(
"hbase.columns.mapping"=":key,f1:name,f2:province,f1:gender,f1:age"
)
tblproperties(
"hbase.table.name"="myns:student"
);
结果查看
在hive中 写select语句进行查看。
6.1.4 总结
-1.hive表的字段与hbase表的单元格 是按照顺序映射,而不是根据名称映射。
-2.hbase的rowkey 可以映射成hive中的一个字段,通过:key进行映射。可以不写:key,则与hive的第一个字段映射
-3.在字段映射时,注意字段类型的合理性
-4.如果hbase表已经存在,进行hive新表映射,hive表必须是外部表。
七、Hbase的二级索引和协处理器
7.1 二级索引的简介
rk1001 f1:name-zhangsan f1:age-23 f2:province-guangdong
........................
rk2001 f1:name-gaoyuanyuan f1:age-38 f2:province-shanghai
...........
rk3001 f1:name-gaoyuanyuan
需求: 查询 name叫gaoyuanyuan的年龄
SingleColumnValueFilter--- name:gaoyuanyuan
hbase的底层逻辑: 遍历数据块中的所有行信息,要查看是否有name:gaoyuanyuan单元格,有,返回所有行。
程序员需要再次编程对返回的所有行数据,查看是否age单元格。有,就返回。 性能很低。
如何提高上述需求类型的查询性能??? 再维护一张表:单元格与rowkey的映射关系表。
index表:
rowkey:
.........
f1:name-gaoyuanyuan info:rk1 'rk2001'
info:rk2 'rk3001'
......
f1:name-zhangsan info:rk1 'rk1001'
........
什么是二级索引表
概念:维护的数据是另外一张表的单元格与rowkey的映射关系的表,就是二级索引表
作用:提高查询效率,避免对原表的全表遍历, 牺牲磁盘空间,换取查询效率。
小贴士:
二级索引表,应该是程序自动维护的。
7.2 协处理器组件简介
7.2.1 为什么要引入协处理器
在Hbase的低版本(0.92以前)作为列族数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执行求和、计数、排序等操作。
之后引入了协处理器(coprocessor)进行改进,可以轻松的实现上述需求。
7.2.2 协处理器的分类(熟悉)
分两大类型:一个是Observer类型, 一个是endpoint类型
- Observer 允许集群在正常的客户端操作过程中可以有不同的行为表现
- Observer 类似于 RDBMS 中的触发器,主要在服务端工作
- Observer 可以实现权限管理、优先级设置、监控、ddl 控制、二级索引等功能
- Endpoint 类似于 RDBMS 中的存储过程,主要在服务端工作
- Endpoint 允许扩展集群的能力,对客户端应用开放新的运算命令
- Endpoint 可以实现 min、max、avg、sum、distinct、group by 等功能
7.2.3 协处理器的加载和卸载
1)加载方式:两种
第一种:静态加载,也叫系统级别的协处理器,只需要在hhbase-site.xml里添加如下属性和具体类名
<property>
<name>hbase.coprocessor.user.region.classes</name>
<value>类全名</value>
</property>
可以用”,”分割加载多个 class
第二种:动态记载,称之为表级别的协处理器
只对特定的表生效。通过 HBase Shell 来实现。
1. 停用表 disable 'mytable'
2. 添加协处理器
alter 't_guanzhu',METHOD => 'table_att',
'coprocessor'=>
'hdfs://supercluster/jar/mycoprocessor.jar|com.qf.hbase.coprocessor.MyIndexCoprocessor|1001|'
3. 启用表 enable 'mytable'
2)卸载方式
1. disable 'mytable'
2. alter 'mytable',METHOD=>'table_att_unset',NAME=>'coprocessor$1'
3. enable 'mytable'
3)注意事项:
如果写的协处理器逻辑有问题,那么可能会造成hbase的集群宕机
解决办法:
1. 关闭所有的hbase的守护进程
2. 进入zookeeper,删除相关的znode。 如果不知道是哪一个znode,就将hbase 整个删掉
3. 重新启动hbase,删除掉挂载了协处理器的那张表。重新维护表
4. 再加载协处理器,进行测试
7.3 案例演示:使用协处理器完成二级索引表的创建
7.3.1 案例描述
模拟博客上的关注信息表,以及粉丝表。
1. 关注信息表是原表: 维护的是每个用户关注的人
rk0001 f1:user-wcm f1:obj-gaoyuanyuan ......
......
rk0009 f1:user-wcm f1:obj-canglaoshi .....
....
rk0019 f1:user-laoli f1:liuyifei
2. 粉丝表是二级索引表。
wcm-gaoyuanyuan f1:rk-rk0001
wcm-canglaoshi f1:rk-rk0009
...........
laoli-gaoyuanyuan f1:rk-rk0019
create 'fans','f1'
7.3.2 代码编写
package com.qf.hbase.coprocessor;
import com.qf.hbase.util.HbaseUtil;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import java.io.IOException;
import java.util.List;
public class FansObServer extends BaseRegionObserver {
/**
* 重写prePut方法。
* @param e
* @param put put形参就会主动接受客户端提交的put对象
* @param edit
* @param durability
* @throws IOException
*
* rk0001 f1:user-wcm f1:obj-gaoyuanyuan
*
*
* 注意:该Observer是对原表进行监听
*/
@Override
public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
//获取put对象上的rowkey
byte[] row = put.getRow();
String rowkey = new String(row); //rk0001
List<Cell> users = put.get("f1".getBytes(), "user".getBytes());
Cell cell = users.get(0);
String value = new String(CellUtil.cloneValue(cell)); //wcm
List<Cell> objs = put.get("f1".getBytes(), "obj".getBytes());
Cell cell2 = objs.get(0);
String value1 = new String(CellUtil.cloneValue(cell2)); //gaoyuanyuan
//先封装一个新的put对象,准备提交到Fans表中 wcm-gaoyuanyuan f1:rk-rk0001
Put newPut = new Put((value+"-"+value1).getBytes());
newPut.addColumn("f1".getBytes(),"rk".getBytes(),rowkey.getBytes());
Table table = HbaseUtil.getTable("Fans"); //千万别写错表名
table.put(newPut);
table.close();
}
}
7.3.3 动态加载协处理器
--1. 创建关注表
create 'guanzhu','f1'
--2. 加载协处理器
(1)先将jar包上传到hdfs上的/jar目录下
(2)挂载
alter 'guanzhu',METHOD => 'table_att','coprocessor'=>'hdfs://qianfeng01/jar/sz2103_hbase.jar|com.qf.hbase.coprocessor.FansObServer|1001|'
7.3.4 案例测试
小贴士:基于案例的需求,user和obj单元格应该同时添加,所以,应该使用api添加数据
@Before
public void getTable(){
table = HbaseUtil.getTable("guanzhu");
}
@Test
public void putOne() throws IOException {
//1. 获取Put对象,指定rowkey
Put put = new Put(Bytes.toBytes("rk0001"));
//2. 指定列族名,列名,列值
put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("user"), Bytes.toBytes("wcm"));
put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("obj"), Bytes.toBytes("gaoyuanyuan"));
//3. 提交
table.put(put);
}
最后查看两张表的信息
hbase(main):009:0> scan 'Fans'
ROW COLUMN+CELL
wcm-gaoyuanyuan column=f1:rk, timestamp=1640165499598, value=rk0001
hbase(main):010:0> scan 'guanzhu'
ROW COLUMN+CELL
rk0001 column=f1:obj, timestamp=1640165499610, value=gaoyuanyuan
rk0001 column=f1:user, timestamp=1640165499610, value=wcm
八、Hbase的优化
8.1 在设计表上进行优化
1)预分区
在创建表的时候进行预分区,好处是,减少hbase的region的切分所造成的性能开销。
2)优秀的rowkey设计(重要)
热点问题: 当过多的请求集中在某一个机器节点上,可能会造成机器的瘫痪。 这种问题就叫热点问题。
1. rowkey的唯一原则
2. rowkey的长度一致原则
长度不一致的缺点,排序不是我们所想要的
1 2 3 ....10....40....101....121....
上述rowkey不统一长度,排序如下:
1
10
101
121
2
3
40
应该统一长度: 001,002,003.....010.....040.....101....121...
长度:建议低于100个字节, 最好是16个字节。 不过要看具体需求具体分析。
3. rowkey的散列原则:(避免热点问题)
-- rowkey的reverse
136.....72345
137.....62345
137......2346
..........
54326.....731
54327.....631
6432......731
-- 加盐Salt
-- hash随机
提前对普通的rowkey进行hash算法或者是取模算法或者其他的加密算法。将计算出来的结果,取前4位,作为前缀,拼接到rowkey前。这样的就可以将数据分散到不同的region里存储了。
942a-abc001 -->
3030-abc002
3)列族个数
-- hbase对多于2以上的列族维护性能开销很大
某一个列族下的一个文件达到大小阈值时,可能会关联到其他文件的切分,就会产生大量的磁盘IO。
4)使用内存
在建表时,可以开启regionserver的缓存。将表缓存到服务端。
5)版本数量与存活周期的设计
根据数据的重要性,适当的调整版本数量和存储周期
6)合并和切分
compact: 减少storefile的数量,可以提高查询效率。因此,可以适当的手动触发合并。
split: hbase的切分会产生性能开销,因此可以调高storefile大小阈值。
8.2 写表操作的优化
1)大数据集多可客户端写
数据量特别大的时候,可以使用多个Table进行写操作
2)取消自动flush
客户端有缓存,默认情况下是一条一flush,取消后,可以批量的put
HTable.setAutoFlush(false)
3)提高客户端的buffer
可以提高客户端的缓存字节数,批量的冲刷
table.setWriteBufferSize();
参数: hbase.client.write.buffer
4)取消WAL写(谨慎使用)
在配置文件中设置HLog的是否写操作。hbase-site.xml
5)批量put
默认情况下是一条一put。 可以使用put(List<put> puts)
6)多线程写
并发的写
8.3 读表操作的优化
1)大数据集多客户端读
数据量特别大的时候,可以使用for循环开启多个Table读数据
2)参数设置
可以设置客户端,以及服务端的相关参数:
hbase.client.scanner.caching : 设置一次scan的条数, 默认是1条, 可以往大了调整。 减少scan与hbase的交互次数
3)批量读取
get(List<Get> gets)
4)多线程读取
并发读取
5)客户端设置缓存
可以自己写api, 在程序中维护一个数据结构,来存储查询过的数据。前提是这样的数据要频繁查询多次。
6)提高服务端的读缓存
8.4 其他相关优化
1)hdfs
2)zookeeper
3)linux
4)hbase高可用
启动高可用,多个hmaster. hmaster可以有多个
5)关闭不必要的服务
节省内存使用资源
整版本数量和存储周期
6)合并和切分
compact: 减少storefile的数量,可以提高查询效率。因此,可以适当的手动触发合并。
split: hbase的切分会产生性能开销,因此可以调高storefile大小阈值。
## 8.2 写表操作的优化
1)大数据集多可客户端写
数据量特别大的时候,可以使用多个Table进行写操作
2)取消自动flush
客户端有缓存,默认情况下是一条一flush,取消后,可以批量的put
HTable.setAutoFlush(false)
3)提高客户端的buffer
可以提高客户端的缓存字节数,批量的冲刷
table.setWriteBufferSize();
参数: hbase.client.write.buffer
4)取消WAL写(谨慎使用)
在配置文件中设置HLog的是否写操作。hbase-site.xml
5)批量put
默认情况下是一条一put。 可以使用put(List puts)
6)多线程写
并发的写
## 8.3 读表操作的优化
1)大数据集多客户端读
数据量特别大的时候,可以使用for循环开启多个Table读数据
2)参数设置
可以设置客户端,以及服务端的相关参数:
hbase.client.scanner.caching : 设置一次scan的条数, 默认是1条, 可以往大了调整。 减少scan与hbase的交互次数
3)批量读取
get(List gets)
4)多线程读取
并发读取
5)客户端设置缓存
可以自己写api, 在程序中维护一个数据结构,来存储查询过的数据。前提是这样的数据要频繁查询多次。
6)提高服务端的读缓存
## 8.4 其他相关优化
1)hdfs
2)zookeeper
3)linux
4)hbase高可用
启动高可用,多个hmaster. hmaster可以有多个
5)关闭不必要的服务
节省内存使用资源